1139c1837SPaolo Bonzini/* 2139c1837SPaolo Bonzini * Tiny Code Generator for QEMU 3139c1837SPaolo Bonzini * 4139c1837SPaolo Bonzini * Copyright (c) 2008 Andrzej Zaborowski 5139c1837SPaolo Bonzini * 6139c1837SPaolo Bonzini * Permission is hereby granted, free of charge, to any person obtaining a copy 7139c1837SPaolo Bonzini * of this software and associated documentation files (the "Software"), to deal 8139c1837SPaolo Bonzini * in the Software without restriction, including without limitation the rights 9139c1837SPaolo Bonzini * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10139c1837SPaolo Bonzini * copies of the Software, and to permit persons to whom the Software is 11139c1837SPaolo Bonzini * furnished to do so, subject to the following conditions: 12139c1837SPaolo Bonzini * 13139c1837SPaolo Bonzini * The above copyright notice and this permission notice shall be included in 14139c1837SPaolo Bonzini * all copies or substantial portions of the Software. 15139c1837SPaolo Bonzini * 16139c1837SPaolo Bonzini * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17139c1837SPaolo Bonzini * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18139c1837SPaolo Bonzini * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19139c1837SPaolo Bonzini * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20139c1837SPaolo Bonzini * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21139c1837SPaolo Bonzini * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22139c1837SPaolo Bonzini * THE SOFTWARE. 23139c1837SPaolo Bonzini */ 24139c1837SPaolo Bonzini 25139c1837SPaolo Bonzini#include "elf.h" 260c90fa5dSRichard Henderson#include "../tcg-ldst.c.inc" 27139c1837SPaolo Bonzini#include "../tcg-pool.c.inc" 28139c1837SPaolo Bonzini 29139c1837SPaolo Bonziniint arm_arch = __ARM_ARCH; 30139c1837SPaolo Bonzini 31139c1837SPaolo Bonzini#ifndef use_idiv_instructions 32139c1837SPaolo Bonzinibool use_idiv_instructions; 33139c1837SPaolo Bonzini#endif 34d74b86edSRichard Henderson#ifndef use_neon_instructions 35d74b86edSRichard Hendersonbool use_neon_instructions; 36d74b86edSRichard Henderson#endif 37139c1837SPaolo Bonzini 38139c1837SPaolo Bonzini#ifdef CONFIG_DEBUG_TCG 39139c1837SPaolo Bonzinistatic const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { 40000cf477SRichard Henderson "%r0", "%r1", "%r2", "%r3", "%r4", "%r5", "%r6", "%r7", 41000cf477SRichard Henderson "%r8", "%r9", "%r10", "%r11", "%r12", "%sp", "%r14", "%pc", 42000cf477SRichard Henderson "%q0", "%q1", "%q2", "%q3", "%q4", "%q5", "%q6", "%q7", 43000cf477SRichard Henderson "%q8", "%q9", "%q10", "%q11", "%q12", "%q13", "%q14", "%q15", 44139c1837SPaolo Bonzini}; 45139c1837SPaolo Bonzini#endif 46139c1837SPaolo Bonzini 47139c1837SPaolo Bonzinistatic const int tcg_target_reg_alloc_order[] = { 48139c1837SPaolo Bonzini TCG_REG_R4, 49139c1837SPaolo Bonzini TCG_REG_R5, 50139c1837SPaolo Bonzini TCG_REG_R6, 51139c1837SPaolo Bonzini TCG_REG_R7, 52139c1837SPaolo Bonzini TCG_REG_R8, 53139c1837SPaolo Bonzini TCG_REG_R9, 54139c1837SPaolo Bonzini TCG_REG_R10, 55139c1837SPaolo Bonzini TCG_REG_R11, 56139c1837SPaolo Bonzini TCG_REG_R13, 57139c1837SPaolo Bonzini TCG_REG_R0, 58139c1837SPaolo Bonzini TCG_REG_R1, 59139c1837SPaolo Bonzini TCG_REG_R2, 60139c1837SPaolo Bonzini TCG_REG_R3, 61139c1837SPaolo Bonzini TCG_REG_R12, 62139c1837SPaolo Bonzini TCG_REG_R14, 63000cf477SRichard Henderson 64000cf477SRichard Henderson TCG_REG_Q0, 65000cf477SRichard Henderson TCG_REG_Q1, 66000cf477SRichard Henderson TCG_REG_Q2, 67000cf477SRichard Henderson TCG_REG_Q3, 68000cf477SRichard Henderson /* Q4 - Q7 are call-saved, and skipped. */ 69000cf477SRichard Henderson TCG_REG_Q8, 70000cf477SRichard Henderson TCG_REG_Q9, 71000cf477SRichard Henderson TCG_REG_Q10, 72000cf477SRichard Henderson TCG_REG_Q11, 73000cf477SRichard Henderson TCG_REG_Q12, 74000cf477SRichard Henderson TCG_REG_Q13, 75000cf477SRichard Henderson TCG_REG_Q14, 76000cf477SRichard Henderson TCG_REG_Q15, 77139c1837SPaolo Bonzini}; 78139c1837SPaolo Bonzini 79139c1837SPaolo Bonzinistatic const int tcg_target_call_iarg_regs[4] = { 80139c1837SPaolo Bonzini TCG_REG_R0, TCG_REG_R1, TCG_REG_R2, TCG_REG_R3 81139c1837SPaolo Bonzini}; 825e3d0c19SRichard Henderson 835e3d0c19SRichard Hendersonstatic TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot) 845e3d0c19SRichard Henderson{ 855e3d0c19SRichard Henderson tcg_debug_assert(kind == TCG_CALL_RET_NORMAL); 865e3d0c19SRichard Henderson tcg_debug_assert(slot >= 0 && slot <= 3); 875e3d0c19SRichard Henderson return TCG_REG_R0 + slot; 885e3d0c19SRichard Henderson} 89139c1837SPaolo Bonzini 90139c1837SPaolo Bonzini#define TCG_REG_TMP TCG_REG_R12 91000cf477SRichard Henderson#define TCG_VEC_TMP TCG_REG_Q15 924bb80207SRichard Henderson#define TCG_REG_GUEST_BASE TCG_REG_R11 93139c1837SPaolo Bonzini 941446600fSRichard Hendersontypedef enum { 95139c1837SPaolo Bonzini COND_EQ = 0x0, 96139c1837SPaolo Bonzini COND_NE = 0x1, 97139c1837SPaolo Bonzini COND_CS = 0x2, /* Unsigned greater or equal */ 98139c1837SPaolo Bonzini COND_CC = 0x3, /* Unsigned less than */ 99139c1837SPaolo Bonzini COND_MI = 0x4, /* Negative */ 100139c1837SPaolo Bonzini COND_PL = 0x5, /* Zero or greater */ 101139c1837SPaolo Bonzini COND_VS = 0x6, /* Overflow */ 102139c1837SPaolo Bonzini COND_VC = 0x7, /* No overflow */ 103139c1837SPaolo Bonzini COND_HI = 0x8, /* Unsigned greater than */ 104139c1837SPaolo Bonzini COND_LS = 0x9, /* Unsigned less or equal */ 105139c1837SPaolo Bonzini COND_GE = 0xa, 106139c1837SPaolo Bonzini COND_LT = 0xb, 107139c1837SPaolo Bonzini COND_GT = 0xc, 108139c1837SPaolo Bonzini COND_LE = 0xd, 109139c1837SPaolo Bonzini COND_AL = 0xe, 1101446600fSRichard Henderson} ARMCond; 111139c1837SPaolo Bonzini 112139c1837SPaolo Bonzini#define TO_CPSR (1 << 20) 113139c1837SPaolo Bonzini 114139c1837SPaolo Bonzini#define SHIFT_IMM_LSL(im) (((im) << 7) | 0x00) 115139c1837SPaolo Bonzini#define SHIFT_IMM_LSR(im) (((im) << 7) | 0x20) 116139c1837SPaolo Bonzini#define SHIFT_IMM_ASR(im) (((im) << 7) | 0x40) 117139c1837SPaolo Bonzini#define SHIFT_IMM_ROR(im) (((im) << 7) | 0x60) 118139c1837SPaolo Bonzini#define SHIFT_REG_LSL(rs) (((rs) << 8) | 0x10) 119139c1837SPaolo Bonzini#define SHIFT_REG_LSR(rs) (((rs) << 8) | 0x30) 120139c1837SPaolo Bonzini#define SHIFT_REG_ASR(rs) (((rs) << 8) | 0x50) 121139c1837SPaolo Bonzini#define SHIFT_REG_ROR(rs) (((rs) << 8) | 0x70) 122139c1837SPaolo Bonzini 123139c1837SPaolo Bonzinitypedef enum { 124139c1837SPaolo Bonzini ARITH_AND = 0x0 << 21, 125139c1837SPaolo Bonzini ARITH_EOR = 0x1 << 21, 126139c1837SPaolo Bonzini ARITH_SUB = 0x2 << 21, 127139c1837SPaolo Bonzini ARITH_RSB = 0x3 << 21, 128139c1837SPaolo Bonzini ARITH_ADD = 0x4 << 21, 129139c1837SPaolo Bonzini ARITH_ADC = 0x5 << 21, 130139c1837SPaolo Bonzini ARITH_SBC = 0x6 << 21, 131139c1837SPaolo Bonzini ARITH_RSC = 0x7 << 21, 132139c1837SPaolo Bonzini ARITH_TST = 0x8 << 21 | TO_CPSR, 133139c1837SPaolo Bonzini ARITH_CMP = 0xa << 21 | TO_CPSR, 134139c1837SPaolo Bonzini ARITH_CMN = 0xb << 21 | TO_CPSR, 135139c1837SPaolo Bonzini ARITH_ORR = 0xc << 21, 136139c1837SPaolo Bonzini ARITH_MOV = 0xd << 21, 137139c1837SPaolo Bonzini ARITH_BIC = 0xe << 21, 138139c1837SPaolo Bonzini ARITH_MVN = 0xf << 21, 139139c1837SPaolo Bonzini 14079ffece4SRichard Henderson INSN_B = 0x0a000000, 14179ffece4SRichard Henderson 142139c1837SPaolo Bonzini INSN_CLZ = 0x016f0f10, 143139c1837SPaolo Bonzini INSN_RBIT = 0x06ff0f30, 144139c1837SPaolo Bonzini 14531d160adSRichard Henderson INSN_LDMIA = 0x08b00000, 14631d160adSRichard Henderson INSN_STMDB = 0x09200000, 14731d160adSRichard Henderson 148139c1837SPaolo Bonzini INSN_LDR_IMM = 0x04100000, 149139c1837SPaolo Bonzini INSN_LDR_REG = 0x06100000, 150139c1837SPaolo Bonzini INSN_STR_IMM = 0x04000000, 151139c1837SPaolo Bonzini INSN_STR_REG = 0x06000000, 152139c1837SPaolo Bonzini 153139c1837SPaolo Bonzini INSN_LDRH_IMM = 0x005000b0, 154139c1837SPaolo Bonzini INSN_LDRH_REG = 0x001000b0, 155139c1837SPaolo Bonzini INSN_LDRSH_IMM = 0x005000f0, 156139c1837SPaolo Bonzini INSN_LDRSH_REG = 0x001000f0, 157139c1837SPaolo Bonzini INSN_STRH_IMM = 0x004000b0, 158139c1837SPaolo Bonzini INSN_STRH_REG = 0x000000b0, 159139c1837SPaolo Bonzini 160139c1837SPaolo Bonzini INSN_LDRB_IMM = 0x04500000, 161139c1837SPaolo Bonzini INSN_LDRB_REG = 0x06500000, 162139c1837SPaolo Bonzini INSN_LDRSB_IMM = 0x005000d0, 163139c1837SPaolo Bonzini INSN_LDRSB_REG = 0x001000d0, 164139c1837SPaolo Bonzini INSN_STRB_IMM = 0x04400000, 165139c1837SPaolo Bonzini INSN_STRB_REG = 0x06400000, 166139c1837SPaolo Bonzini 167139c1837SPaolo Bonzini INSN_LDRD_IMM = 0x004000d0, 168139c1837SPaolo Bonzini INSN_LDRD_REG = 0x000000d0, 169139c1837SPaolo Bonzini INSN_STRD_IMM = 0x004000f0, 170139c1837SPaolo Bonzini INSN_STRD_REG = 0x000000f0, 171139c1837SPaolo Bonzini 172139c1837SPaolo Bonzini INSN_DMB_ISH = 0xf57ff05b, 173139c1837SPaolo Bonzini INSN_DMB_MCR = 0xee070fba, 174139c1837SPaolo Bonzini 175139c1837SPaolo Bonzini /* Architected nop introduced in v6k. */ 176139c1837SPaolo Bonzini /* ??? This is an MSR (imm) 0,0,0 insn. Anyone know if this 177139c1837SPaolo Bonzini also Just So Happened to do nothing on pre-v6k so that we 178139c1837SPaolo Bonzini don't need to conditionalize it? */ 179139c1837SPaolo Bonzini INSN_NOP_v6k = 0xe320f000, 180139c1837SPaolo Bonzini /* Otherwise the assembler uses mov r0,r0 */ 181139c1837SPaolo Bonzini INSN_NOP_v4 = (COND_AL << 28) | ARITH_MOV, 1826e49fad2SRichard Henderson 183d74b86edSRichard Henderson INSN_VADD = 0xf2000800, 184d74b86edSRichard Henderson INSN_VAND = 0xf2000110, 1857df44cf6SRichard Henderson INSN_VBIC = 0xf2100110, 186d74b86edSRichard Henderson INSN_VEOR = 0xf3000110, 1877df44cf6SRichard Henderson INSN_VORN = 0xf2300110, 1882df2a8cfSRichard Henderson INSN_VORR = 0xf2200110, 189d74b86edSRichard Henderson INSN_VSUB = 0xf3000800, 190752b1769SRichard Henderson INSN_VMUL = 0xf2000910, 1914fcd3017SRichard Henderson INSN_VQADD = 0xf2000010, 1924fcd3017SRichard Henderson INSN_VQADD_U = 0xf3000010, 1934fcd3017SRichard Henderson INSN_VQSUB = 0xf2000210, 1944fcd3017SRichard Henderson INSN_VQSUB_U = 0xf3000210, 195dbbeff77SRichard Henderson INSN_VMAX = 0xf2000600, 196dbbeff77SRichard Henderson INSN_VMAX_U = 0xf3000600, 197dbbeff77SRichard Henderson INSN_VMIN = 0xf2000610, 198dbbeff77SRichard Henderson INSN_VMIN_U = 0xf3000610, 199d74b86edSRichard Henderson 2007df44cf6SRichard Henderson INSN_VABS = 0xf3b10300, 201d74b86edSRichard Henderson INSN_VMVN = 0xf3b00580, 2027df44cf6SRichard Henderson INSN_VNEG = 0xf3b10380, 203d74b86edSRichard Henderson 204d74b86edSRichard Henderson INSN_VCEQ0 = 0xf3b10100, 205d74b86edSRichard Henderson INSN_VCGT0 = 0xf3b10000, 206d74b86edSRichard Henderson INSN_VCGE0 = 0xf3b10080, 207d74b86edSRichard Henderson INSN_VCLE0 = 0xf3b10180, 208d74b86edSRichard Henderson INSN_VCLT0 = 0xf3b10200, 209d74b86edSRichard Henderson 210d74b86edSRichard Henderson INSN_VCEQ = 0xf3000810, 211d74b86edSRichard Henderson INSN_VCGE = 0xf2000310, 212d74b86edSRichard Henderson INSN_VCGT = 0xf2000300, 213d74b86edSRichard Henderson INSN_VCGE_U = 0xf3000310, 214d74b86edSRichard Henderson INSN_VCGT_U = 0xf3000300, 215d74b86edSRichard Henderson 216d4c4e9c5SRichard Henderson INSN_VSHLI = 0xf2800510, /* VSHL (immediate) */ 217d4c4e9c5SRichard Henderson INSN_VSARI = 0xf2800010, /* VSHR.S */ 218d4c4e9c5SRichard Henderson INSN_VSHRI = 0xf3800010, /* VSHR.U */ 2195047ae64SRichard Henderson INSN_VSLI = 0xf3800510, 22031d36639SRichard Henderson INSN_VSHL_S = 0xf2000400, /* VSHL.S (register) */ 22131d36639SRichard Henderson INSN_VSHL_U = 0xf3000400, /* VSHL.U (register) */ 222d4c4e9c5SRichard Henderson 223f2b46c71SRichard Henderson INSN_VBSL = 0xf3100110, 224f2b46c71SRichard Henderson INSN_VBIT = 0xf3200110, 225f2b46c71SRichard Henderson INSN_VBIF = 0xf3300110, 226f2b46c71SRichard Henderson 227d74b86edSRichard Henderson INSN_VTST = 0xf2000810, 2282df2a8cfSRichard Henderson 229213e8d84SRichard Henderson INSN_VDUP_G = 0xee800b10, /* VDUP (ARM core register) */ 230213e8d84SRichard Henderson INSN_VDUP_S = 0xf3b00c00, /* VDUP (scalar) */ 231213e8d84SRichard Henderson INSN_VLDR_D = 0xed100b00, /* VLDR.64 */ 2326e49fad2SRichard Henderson INSN_VLD1 = 0xf4200000, /* VLD1 (multiple single elements) */ 233213e8d84SRichard Henderson INSN_VLD1R = 0xf4a00c00, /* VLD1 (single element to all lanes) */ 2346e49fad2SRichard Henderson INSN_VST1 = 0xf4000000, /* VST1 (multiple single elements) */ 235213e8d84SRichard Henderson INSN_VMOVI = 0xf2800010, /* VMOV (immediate) */ 236139c1837SPaolo Bonzini} ARMInsn; 237139c1837SPaolo Bonzini 238139c1837SPaolo Bonzini#define INSN_NOP (use_armv7_instructions ? INSN_NOP_v6k : INSN_NOP_v4) 239139c1837SPaolo Bonzini 240139c1837SPaolo Bonzinistatic const uint8_t tcg_cond_to_arm_cond[] = { 241139c1837SPaolo Bonzini [TCG_COND_EQ] = COND_EQ, 242139c1837SPaolo Bonzini [TCG_COND_NE] = COND_NE, 243139c1837SPaolo Bonzini [TCG_COND_LT] = COND_LT, 244139c1837SPaolo Bonzini [TCG_COND_GE] = COND_GE, 245139c1837SPaolo Bonzini [TCG_COND_LE] = COND_LE, 246139c1837SPaolo Bonzini [TCG_COND_GT] = COND_GT, 247139c1837SPaolo Bonzini /* unsigned */ 248139c1837SPaolo Bonzini [TCG_COND_LTU] = COND_CC, 249139c1837SPaolo Bonzini [TCG_COND_GEU] = COND_CS, 250139c1837SPaolo Bonzini [TCG_COND_LEU] = COND_LS, 251139c1837SPaolo Bonzini [TCG_COND_GTU] = COND_HI, 252139c1837SPaolo Bonzini}; 253139c1837SPaolo Bonzini 254213e8d84SRichard Hendersonstatic int encode_imm(uint32_t imm); 255213e8d84SRichard Henderson 256213e8d84SRichard Henderson/* TCG private relocation type: add with pc+imm8 */ 257213e8d84SRichard Henderson#define R_ARM_PC8 11 258213e8d84SRichard Henderson 259213e8d84SRichard Henderson/* TCG private relocation type: vldr with imm8 << 2 */ 260213e8d84SRichard Henderson#define R_ARM_PC11 12 261213e8d84SRichard Henderson 26269478b8bSRichard Hendersonstatic bool reloc_pc24(tcg_insn_unit *src_rw, const tcg_insn_unit *target) 263139c1837SPaolo Bonzini{ 26469478b8bSRichard Henderson const tcg_insn_unit *src_rx = tcg_splitwx_to_rx(src_rw); 26569478b8bSRichard Henderson ptrdiff_t offset = (tcg_ptr_byte_diff(target, src_rx) - 8) >> 2; 26669478b8bSRichard Henderson 267139c1837SPaolo Bonzini if (offset == sextract32(offset, 0, 24)) { 26869478b8bSRichard Henderson *src_rw = deposit32(*src_rw, 0, 24, offset); 269139c1837SPaolo Bonzini return true; 270139c1837SPaolo Bonzini } 271139c1837SPaolo Bonzini return false; 272139c1837SPaolo Bonzini} 273139c1837SPaolo Bonzini 27469478b8bSRichard Hendersonstatic bool reloc_pc13(tcg_insn_unit *src_rw, const tcg_insn_unit *target) 275139c1837SPaolo Bonzini{ 27669478b8bSRichard Henderson const tcg_insn_unit *src_rx = tcg_splitwx_to_rx(src_rw); 27769478b8bSRichard Henderson ptrdiff_t offset = tcg_ptr_byte_diff(target, src_rx) - 8; 278139c1837SPaolo Bonzini 279139c1837SPaolo Bonzini if (offset >= -0xfff && offset <= 0xfff) { 28069478b8bSRichard Henderson tcg_insn_unit insn = *src_rw; 281139c1837SPaolo Bonzini bool u = (offset >= 0); 282139c1837SPaolo Bonzini if (!u) { 283139c1837SPaolo Bonzini offset = -offset; 284139c1837SPaolo Bonzini } 285139c1837SPaolo Bonzini insn = deposit32(insn, 23, 1, u); 286139c1837SPaolo Bonzini insn = deposit32(insn, 0, 12, offset); 28769478b8bSRichard Henderson *src_rw = insn; 288139c1837SPaolo Bonzini return true; 289139c1837SPaolo Bonzini } 290139c1837SPaolo Bonzini return false; 291139c1837SPaolo Bonzini} 292139c1837SPaolo Bonzini 293213e8d84SRichard Hendersonstatic bool reloc_pc11(tcg_insn_unit *src_rw, const tcg_insn_unit *target) 294213e8d84SRichard Henderson{ 295213e8d84SRichard Henderson const tcg_insn_unit *src_rx = tcg_splitwx_to_rx(src_rw); 296213e8d84SRichard Henderson ptrdiff_t offset = (tcg_ptr_byte_diff(target, src_rx) - 8) / 4; 297213e8d84SRichard Henderson 298213e8d84SRichard Henderson if (offset >= -0xff && offset <= 0xff) { 299213e8d84SRichard Henderson tcg_insn_unit insn = *src_rw; 300213e8d84SRichard Henderson bool u = (offset >= 0); 301213e8d84SRichard Henderson if (!u) { 302213e8d84SRichard Henderson offset = -offset; 303213e8d84SRichard Henderson } 304213e8d84SRichard Henderson insn = deposit32(insn, 23, 1, u); 305213e8d84SRichard Henderson insn = deposit32(insn, 0, 8, offset); 306213e8d84SRichard Henderson *src_rw = insn; 307213e8d84SRichard Henderson return true; 308213e8d84SRichard Henderson } 309213e8d84SRichard Henderson return false; 310213e8d84SRichard Henderson} 311213e8d84SRichard Henderson 312213e8d84SRichard Hendersonstatic bool reloc_pc8(tcg_insn_unit *src_rw, const tcg_insn_unit *target) 313213e8d84SRichard Henderson{ 314213e8d84SRichard Henderson const tcg_insn_unit *src_rx = tcg_splitwx_to_rx(src_rw); 315213e8d84SRichard Henderson ptrdiff_t offset = tcg_ptr_byte_diff(target, src_rx) - 8; 31690606715SRichard Henderson int imm12 = encode_imm(offset); 317213e8d84SRichard Henderson 31890606715SRichard Henderson if (imm12 >= 0) { 31990606715SRichard Henderson *src_rw = deposit32(*src_rw, 0, 12, imm12); 320213e8d84SRichard Henderson return true; 321213e8d84SRichard Henderson } 322213e8d84SRichard Henderson return false; 323213e8d84SRichard Henderson} 324213e8d84SRichard Henderson 325139c1837SPaolo Bonzinistatic bool patch_reloc(tcg_insn_unit *code_ptr, int type, 326139c1837SPaolo Bonzini intptr_t value, intptr_t addend) 327139c1837SPaolo Bonzini{ 328139c1837SPaolo Bonzini tcg_debug_assert(addend == 0); 329213e8d84SRichard Henderson switch (type) { 330213e8d84SRichard Henderson case R_ARM_PC24: 33169478b8bSRichard Henderson return reloc_pc24(code_ptr, (const tcg_insn_unit *)value); 332213e8d84SRichard Henderson case R_ARM_PC13: 33369478b8bSRichard Henderson return reloc_pc13(code_ptr, (const tcg_insn_unit *)value); 334213e8d84SRichard Henderson case R_ARM_PC11: 335213e8d84SRichard Henderson return reloc_pc11(code_ptr, (const tcg_insn_unit *)value); 336213e8d84SRichard Henderson case R_ARM_PC8: 337213e8d84SRichard Henderson return reloc_pc8(code_ptr, (const tcg_insn_unit *)value); 338213e8d84SRichard Henderson default: 339139c1837SPaolo Bonzini g_assert_not_reached(); 340139c1837SPaolo Bonzini } 341139c1837SPaolo Bonzini} 342139c1837SPaolo Bonzini 343139c1837SPaolo Bonzini#define TCG_CT_CONST_ARM 0x100 344139c1837SPaolo Bonzini#define TCG_CT_CONST_INV 0x200 345139c1837SPaolo Bonzini#define TCG_CT_CONST_NEG 0x400 346139c1837SPaolo Bonzini#define TCG_CT_CONST_ZERO 0x800 347d74b86edSRichard Henderson#define TCG_CT_CONST_ORRI 0x1000 348d74b86edSRichard Henderson#define TCG_CT_CONST_ANDI 0x2000 349139c1837SPaolo Bonzini 3503440d583SRichard Henderson#define ALL_GENERAL_REGS 0xffffu 351000cf477SRichard Henderson#define ALL_VECTOR_REGS 0xffff0000u 352139c1837SPaolo Bonzini 3533440d583SRichard Henderson/* 3547893e42dSPhilippe Mathieu-Daudé * r0-r3 will be overwritten when reading the tlb entry (system-mode only); 35572128122SRichard Henderson * r14 will be overwritten by the BLNE branching to the slow path. 3563440d583SRichard Henderson */ 35772128122SRichard Henderson#define ALL_QLDST_REGS \ 3582c53bdf1SRichard Henderson (ALL_GENERAL_REGS & ~((tcg_use_softmmu ? 0xf : 0) | (1 << TCG_REG_R14))) 359139c1837SPaolo Bonzini 36090606715SRichard Henderson/* 36190606715SRichard Henderson * ARM immediates for ALU instructions are made of an unsigned 8-bit 36290606715SRichard Henderson * right-rotated by an even amount between 0 and 30. 36390606715SRichard Henderson * 36490606715SRichard Henderson * Return < 0 if @imm cannot be encoded, else the entire imm12 field. 36590606715SRichard Henderson */ 366213e8d84SRichard Hendersonstatic int encode_imm(uint32_t imm) 367139c1837SPaolo Bonzini{ 36890606715SRichard Henderson uint32_t rot, imm8; 369139c1837SPaolo Bonzini 37090606715SRichard Henderson /* Simple case, no rotation required. */ 37190606715SRichard Henderson if ((imm & ~0xff) == 0) { 37290606715SRichard Henderson return imm; 37390606715SRichard Henderson } 37490606715SRichard Henderson 37590606715SRichard Henderson /* Next, try a simple even shift. */ 37690606715SRichard Henderson rot = ctz32(imm) & ~1; 37790606715SRichard Henderson imm8 = imm >> rot; 37890606715SRichard Henderson rot = 32 - rot; 37990606715SRichard Henderson if ((imm8 & ~0xff) == 0) { 38090606715SRichard Henderson goto found; 38190606715SRichard Henderson } 38290606715SRichard Henderson 38390606715SRichard Henderson /* 38490606715SRichard Henderson * Finally, try harder with rotations. 38590606715SRichard Henderson * The ctz test above will have taken care of rotates >= 8. 38690606715SRichard Henderson */ 38790606715SRichard Henderson for (rot = 2; rot < 8; rot += 2) { 38890606715SRichard Henderson imm8 = rol32(imm, rot); 38990606715SRichard Henderson if ((imm8 & ~0xff) == 0) { 39090606715SRichard Henderson goto found; 39190606715SRichard Henderson } 39290606715SRichard Henderson } 39390606715SRichard Henderson /* Fail: imm cannot be encoded. */ 394139c1837SPaolo Bonzini return -1; 39590606715SRichard Henderson 39690606715SRichard Henderson found: 39790606715SRichard Henderson /* Note that rot is even, and we discard bit 0 by shifting by 7. */ 39890606715SRichard Henderson return rot << 7 | imm8; 39990606715SRichard Henderson} 40090606715SRichard Henderson 40190606715SRichard Hendersonstatic int encode_imm_nofail(uint32_t imm) 40290606715SRichard Henderson{ 40390606715SRichard Henderson int ret = encode_imm(imm); 40490606715SRichard Henderson tcg_debug_assert(ret >= 0); 40590606715SRichard Henderson return ret; 406139c1837SPaolo Bonzini} 407139c1837SPaolo Bonzini 4085f726ebcSRichard Hendersonstatic bool check_fit_imm(uint32_t imm) 409139c1837SPaolo Bonzini{ 410139c1837SPaolo Bonzini return encode_imm(imm) >= 0; 411139c1837SPaolo Bonzini} 412139c1837SPaolo Bonzini 413213e8d84SRichard Henderson/* Return true if v16 is a valid 16-bit shifted immediate. */ 414213e8d84SRichard Hendersonstatic bool is_shimm16(uint16_t v16, int *cmode, int *imm8) 415213e8d84SRichard Henderson{ 416213e8d84SRichard Henderson if (v16 == (v16 & 0xff)) { 417213e8d84SRichard Henderson *cmode = 0x8; 418213e8d84SRichard Henderson *imm8 = v16 & 0xff; 419213e8d84SRichard Henderson return true; 420213e8d84SRichard Henderson } else if (v16 == (v16 & 0xff00)) { 421213e8d84SRichard Henderson *cmode = 0xa; 422213e8d84SRichard Henderson *imm8 = v16 >> 8; 423213e8d84SRichard Henderson return true; 424213e8d84SRichard Henderson } 425213e8d84SRichard Henderson return false; 426213e8d84SRichard Henderson} 427213e8d84SRichard Henderson 428213e8d84SRichard Henderson/* Return true if v32 is a valid 32-bit shifted immediate. */ 429213e8d84SRichard Hendersonstatic bool is_shimm32(uint32_t v32, int *cmode, int *imm8) 430213e8d84SRichard Henderson{ 431213e8d84SRichard Henderson if (v32 == (v32 & 0xff)) { 432213e8d84SRichard Henderson *cmode = 0x0; 433213e8d84SRichard Henderson *imm8 = v32 & 0xff; 434213e8d84SRichard Henderson return true; 435213e8d84SRichard Henderson } else if (v32 == (v32 & 0xff00)) { 436213e8d84SRichard Henderson *cmode = 0x2; 437213e8d84SRichard Henderson *imm8 = (v32 >> 8) & 0xff; 438213e8d84SRichard Henderson return true; 439213e8d84SRichard Henderson } else if (v32 == (v32 & 0xff0000)) { 440213e8d84SRichard Henderson *cmode = 0x4; 441213e8d84SRichard Henderson *imm8 = (v32 >> 16) & 0xff; 442213e8d84SRichard Henderson return true; 443213e8d84SRichard Henderson } else if (v32 == (v32 & 0xff000000)) { 444213e8d84SRichard Henderson *cmode = 0x6; 445213e8d84SRichard Henderson *imm8 = v32 >> 24; 446213e8d84SRichard Henderson return true; 447213e8d84SRichard Henderson } 448213e8d84SRichard Henderson return false; 449213e8d84SRichard Henderson} 450213e8d84SRichard Henderson 451213e8d84SRichard Henderson/* Return true if v32 is a valid 32-bit shifting ones immediate. */ 452213e8d84SRichard Hendersonstatic bool is_soimm32(uint32_t v32, int *cmode, int *imm8) 453213e8d84SRichard Henderson{ 454213e8d84SRichard Henderson if ((v32 & 0xffff00ff) == 0xff) { 455213e8d84SRichard Henderson *cmode = 0xc; 456213e8d84SRichard Henderson *imm8 = (v32 >> 8) & 0xff; 457213e8d84SRichard Henderson return true; 458213e8d84SRichard Henderson } else if ((v32 & 0xff00ffff) == 0xffff) { 459213e8d84SRichard Henderson *cmode = 0xd; 460213e8d84SRichard Henderson *imm8 = (v32 >> 16) & 0xff; 461213e8d84SRichard Henderson return true; 462213e8d84SRichard Henderson } 463213e8d84SRichard Henderson return false; 464213e8d84SRichard Henderson} 465213e8d84SRichard Henderson 466213e8d84SRichard Henderson/* 467213e8d84SRichard Henderson * Return non-zero if v32 can be formed by MOVI+ORR. 468213e8d84SRichard Henderson * Place the parameters for MOVI in (cmode, imm8). 469213e8d84SRichard Henderson * Return the cmode for ORR; the imm8 can be had via extraction from v32. 470213e8d84SRichard Henderson */ 471213e8d84SRichard Hendersonstatic int is_shimm32_pair(uint32_t v32, int *cmode, int *imm8) 472213e8d84SRichard Henderson{ 473213e8d84SRichard Henderson int i; 474213e8d84SRichard Henderson 475213e8d84SRichard Henderson for (i = 6; i > 0; i -= 2) { 476213e8d84SRichard Henderson /* Mask out one byte we can add with ORR. */ 477213e8d84SRichard Henderson uint32_t tmp = v32 & ~(0xffu << (i * 4)); 478213e8d84SRichard Henderson if (is_shimm32(tmp, cmode, imm8) || 479213e8d84SRichard Henderson is_soimm32(tmp, cmode, imm8)) { 480213e8d84SRichard Henderson break; 481213e8d84SRichard Henderson } 482213e8d84SRichard Henderson } 483213e8d84SRichard Henderson return i; 484213e8d84SRichard Henderson} 485213e8d84SRichard Henderson 486d74b86edSRichard Henderson/* Return true if V is a valid 16-bit or 32-bit shifted immediate. */ 487d74b86edSRichard Hendersonstatic bool is_shimm1632(uint32_t v32, int *cmode, int *imm8) 488d74b86edSRichard Henderson{ 489d74b86edSRichard Henderson if (v32 == deposit32(v32, 16, 16, v32)) { 490d74b86edSRichard Henderson return is_shimm16(v32, cmode, imm8); 491d74b86edSRichard Henderson } else { 492d74b86edSRichard Henderson return is_shimm32(v32, cmode, imm8); 493d74b86edSRichard Henderson } 494d74b86edSRichard Henderson} 495d74b86edSRichard Henderson 496139c1837SPaolo Bonzini/* Test if a constant matches the constraint. 497139c1837SPaolo Bonzini * TODO: define constraints for: 498139c1837SPaolo Bonzini * 499139c1837SPaolo Bonzini * ldr/str offset: between -0xfff and 0xfff 500139c1837SPaolo Bonzini * ldrh/strh offset: between -0xff and 0xff 501139c1837SPaolo Bonzini * mov operand2: values represented with x << (2 * y), x < 0x100 502139c1837SPaolo Bonzini * add, sub, eor...: ditto 503139c1837SPaolo Bonzini */ 50421e9a8aeSRichard Hendersonstatic bool tcg_target_const_match(int64_t val, int ct, 50521e9a8aeSRichard Henderson TCGType type, TCGCond cond, int vece) 506139c1837SPaolo Bonzini{ 507139c1837SPaolo Bonzini if (ct & TCG_CT_CONST) { 508139c1837SPaolo Bonzini return 1; 509139c1837SPaolo Bonzini } else if ((ct & TCG_CT_CONST_ARM) && check_fit_imm(val)) { 510139c1837SPaolo Bonzini return 1; 511139c1837SPaolo Bonzini } else if ((ct & TCG_CT_CONST_INV) && check_fit_imm(~val)) { 512139c1837SPaolo Bonzini return 1; 513139c1837SPaolo Bonzini } else if ((ct & TCG_CT_CONST_NEG) && check_fit_imm(-val)) { 514139c1837SPaolo Bonzini return 1; 515139c1837SPaolo Bonzini } else if ((ct & TCG_CT_CONST_ZERO) && val == 0) { 516139c1837SPaolo Bonzini return 1; 517139c1837SPaolo Bonzini } 518d74b86edSRichard Henderson 519d74b86edSRichard Henderson switch (ct & (TCG_CT_CONST_ORRI | TCG_CT_CONST_ANDI)) { 520d74b86edSRichard Henderson case 0: 521d74b86edSRichard Henderson break; 522d74b86edSRichard Henderson case TCG_CT_CONST_ANDI: 523d74b86edSRichard Henderson val = ~val; 524d74b86edSRichard Henderson /* fallthru */ 525d74b86edSRichard Henderson case TCG_CT_CONST_ORRI: 526d74b86edSRichard Henderson if (val == deposit64(val, 32, 32, val)) { 527d74b86edSRichard Henderson int cmode, imm8; 528d74b86edSRichard Henderson return is_shimm1632(val, &cmode, &imm8); 529d74b86edSRichard Henderson } 530d74b86edSRichard Henderson break; 531d74b86edSRichard Henderson default: 532d74b86edSRichard Henderson /* Both bits should not be set for the same insn. */ 533d74b86edSRichard Henderson g_assert_not_reached(); 534d74b86edSRichard Henderson } 535d74b86edSRichard Henderson 536d74b86edSRichard Henderson return 0; 537139c1837SPaolo Bonzini} 538139c1837SPaolo Bonzini 5391446600fSRichard Hendersonstatic void tcg_out_b_imm(TCGContext *s, ARMCond cond, int32_t offset) 540139c1837SPaolo Bonzini{ 54179ffece4SRichard Henderson tcg_out32(s, (cond << 28) | INSN_B | 542139c1837SPaolo Bonzini (((offset - 8) >> 2) & 0x00ffffff)); 543139c1837SPaolo Bonzini} 544139c1837SPaolo Bonzini 5451446600fSRichard Hendersonstatic void tcg_out_bl_imm(TCGContext *s, ARMCond cond, int32_t offset) 546139c1837SPaolo Bonzini{ 547139c1837SPaolo Bonzini tcg_out32(s, (cond << 28) | 0x0b000000 | 548139c1837SPaolo Bonzini (((offset - 8) >> 2) & 0x00ffffff)); 549139c1837SPaolo Bonzini} 550139c1837SPaolo Bonzini 551e028eadaSRichard Hendersonstatic void tcg_out_blx_reg(TCGContext *s, ARMCond cond, TCGReg rn) 552139c1837SPaolo Bonzini{ 553139c1837SPaolo Bonzini tcg_out32(s, (cond << 28) | 0x012fff30 | rn); 554139c1837SPaolo Bonzini} 555139c1837SPaolo Bonzini 5565f726ebcSRichard Hendersonstatic void tcg_out_blx_imm(TCGContext *s, int32_t offset) 557139c1837SPaolo Bonzini{ 558139c1837SPaolo Bonzini tcg_out32(s, 0xfa000000 | ((offset & 2) << 23) | 559139c1837SPaolo Bonzini (((offset - 8) >> 2) & 0x00ffffff)); 560139c1837SPaolo Bonzini} 561139c1837SPaolo Bonzini 562e028eadaSRichard Hendersonstatic void tcg_out_dat_reg(TCGContext *s, ARMCond cond, ARMInsn opc, 563e028eadaSRichard Henderson TCGReg rd, TCGReg rn, TCGReg rm, int shift) 564139c1837SPaolo Bonzini{ 565139c1837SPaolo Bonzini tcg_out32(s, (cond << 28) | (0 << 25) | opc | 566139c1837SPaolo Bonzini (rn << 16) | (rd << 12) | shift | rm); 567139c1837SPaolo Bonzini} 568139c1837SPaolo Bonzini 569e028eadaSRichard Hendersonstatic void tcg_out_mov_reg(TCGContext *s, ARMCond cond, TCGReg rd, TCGReg rm) 570139c1837SPaolo Bonzini{ 571139c1837SPaolo Bonzini /* Simple reg-reg move, optimising out the 'do nothing' case */ 572139c1837SPaolo Bonzini if (rd != rm) { 573139c1837SPaolo Bonzini tcg_out_dat_reg(s, cond, ARITH_MOV, rd, 0, rm, SHIFT_IMM_LSL(0)); 574139c1837SPaolo Bonzini } 575139c1837SPaolo Bonzini} 576139c1837SPaolo Bonzini 5771446600fSRichard Hendersonstatic void tcg_out_bx_reg(TCGContext *s, ARMCond cond, TCGReg rn) 578139c1837SPaolo Bonzini{ 579139c1837SPaolo Bonzini tcg_out32(s, (cond << 28) | 0x012fff10 | rn); 580326b9669SRichard Henderson} 581326b9669SRichard Henderson 5821446600fSRichard Hendersonstatic void tcg_out_b_reg(TCGContext *s, ARMCond cond, TCGReg rn) 583326b9669SRichard Henderson{ 584326b9669SRichard Henderson /* 585326b9669SRichard Henderson * Unless the C portion of QEMU is compiled as thumb, we don't need 586326b9669SRichard Henderson * true BX semantics; merely a branch to an address held in a register. 587326b9669SRichard Henderson */ 588326b9669SRichard Henderson tcg_out_bx_reg(s, cond, rn); 589139c1837SPaolo Bonzini} 590139c1837SPaolo Bonzini 591142fb62fSRichard Hendersonstatic void tcg_out_dat_imm(TCGContext *s, ARMCond cond, ARMInsn opc, 592e028eadaSRichard Henderson TCGReg rd, TCGReg rn, int im) 593139c1837SPaolo Bonzini{ 594139c1837SPaolo Bonzini tcg_out32(s, (cond << 28) | (1 << 25) | opc | 595139c1837SPaolo Bonzini (rn << 16) | (rd << 12) | im); 596139c1837SPaolo Bonzini} 597139c1837SPaolo Bonzini 598142fb62fSRichard Hendersonstatic void tcg_out_ldstm(TCGContext *s, ARMCond cond, ARMInsn opc, 59931d160adSRichard Henderson TCGReg rn, uint16_t mask) 60031d160adSRichard Henderson{ 60131d160adSRichard Henderson tcg_out32(s, (cond << 28) | opc | (rn << 16) | mask); 60231d160adSRichard Henderson} 60331d160adSRichard Henderson 604139c1837SPaolo Bonzini/* Note that this routine is used for both LDR and LDRH formats, so we do 605139c1837SPaolo Bonzini not wish to include an immediate shift at this point. */ 6061446600fSRichard Hendersonstatic void tcg_out_memop_r(TCGContext *s, ARMCond cond, ARMInsn opc, TCGReg rt, 607139c1837SPaolo Bonzini TCGReg rn, TCGReg rm, bool u, bool p, bool w) 608139c1837SPaolo Bonzini{ 609139c1837SPaolo Bonzini tcg_out32(s, (cond << 28) | opc | (u << 23) | (p << 24) 610139c1837SPaolo Bonzini | (w << 21) | (rn << 16) | (rt << 12) | rm); 611139c1837SPaolo Bonzini} 612139c1837SPaolo Bonzini 6131446600fSRichard Hendersonstatic void tcg_out_memop_8(TCGContext *s, ARMCond cond, ARMInsn opc, TCGReg rt, 614139c1837SPaolo Bonzini TCGReg rn, int imm8, bool p, bool w) 615139c1837SPaolo Bonzini{ 616139c1837SPaolo Bonzini bool u = 1; 617139c1837SPaolo Bonzini if (imm8 < 0) { 618139c1837SPaolo Bonzini imm8 = -imm8; 619139c1837SPaolo Bonzini u = 0; 620139c1837SPaolo Bonzini } 621139c1837SPaolo Bonzini tcg_out32(s, (cond << 28) | opc | (u << 23) | (p << 24) | (w << 21) | 622139c1837SPaolo Bonzini (rn << 16) | (rt << 12) | ((imm8 & 0xf0) << 4) | (imm8 & 0xf)); 623139c1837SPaolo Bonzini} 624139c1837SPaolo Bonzini 625142fb62fSRichard Hendersonstatic void tcg_out_memop_12(TCGContext *s, ARMCond cond, ARMInsn opc, 626142fb62fSRichard Henderson TCGReg rt, TCGReg rn, int imm12, bool p, bool w) 627139c1837SPaolo Bonzini{ 628139c1837SPaolo Bonzini bool u = 1; 629139c1837SPaolo Bonzini if (imm12 < 0) { 630139c1837SPaolo Bonzini imm12 = -imm12; 631139c1837SPaolo Bonzini u = 0; 632139c1837SPaolo Bonzini } 633139c1837SPaolo Bonzini tcg_out32(s, (cond << 28) | opc | (u << 23) | (p << 24) | (w << 21) | 634139c1837SPaolo Bonzini (rn << 16) | (rt << 12) | imm12); 635139c1837SPaolo Bonzini} 636139c1837SPaolo Bonzini 6371446600fSRichard Hendersonstatic void tcg_out_ld32_12(TCGContext *s, ARMCond cond, TCGReg rt, 638139c1837SPaolo Bonzini TCGReg rn, int imm12) 639139c1837SPaolo Bonzini{ 640139c1837SPaolo Bonzini tcg_out_memop_12(s, cond, INSN_LDR_IMM, rt, rn, imm12, 1, 0); 641139c1837SPaolo Bonzini} 642139c1837SPaolo Bonzini 6431446600fSRichard Hendersonstatic void tcg_out_st32_12(TCGContext *s, ARMCond cond, TCGReg rt, 644139c1837SPaolo Bonzini TCGReg rn, int imm12) 645139c1837SPaolo Bonzini{ 646139c1837SPaolo Bonzini tcg_out_memop_12(s, cond, INSN_STR_IMM, rt, rn, imm12, 1, 0); 647139c1837SPaolo Bonzini} 648139c1837SPaolo Bonzini 6491446600fSRichard Hendersonstatic void tcg_out_ld32_r(TCGContext *s, ARMCond cond, TCGReg rt, 650139c1837SPaolo Bonzini TCGReg rn, TCGReg rm) 651139c1837SPaolo Bonzini{ 652139c1837SPaolo Bonzini tcg_out_memop_r(s, cond, INSN_LDR_REG, rt, rn, rm, 1, 1, 0); 653139c1837SPaolo Bonzini} 654139c1837SPaolo Bonzini 6551446600fSRichard Hendersonstatic void tcg_out_st32_r(TCGContext *s, ARMCond cond, TCGReg rt, 656139c1837SPaolo Bonzini TCGReg rn, TCGReg rm) 657139c1837SPaolo Bonzini{ 658139c1837SPaolo Bonzini tcg_out_memop_r(s, cond, INSN_STR_REG, rt, rn, rm, 1, 1, 0); 659139c1837SPaolo Bonzini} 660139c1837SPaolo Bonzini 6611446600fSRichard Hendersonstatic void tcg_out_ldrd_8(TCGContext *s, ARMCond cond, TCGReg rt, 662139c1837SPaolo Bonzini TCGReg rn, int imm8) 663139c1837SPaolo Bonzini{ 664139c1837SPaolo Bonzini tcg_out_memop_8(s, cond, INSN_LDRD_IMM, rt, rn, imm8, 1, 0); 665139c1837SPaolo Bonzini} 666139c1837SPaolo Bonzini 6671446600fSRichard Hendersonstatic void tcg_out_ldrd_r(TCGContext *s, ARMCond cond, TCGReg rt, 668139c1837SPaolo Bonzini TCGReg rn, TCGReg rm) 669139c1837SPaolo Bonzini{ 670139c1837SPaolo Bonzini tcg_out_memop_r(s, cond, INSN_LDRD_REG, rt, rn, rm, 1, 1, 0); 671139c1837SPaolo Bonzini} 672139c1837SPaolo Bonzini 6735f726ebcSRichard Hendersonstatic void __attribute__((unused)) 6741446600fSRichard Hendersontcg_out_ldrd_rwb(TCGContext *s, ARMCond cond, TCGReg rt, TCGReg rn, TCGReg rm) 675139c1837SPaolo Bonzini{ 676139c1837SPaolo Bonzini tcg_out_memop_r(s, cond, INSN_LDRD_REG, rt, rn, rm, 1, 1, 1); 677139c1837SPaolo Bonzini} 678139c1837SPaolo Bonzini 67974c17067SRichard Hendersonstatic void __attribute__((unused)) 68074c17067SRichard Hendersontcg_out_strd_8(TCGContext *s, ARMCond cond, TCGReg rt, TCGReg rn, int imm8) 681139c1837SPaolo Bonzini{ 682139c1837SPaolo Bonzini tcg_out_memop_8(s, cond, INSN_STRD_IMM, rt, rn, imm8, 1, 0); 683139c1837SPaolo Bonzini} 684139c1837SPaolo Bonzini 6851446600fSRichard Hendersonstatic void tcg_out_strd_r(TCGContext *s, ARMCond cond, TCGReg rt, 686139c1837SPaolo Bonzini TCGReg rn, TCGReg rm) 687139c1837SPaolo Bonzini{ 688139c1837SPaolo Bonzini tcg_out_memop_r(s, cond, INSN_STRD_REG, rt, rn, rm, 1, 1, 0); 689139c1837SPaolo Bonzini} 690139c1837SPaolo Bonzini 691139c1837SPaolo Bonzini/* Register pre-increment with base writeback. */ 6921446600fSRichard Hendersonstatic void tcg_out_ld32_rwb(TCGContext *s, ARMCond cond, TCGReg rt, 693139c1837SPaolo Bonzini TCGReg rn, TCGReg rm) 694139c1837SPaolo Bonzini{ 695139c1837SPaolo Bonzini tcg_out_memop_r(s, cond, INSN_LDR_REG, rt, rn, rm, 1, 1, 1); 696139c1837SPaolo Bonzini} 697139c1837SPaolo Bonzini 6981446600fSRichard Hendersonstatic void tcg_out_st32_rwb(TCGContext *s, ARMCond cond, TCGReg rt, 699139c1837SPaolo Bonzini TCGReg rn, TCGReg rm) 700139c1837SPaolo Bonzini{ 701139c1837SPaolo Bonzini tcg_out_memop_r(s, cond, INSN_STR_REG, rt, rn, rm, 1, 1, 1); 702139c1837SPaolo Bonzini} 703139c1837SPaolo Bonzini 7041446600fSRichard Hendersonstatic void tcg_out_ld16u_8(TCGContext *s, ARMCond cond, TCGReg rt, 705139c1837SPaolo Bonzini TCGReg rn, int imm8) 706139c1837SPaolo Bonzini{ 707139c1837SPaolo Bonzini tcg_out_memop_8(s, cond, INSN_LDRH_IMM, rt, rn, imm8, 1, 0); 708139c1837SPaolo Bonzini} 709139c1837SPaolo Bonzini 7101446600fSRichard Hendersonstatic void tcg_out_st16_8(TCGContext *s, ARMCond cond, TCGReg rt, 711139c1837SPaolo Bonzini TCGReg rn, int imm8) 712139c1837SPaolo Bonzini{ 713139c1837SPaolo Bonzini tcg_out_memop_8(s, cond, INSN_STRH_IMM, rt, rn, imm8, 1, 0); 714139c1837SPaolo Bonzini} 715139c1837SPaolo Bonzini 7161446600fSRichard Hendersonstatic void tcg_out_ld16u_r(TCGContext *s, ARMCond cond, TCGReg rt, 717139c1837SPaolo Bonzini TCGReg rn, TCGReg rm) 718139c1837SPaolo Bonzini{ 719139c1837SPaolo Bonzini tcg_out_memop_r(s, cond, INSN_LDRH_REG, rt, rn, rm, 1, 1, 0); 720139c1837SPaolo Bonzini} 721139c1837SPaolo Bonzini 7221446600fSRichard Hendersonstatic void tcg_out_st16_r(TCGContext *s, ARMCond cond, TCGReg rt, 723139c1837SPaolo Bonzini TCGReg rn, TCGReg rm) 724139c1837SPaolo Bonzini{ 725139c1837SPaolo Bonzini tcg_out_memop_r(s, cond, INSN_STRH_REG, rt, rn, rm, 1, 1, 0); 726139c1837SPaolo Bonzini} 727139c1837SPaolo Bonzini 7281446600fSRichard Hendersonstatic void tcg_out_ld16s_8(TCGContext *s, ARMCond cond, TCGReg rt, 729139c1837SPaolo Bonzini TCGReg rn, int imm8) 730139c1837SPaolo Bonzini{ 731139c1837SPaolo Bonzini tcg_out_memop_8(s, cond, INSN_LDRSH_IMM, rt, rn, imm8, 1, 0); 732139c1837SPaolo Bonzini} 733139c1837SPaolo Bonzini 7341446600fSRichard Hendersonstatic void tcg_out_ld16s_r(TCGContext *s, ARMCond cond, TCGReg rt, 735139c1837SPaolo Bonzini TCGReg rn, TCGReg rm) 736139c1837SPaolo Bonzini{ 737139c1837SPaolo Bonzini tcg_out_memop_r(s, cond, INSN_LDRSH_REG, rt, rn, rm, 1, 1, 0); 738139c1837SPaolo Bonzini} 739139c1837SPaolo Bonzini 7401446600fSRichard Hendersonstatic void tcg_out_ld8_12(TCGContext *s, ARMCond cond, TCGReg rt, 741139c1837SPaolo Bonzini TCGReg rn, int imm12) 742139c1837SPaolo Bonzini{ 743139c1837SPaolo Bonzini tcg_out_memop_12(s, cond, INSN_LDRB_IMM, rt, rn, imm12, 1, 0); 744139c1837SPaolo Bonzini} 745139c1837SPaolo Bonzini 7461446600fSRichard Hendersonstatic void tcg_out_st8_12(TCGContext *s, ARMCond cond, TCGReg rt, 747139c1837SPaolo Bonzini TCGReg rn, int imm12) 748139c1837SPaolo Bonzini{ 749139c1837SPaolo Bonzini tcg_out_memop_12(s, cond, INSN_STRB_IMM, rt, rn, imm12, 1, 0); 750139c1837SPaolo Bonzini} 751139c1837SPaolo Bonzini 7521446600fSRichard Hendersonstatic void tcg_out_ld8_r(TCGContext *s, ARMCond cond, TCGReg rt, 753139c1837SPaolo Bonzini TCGReg rn, TCGReg rm) 754139c1837SPaolo Bonzini{ 755139c1837SPaolo Bonzini tcg_out_memop_r(s, cond, INSN_LDRB_REG, rt, rn, rm, 1, 1, 0); 756139c1837SPaolo Bonzini} 757139c1837SPaolo Bonzini 7581446600fSRichard Hendersonstatic void tcg_out_st8_r(TCGContext *s, ARMCond cond, TCGReg rt, 759139c1837SPaolo Bonzini TCGReg rn, TCGReg rm) 760139c1837SPaolo Bonzini{ 761139c1837SPaolo Bonzini tcg_out_memop_r(s, cond, INSN_STRB_REG, rt, rn, rm, 1, 1, 0); 762139c1837SPaolo Bonzini} 763139c1837SPaolo Bonzini 7641446600fSRichard Hendersonstatic void tcg_out_ld8s_8(TCGContext *s, ARMCond cond, TCGReg rt, 765139c1837SPaolo Bonzini TCGReg rn, int imm8) 766139c1837SPaolo Bonzini{ 767139c1837SPaolo Bonzini tcg_out_memop_8(s, cond, INSN_LDRSB_IMM, rt, rn, imm8, 1, 0); 768139c1837SPaolo Bonzini} 769139c1837SPaolo Bonzini 7701446600fSRichard Hendersonstatic void tcg_out_ld8s_r(TCGContext *s, ARMCond cond, TCGReg rt, 771139c1837SPaolo Bonzini TCGReg rn, TCGReg rm) 772139c1837SPaolo Bonzini{ 773139c1837SPaolo Bonzini tcg_out_memop_r(s, cond, INSN_LDRSB_REG, rt, rn, rm, 1, 1, 0); 774139c1837SPaolo Bonzini} 775139c1837SPaolo Bonzini 776e028eadaSRichard Hendersonstatic void tcg_out_movi_pool(TCGContext *s, ARMCond cond, 777e028eadaSRichard Henderson TCGReg rd, uint32_t arg) 778139c1837SPaolo Bonzini{ 779139c1837SPaolo Bonzini new_pool_label(s, arg, R_ARM_PC13, s->code_ptr, 0); 780139c1837SPaolo Bonzini tcg_out_ld32_12(s, cond, rd, TCG_REG_PC, 0); 781139c1837SPaolo Bonzini} 782139c1837SPaolo Bonzini 783e028eadaSRichard Hendersonstatic void tcg_out_movi32(TCGContext *s, ARMCond cond, 784e028eadaSRichard Henderson TCGReg rd, uint32_t arg) 785139c1837SPaolo Bonzini{ 78690606715SRichard Henderson int imm12, diff, opc, sh1, sh2; 787139c1837SPaolo Bonzini uint32_t tt0, tt1, tt2; 788139c1837SPaolo Bonzini 789139c1837SPaolo Bonzini /* Check a single MOV/MVN before anything else. */ 79090606715SRichard Henderson imm12 = encode_imm(arg); 79190606715SRichard Henderson if (imm12 >= 0) { 79290606715SRichard Henderson tcg_out_dat_imm(s, cond, ARITH_MOV, rd, 0, imm12); 793139c1837SPaolo Bonzini return; 794139c1837SPaolo Bonzini } 79590606715SRichard Henderson imm12 = encode_imm(~arg); 79690606715SRichard Henderson if (imm12 >= 0) { 79790606715SRichard Henderson tcg_out_dat_imm(s, cond, ARITH_MVN, rd, 0, imm12); 798139c1837SPaolo Bonzini return; 799139c1837SPaolo Bonzini } 800139c1837SPaolo Bonzini 801139c1837SPaolo Bonzini /* Check for a pc-relative address. This will usually be the TB, 802139c1837SPaolo Bonzini or within the TB, which is immediately before the code block. */ 80369478b8bSRichard Henderson diff = tcg_pcrel_diff(s, (void *)arg) - 8; 804139c1837SPaolo Bonzini if (diff >= 0) { 80590606715SRichard Henderson imm12 = encode_imm(diff); 80690606715SRichard Henderson if (imm12 >= 0) { 80790606715SRichard Henderson tcg_out_dat_imm(s, cond, ARITH_ADD, rd, TCG_REG_PC, imm12); 808139c1837SPaolo Bonzini return; 809139c1837SPaolo Bonzini } 810139c1837SPaolo Bonzini } else { 81190606715SRichard Henderson imm12 = encode_imm(-diff); 81290606715SRichard Henderson if (imm12 >= 0) { 81390606715SRichard Henderson tcg_out_dat_imm(s, cond, ARITH_SUB, rd, TCG_REG_PC, imm12); 814139c1837SPaolo Bonzini return; 815139c1837SPaolo Bonzini } 816139c1837SPaolo Bonzini } 817139c1837SPaolo Bonzini 818139c1837SPaolo Bonzini /* Use movw + movt. */ 819139c1837SPaolo Bonzini if (use_armv7_instructions) { 820139c1837SPaolo Bonzini /* movw */ 821139c1837SPaolo Bonzini tcg_out32(s, (cond << 28) | 0x03000000 | (rd << 12) 822139c1837SPaolo Bonzini | ((arg << 4) & 0x000f0000) | (arg & 0xfff)); 823139c1837SPaolo Bonzini if (arg & 0xffff0000) { 824139c1837SPaolo Bonzini /* movt */ 825139c1837SPaolo Bonzini tcg_out32(s, (cond << 28) | 0x03400000 | (rd << 12) 826139c1837SPaolo Bonzini | ((arg >> 12) & 0x000f0000) | ((arg >> 16) & 0xfff)); 827139c1837SPaolo Bonzini } 828139c1837SPaolo Bonzini return; 829139c1837SPaolo Bonzini } 830139c1837SPaolo Bonzini 831139c1837SPaolo Bonzini /* Look for sequences of two insns. If we have lots of 1's, we can 832139c1837SPaolo Bonzini shorten the sequence by beginning with mvn and then clearing 833139c1837SPaolo Bonzini higher bits with eor. */ 834139c1837SPaolo Bonzini tt0 = arg; 835139c1837SPaolo Bonzini opc = ARITH_MOV; 836139c1837SPaolo Bonzini if (ctpop32(arg) > 16) { 837139c1837SPaolo Bonzini tt0 = ~arg; 838139c1837SPaolo Bonzini opc = ARITH_MVN; 839139c1837SPaolo Bonzini } 840139c1837SPaolo Bonzini sh1 = ctz32(tt0) & ~1; 841139c1837SPaolo Bonzini tt1 = tt0 & ~(0xff << sh1); 842139c1837SPaolo Bonzini sh2 = ctz32(tt1) & ~1; 843139c1837SPaolo Bonzini tt2 = tt1 & ~(0xff << sh2); 844139c1837SPaolo Bonzini if (tt2 == 0) { 84590606715SRichard Henderson int rot; 84690606715SRichard Henderson 847139c1837SPaolo Bonzini rot = ((32 - sh1) << 7) & 0xf00; 848139c1837SPaolo Bonzini tcg_out_dat_imm(s, cond, opc, rd, 0, ((tt0 >> sh1) & 0xff) | rot); 849139c1837SPaolo Bonzini rot = ((32 - sh2) << 7) & 0xf00; 850139c1837SPaolo Bonzini tcg_out_dat_imm(s, cond, ARITH_EOR, rd, rd, 851139c1837SPaolo Bonzini ((tt0 >> sh2) & 0xff) | rot); 852139c1837SPaolo Bonzini return; 853139c1837SPaolo Bonzini } 854139c1837SPaolo Bonzini 855139c1837SPaolo Bonzini /* Otherwise, drop it into the constant pool. */ 856139c1837SPaolo Bonzini tcg_out_movi_pool(s, cond, rd, arg); 857139c1837SPaolo Bonzini} 858139c1837SPaolo Bonzini 85990606715SRichard Henderson/* 86090606715SRichard Henderson * Emit either the reg,imm or reg,reg form of a data-processing insn. 86190606715SRichard Henderson * rhs must satisfy the "rI" constraint. 86290606715SRichard Henderson */ 863e028eadaSRichard Hendersonstatic void tcg_out_dat_rI(TCGContext *s, ARMCond cond, ARMInsn opc, 864e028eadaSRichard Henderson TCGReg dst, TCGReg lhs, TCGArg rhs, int rhs_is_const) 865139c1837SPaolo Bonzini{ 866139c1837SPaolo Bonzini if (rhs_is_const) { 86790606715SRichard Henderson tcg_out_dat_imm(s, cond, opc, dst, lhs, encode_imm_nofail(rhs)); 868139c1837SPaolo Bonzini } else { 869139c1837SPaolo Bonzini tcg_out_dat_reg(s, cond, opc, dst, lhs, rhs, SHIFT_IMM_LSL(0)); 870139c1837SPaolo Bonzini } 871139c1837SPaolo Bonzini} 872139c1837SPaolo Bonzini 87390606715SRichard Henderson/* 87490606715SRichard Henderson * Emit either the reg,imm or reg,reg form of a data-processing insn. 87590606715SRichard Henderson * rhs must satisfy the "rIK" constraint. 87690606715SRichard Henderson */ 877142fb62fSRichard Hendersonstatic void tcg_out_dat_rIK(TCGContext *s, ARMCond cond, ARMInsn opc, 878142fb62fSRichard Henderson ARMInsn opinv, TCGReg dst, TCGReg lhs, TCGArg rhs, 879139c1837SPaolo Bonzini bool rhs_is_const) 880139c1837SPaolo Bonzini{ 881139c1837SPaolo Bonzini if (rhs_is_const) { 88290606715SRichard Henderson int imm12 = encode_imm(rhs); 88390606715SRichard Henderson if (imm12 < 0) { 88490606715SRichard Henderson imm12 = encode_imm_nofail(~rhs); 885139c1837SPaolo Bonzini opc = opinv; 886139c1837SPaolo Bonzini } 88790606715SRichard Henderson tcg_out_dat_imm(s, cond, opc, dst, lhs, imm12); 888139c1837SPaolo Bonzini } else { 889139c1837SPaolo Bonzini tcg_out_dat_reg(s, cond, opc, dst, lhs, rhs, SHIFT_IMM_LSL(0)); 890139c1837SPaolo Bonzini } 891139c1837SPaolo Bonzini} 892139c1837SPaolo Bonzini 893142fb62fSRichard Hendersonstatic void tcg_out_dat_rIN(TCGContext *s, ARMCond cond, ARMInsn opc, 894e028eadaSRichard Henderson ARMInsn opneg, TCGReg dst, TCGReg lhs, TCGArg rhs, 895139c1837SPaolo Bonzini bool rhs_is_const) 896139c1837SPaolo Bonzini{ 897139c1837SPaolo Bonzini /* Emit either the reg,imm or reg,reg form of a data-processing insn. 898139c1837SPaolo Bonzini * rhs must satisfy the "rIN" constraint. 899139c1837SPaolo Bonzini */ 900139c1837SPaolo Bonzini if (rhs_is_const) { 90190606715SRichard Henderson int imm12 = encode_imm(rhs); 90290606715SRichard Henderson if (imm12 < 0) { 90390606715SRichard Henderson imm12 = encode_imm_nofail(-rhs); 904139c1837SPaolo Bonzini opc = opneg; 905139c1837SPaolo Bonzini } 90690606715SRichard Henderson tcg_out_dat_imm(s, cond, opc, dst, lhs, imm12); 907139c1837SPaolo Bonzini } else { 908139c1837SPaolo Bonzini tcg_out_dat_reg(s, cond, opc, dst, lhs, rhs, SHIFT_IMM_LSL(0)); 909139c1837SPaolo Bonzini } 910139c1837SPaolo Bonzini} 911139c1837SPaolo Bonzini 9121446600fSRichard Hendersonstatic void tcg_out_mul32(TCGContext *s, ARMCond cond, TCGReg rd, 913139c1837SPaolo Bonzini TCGReg rn, TCGReg rm) 914139c1837SPaolo Bonzini{ 915139c1837SPaolo Bonzini /* mul */ 916139c1837SPaolo Bonzini tcg_out32(s, (cond << 28) | 0x90 | (rd << 16) | (rm << 8) | rn); 917139c1837SPaolo Bonzini} 918139c1837SPaolo Bonzini 9191446600fSRichard Hendersonstatic void tcg_out_umull32(TCGContext *s, ARMCond cond, TCGReg rd0, 920139c1837SPaolo Bonzini TCGReg rd1, TCGReg rn, TCGReg rm) 921139c1837SPaolo Bonzini{ 922139c1837SPaolo Bonzini /* umull */ 923139c1837SPaolo Bonzini tcg_out32(s, (cond << 28) | 0x00800090 | 924139c1837SPaolo Bonzini (rd1 << 16) | (rd0 << 12) | (rm << 8) | rn); 925139c1837SPaolo Bonzini} 926139c1837SPaolo Bonzini 9271446600fSRichard Hendersonstatic void tcg_out_smull32(TCGContext *s, ARMCond cond, TCGReg rd0, 928139c1837SPaolo Bonzini TCGReg rd1, TCGReg rn, TCGReg rm) 929139c1837SPaolo Bonzini{ 930139c1837SPaolo Bonzini /* smull */ 931139c1837SPaolo Bonzini tcg_out32(s, (cond << 28) | 0x00c00090 | 932139c1837SPaolo Bonzini (rd1 << 16) | (rd0 << 12) | (rm << 8) | rn); 933139c1837SPaolo Bonzini} 934139c1837SPaolo Bonzini 935e028eadaSRichard Hendersonstatic void tcg_out_sdiv(TCGContext *s, ARMCond cond, 936e028eadaSRichard Henderson TCGReg rd, TCGReg rn, TCGReg rm) 937139c1837SPaolo Bonzini{ 938139c1837SPaolo Bonzini tcg_out32(s, 0x0710f010 | (cond << 28) | (rd << 16) | rn | (rm << 8)); 939139c1837SPaolo Bonzini} 940139c1837SPaolo Bonzini 941e028eadaSRichard Hendersonstatic void tcg_out_udiv(TCGContext *s, ARMCond cond, 942e028eadaSRichard Henderson TCGReg rd, TCGReg rn, TCGReg rm) 943139c1837SPaolo Bonzini{ 944139c1837SPaolo Bonzini tcg_out32(s, 0x0730f010 | (cond << 28) | (rd << 16) | rn | (rm << 8)); 945139c1837SPaolo Bonzini} 946139c1837SPaolo Bonzini 947678155b2SRichard Hendersonstatic void tcg_out_ext8s(TCGContext *s, TCGType t, TCGReg rd, TCGReg rn) 948139c1837SPaolo Bonzini{ 949139c1837SPaolo Bonzini /* sxtb */ 950678155b2SRichard Henderson tcg_out32(s, 0x06af0070 | (COND_AL << 28) | (rd << 12) | rn); 951139c1837SPaolo Bonzini} 952139c1837SPaolo Bonzini 953d0e66c89SRichard Hendersonstatic void tcg_out_ext8u(TCGContext *s, TCGReg rd, TCGReg rn) 954d0e66c89SRichard Henderson{ 955d0e66c89SRichard Henderson tcg_out_dat_imm(s, COND_AL, ARITH_AND, rd, rn, 0xff); 956d0e66c89SRichard Henderson} 957d0e66c89SRichard Henderson 958753e42eaSRichard Hendersonstatic void tcg_out_ext16s(TCGContext *s, TCGType t, TCGReg rd, TCGReg rn) 959139c1837SPaolo Bonzini{ 960139c1837SPaolo Bonzini /* sxth */ 961753e42eaSRichard Henderson tcg_out32(s, 0x06bf0070 | (COND_AL << 28) | (rd << 12) | rn); 962139c1837SPaolo Bonzini} 963139c1837SPaolo Bonzini 964379afdffSRichard Hendersonstatic void tcg_out_ext16u(TCGContext *s, TCGReg rd, TCGReg rn) 965379afdffSRichard Henderson{ 96674c17067SRichard Henderson /* uxth */ 96774c17067SRichard Henderson tcg_out32(s, 0x06ff0070 | (COND_AL << 28) | (rd << 12) | rn); 968379afdffSRichard Henderson} 969379afdffSRichard Henderson 97052bf3398SRichard Hendersonstatic void tcg_out_ext32s(TCGContext *s, TCGReg rd, TCGReg rn) 97152bf3398SRichard Henderson{ 97252bf3398SRichard Henderson g_assert_not_reached(); 97352bf3398SRichard Henderson} 97452bf3398SRichard Henderson 9759ecf5f61SRichard Hendersonstatic void tcg_out_ext32u(TCGContext *s, TCGReg rd, TCGReg rn) 9769ecf5f61SRichard Henderson{ 9779ecf5f61SRichard Henderson g_assert_not_reached(); 9789ecf5f61SRichard Henderson} 9799ecf5f61SRichard Henderson 9809c6aa274SRichard Hendersonstatic void tcg_out_exts_i32_i64(TCGContext *s, TCGReg rd, TCGReg rn) 9819c6aa274SRichard Henderson{ 9829c6aa274SRichard Henderson g_assert_not_reached(); 9839c6aa274SRichard Henderson} 9849c6aa274SRichard Henderson 985b9bfe000SRichard Hendersonstatic void tcg_out_extu_i32_i64(TCGContext *s, TCGReg rd, TCGReg rn) 986b9bfe000SRichard Henderson{ 987b9bfe000SRichard Henderson g_assert_not_reached(); 988b9bfe000SRichard Henderson} 989b9bfe000SRichard Henderson 990b8b94ac6SRichard Hendersonstatic void tcg_out_extrl_i64_i32(TCGContext *s, TCGReg rd, TCGReg rn) 991b8b94ac6SRichard Henderson{ 992b8b94ac6SRichard Henderson g_assert_not_reached(); 993b8b94ac6SRichard Henderson} 994b8b94ac6SRichard Henderson 995e028eadaSRichard Hendersonstatic void tcg_out_bswap16(TCGContext *s, ARMCond cond, 996e028eadaSRichard Henderson TCGReg rd, TCGReg rn, int flags) 997139c1837SPaolo Bonzini{ 9982ec89a78SRichard Henderson if (flags & TCG_BSWAP_OS) { 999139c1837SPaolo Bonzini /* revsh */ 1000139c1837SPaolo Bonzini tcg_out32(s, 0x06ff0fb0 | (cond << 28) | (rd << 12) | rn); 10012ec89a78SRichard Henderson return; 1002139c1837SPaolo Bonzini } 1003139c1837SPaolo Bonzini 1004139c1837SPaolo Bonzini /* rev16 */ 1005139c1837SPaolo Bonzini tcg_out32(s, 0x06bf0fb0 | (cond << 28) | (rd << 12) | rn); 10062ec89a78SRichard Henderson if ((flags & (TCG_BSWAP_IZ | TCG_BSWAP_OZ)) == TCG_BSWAP_OZ) { 10072ec89a78SRichard Henderson /* uxth */ 10082ec89a78SRichard Henderson tcg_out32(s, 0x06ff0070 | (cond << 28) | (rd << 12) | rd); 1009139c1837SPaolo Bonzini } 1010139c1837SPaolo Bonzini} 1011139c1837SPaolo Bonzini 1012e028eadaSRichard Hendersonstatic void tcg_out_bswap32(TCGContext *s, ARMCond cond, TCGReg rd, TCGReg rn) 1013139c1837SPaolo Bonzini{ 1014139c1837SPaolo Bonzini /* rev */ 1015139c1837SPaolo Bonzini tcg_out32(s, 0x06bf0f30 | (cond << 28) | (rd << 12) | rn); 1016139c1837SPaolo Bonzini} 1017139c1837SPaolo Bonzini 10181446600fSRichard Hendersonstatic void tcg_out_deposit(TCGContext *s, ARMCond cond, TCGReg rd, 1019139c1837SPaolo Bonzini TCGArg a1, int ofs, int len, bool const_a1) 1020139c1837SPaolo Bonzini{ 1021139c1837SPaolo Bonzini if (const_a1) { 1022139c1837SPaolo Bonzini /* bfi becomes bfc with rn == 15. */ 1023139c1837SPaolo Bonzini a1 = 15; 1024139c1837SPaolo Bonzini } 1025139c1837SPaolo Bonzini /* bfi/bfc */ 1026139c1837SPaolo Bonzini tcg_out32(s, 0x07c00010 | (cond << 28) | (rd << 12) | a1 1027139c1837SPaolo Bonzini | (ofs << 7) | ((ofs + len - 1) << 16)); 1028139c1837SPaolo Bonzini} 1029139c1837SPaolo Bonzini 10301446600fSRichard Hendersonstatic void tcg_out_extract(TCGContext *s, ARMCond cond, TCGReg rd, 1031e028eadaSRichard Henderson TCGReg rn, int ofs, int len) 1032139c1837SPaolo Bonzini{ 1033139c1837SPaolo Bonzini /* ubfx */ 1034e028eadaSRichard Henderson tcg_out32(s, 0x07e00050 | (cond << 28) | (rd << 12) | rn 1035139c1837SPaolo Bonzini | (ofs << 7) | ((len - 1) << 16)); 1036139c1837SPaolo Bonzini} 1037139c1837SPaolo Bonzini 10381446600fSRichard Hendersonstatic void tcg_out_sextract(TCGContext *s, ARMCond cond, TCGReg rd, 1039e028eadaSRichard Henderson TCGReg rn, int ofs, int len) 1040139c1837SPaolo Bonzini{ 1041139c1837SPaolo Bonzini /* sbfx */ 1042e028eadaSRichard Henderson tcg_out32(s, 0x07a00050 | (cond << 28) | (rd << 12) | rn 1043139c1837SPaolo Bonzini | (ofs << 7) | ((len - 1) << 16)); 1044139c1837SPaolo Bonzini} 1045139c1837SPaolo Bonzini 10461446600fSRichard Hendersonstatic void tcg_out_ld32u(TCGContext *s, ARMCond cond, 1047e028eadaSRichard Henderson TCGReg rd, TCGReg rn, int32_t offset) 1048139c1837SPaolo Bonzini{ 1049139c1837SPaolo Bonzini if (offset > 0xfff || offset < -0xfff) { 1050139c1837SPaolo Bonzini tcg_out_movi32(s, cond, TCG_REG_TMP, offset); 1051139c1837SPaolo Bonzini tcg_out_ld32_r(s, cond, rd, rn, TCG_REG_TMP); 1052139c1837SPaolo Bonzini } else 1053139c1837SPaolo Bonzini tcg_out_ld32_12(s, cond, rd, rn, offset); 1054139c1837SPaolo Bonzini} 1055139c1837SPaolo Bonzini 10561446600fSRichard Hendersonstatic void tcg_out_st32(TCGContext *s, ARMCond cond, 1057e028eadaSRichard Henderson TCGReg rd, TCGReg rn, int32_t offset) 1058139c1837SPaolo Bonzini{ 1059139c1837SPaolo Bonzini if (offset > 0xfff || offset < -0xfff) { 1060139c1837SPaolo Bonzini tcg_out_movi32(s, cond, TCG_REG_TMP, offset); 1061139c1837SPaolo Bonzini tcg_out_st32_r(s, cond, rd, rn, TCG_REG_TMP); 1062139c1837SPaolo Bonzini } else 1063139c1837SPaolo Bonzini tcg_out_st32_12(s, cond, rd, rn, offset); 1064139c1837SPaolo Bonzini} 1065139c1837SPaolo Bonzini 10661446600fSRichard Hendersonstatic void tcg_out_ld16u(TCGContext *s, ARMCond cond, 1067e028eadaSRichard Henderson TCGReg rd, TCGReg rn, int32_t offset) 1068139c1837SPaolo Bonzini{ 1069139c1837SPaolo Bonzini if (offset > 0xff || offset < -0xff) { 1070139c1837SPaolo Bonzini tcg_out_movi32(s, cond, TCG_REG_TMP, offset); 1071139c1837SPaolo Bonzini tcg_out_ld16u_r(s, cond, rd, rn, TCG_REG_TMP); 1072139c1837SPaolo Bonzini } else 1073139c1837SPaolo Bonzini tcg_out_ld16u_8(s, cond, rd, rn, offset); 1074139c1837SPaolo Bonzini} 1075139c1837SPaolo Bonzini 10761446600fSRichard Hendersonstatic void tcg_out_ld16s(TCGContext *s, ARMCond cond, 1077e028eadaSRichard Henderson TCGReg rd, TCGReg rn, int32_t offset) 1078139c1837SPaolo Bonzini{ 1079139c1837SPaolo Bonzini if (offset > 0xff || offset < -0xff) { 1080139c1837SPaolo Bonzini tcg_out_movi32(s, cond, TCG_REG_TMP, offset); 1081139c1837SPaolo Bonzini tcg_out_ld16s_r(s, cond, rd, rn, TCG_REG_TMP); 1082139c1837SPaolo Bonzini } else 1083139c1837SPaolo Bonzini tcg_out_ld16s_8(s, cond, rd, rn, offset); 1084139c1837SPaolo Bonzini} 1085139c1837SPaolo Bonzini 10861446600fSRichard Hendersonstatic void tcg_out_st16(TCGContext *s, ARMCond cond, 1087e028eadaSRichard Henderson TCGReg rd, TCGReg rn, int32_t offset) 1088139c1837SPaolo Bonzini{ 1089139c1837SPaolo Bonzini if (offset > 0xff || offset < -0xff) { 1090139c1837SPaolo Bonzini tcg_out_movi32(s, cond, TCG_REG_TMP, offset); 1091139c1837SPaolo Bonzini tcg_out_st16_r(s, cond, rd, rn, TCG_REG_TMP); 1092139c1837SPaolo Bonzini } else 1093139c1837SPaolo Bonzini tcg_out_st16_8(s, cond, rd, rn, offset); 1094139c1837SPaolo Bonzini} 1095139c1837SPaolo Bonzini 10961446600fSRichard Hendersonstatic void tcg_out_ld8u(TCGContext *s, ARMCond cond, 1097e028eadaSRichard Henderson TCGReg rd, TCGReg rn, int32_t offset) 1098139c1837SPaolo Bonzini{ 1099139c1837SPaolo Bonzini if (offset > 0xfff || offset < -0xfff) { 1100139c1837SPaolo Bonzini tcg_out_movi32(s, cond, TCG_REG_TMP, offset); 1101139c1837SPaolo Bonzini tcg_out_ld8_r(s, cond, rd, rn, TCG_REG_TMP); 1102139c1837SPaolo Bonzini } else 1103139c1837SPaolo Bonzini tcg_out_ld8_12(s, cond, rd, rn, offset); 1104139c1837SPaolo Bonzini} 1105139c1837SPaolo Bonzini 11061446600fSRichard Hendersonstatic void tcg_out_ld8s(TCGContext *s, ARMCond cond, 1107e028eadaSRichard Henderson TCGReg rd, TCGReg rn, int32_t offset) 1108139c1837SPaolo Bonzini{ 1109139c1837SPaolo Bonzini if (offset > 0xff || offset < -0xff) { 1110139c1837SPaolo Bonzini tcg_out_movi32(s, cond, TCG_REG_TMP, offset); 1111139c1837SPaolo Bonzini tcg_out_ld8s_r(s, cond, rd, rn, TCG_REG_TMP); 1112139c1837SPaolo Bonzini } else 1113139c1837SPaolo Bonzini tcg_out_ld8s_8(s, cond, rd, rn, offset); 1114139c1837SPaolo Bonzini} 1115139c1837SPaolo Bonzini 11161446600fSRichard Hendersonstatic void tcg_out_st8(TCGContext *s, ARMCond cond, 1117e028eadaSRichard Henderson TCGReg rd, TCGReg rn, int32_t offset) 1118139c1837SPaolo Bonzini{ 1119139c1837SPaolo Bonzini if (offset > 0xfff || offset < -0xfff) { 1120139c1837SPaolo Bonzini tcg_out_movi32(s, cond, TCG_REG_TMP, offset); 1121139c1837SPaolo Bonzini tcg_out_st8_r(s, cond, rd, rn, TCG_REG_TMP); 1122139c1837SPaolo Bonzini } else 1123139c1837SPaolo Bonzini tcg_out_st8_12(s, cond, rd, rn, offset); 1124139c1837SPaolo Bonzini} 1125139c1837SPaolo Bonzini 1126b87c1addSRichard Henderson/* 1127b87c1addSRichard Henderson * The _goto case is normally between TBs within the same code buffer, and 1128139c1837SPaolo Bonzini * with the code buffer limited to 16MB we wouldn't need the long case. 1129139c1837SPaolo Bonzini * But we also use it for the tail-call to the qemu_ld/st helpers, which does. 1130139c1837SPaolo Bonzini */ 11311446600fSRichard Hendersonstatic void tcg_out_goto(TCGContext *s, ARMCond cond, const tcg_insn_unit *addr) 1132139c1837SPaolo Bonzini{ 1133139c1837SPaolo Bonzini intptr_t addri = (intptr_t)addr; 1134139c1837SPaolo Bonzini ptrdiff_t disp = tcg_pcrel_diff(s, addr); 1135b87c1addSRichard Henderson bool arm_mode = !(addri & 1); 1136139c1837SPaolo Bonzini 1137b87c1addSRichard Henderson if (arm_mode && disp - 8 < 0x01fffffd && disp - 8 > -0x01fffffd) { 1138326b9669SRichard Henderson tcg_out_b_imm(s, cond, disp); 1139139c1837SPaolo Bonzini return; 1140139c1837SPaolo Bonzini } 1141b87c1addSRichard Henderson 1142b87c1addSRichard Henderson /* LDR is interworking from v5t. */ 1143139c1837SPaolo Bonzini tcg_out_movi_pool(s, cond, TCG_REG_PC, addri); 1144b87c1addSRichard Henderson} 1145b87c1addSRichard Henderson 1146b87c1addSRichard Henderson/* 1147b87c1addSRichard Henderson * The call case is mostly used for helpers - so it's not unreasonable 1148b87c1addSRichard Henderson * for them to be beyond branch range. 1149b87c1addSRichard Henderson */ 1150cee44b03SRichard Hendersonstatic void tcg_out_call_int(TCGContext *s, const tcg_insn_unit *addr) 1151139c1837SPaolo Bonzini{ 1152139c1837SPaolo Bonzini intptr_t addri = (intptr_t)addr; 1153139c1837SPaolo Bonzini ptrdiff_t disp = tcg_pcrel_diff(s, addr); 1154b87c1addSRichard Henderson bool arm_mode = !(addri & 1); 1155139c1837SPaolo Bonzini 1156139c1837SPaolo Bonzini if (disp - 8 < 0x02000000 && disp - 8 >= -0x02000000) { 1157b87c1addSRichard Henderson if (arm_mode) { 1158326b9669SRichard Henderson tcg_out_bl_imm(s, COND_AL, disp); 11596cef1394SRichard Henderson } else { 1160b87c1addSRichard Henderson tcg_out_blx_imm(s, disp); 1161b87c1addSRichard Henderson } 11626cef1394SRichard Henderson return; 1163b87c1addSRichard Henderson } 1164b87c1addSRichard Henderson 1165139c1837SPaolo Bonzini tcg_out_movi32(s, COND_AL, TCG_REG_TMP, addri); 1166326b9669SRichard Henderson tcg_out_blx_reg(s, COND_AL, TCG_REG_TMP); 1167139c1837SPaolo Bonzini} 1168139c1837SPaolo Bonzini 1169cee44b03SRichard Hendersonstatic void tcg_out_call(TCGContext *s, const tcg_insn_unit *addr, 1170cee44b03SRichard Henderson const TCGHelperInfo *info) 1171cee44b03SRichard Henderson{ 1172cee44b03SRichard Henderson tcg_out_call_int(s, addr); 1173cee44b03SRichard Henderson} 1174cee44b03SRichard Henderson 11751446600fSRichard Hendersonstatic void tcg_out_goto_label(TCGContext *s, ARMCond cond, TCGLabel *l) 1176139c1837SPaolo Bonzini{ 1177139c1837SPaolo Bonzini if (l->has_value) { 1178139c1837SPaolo Bonzini tcg_out_goto(s, cond, l->u.value_ptr); 1179139c1837SPaolo Bonzini } else { 1180139c1837SPaolo Bonzini tcg_out_reloc(s, s->code_ptr, R_ARM_PC24, l, 0); 1181326b9669SRichard Henderson tcg_out_b_imm(s, cond, 0); 1182139c1837SPaolo Bonzini } 1183139c1837SPaolo Bonzini} 1184139c1837SPaolo Bonzini 11855f726ebcSRichard Hendersonstatic void tcg_out_mb(TCGContext *s, TCGArg a0) 1186139c1837SPaolo Bonzini{ 1187139c1837SPaolo Bonzini if (use_armv7_instructions) { 1188139c1837SPaolo Bonzini tcg_out32(s, INSN_DMB_ISH); 1189bde2cdb5SRichard Henderson } else { 1190139c1837SPaolo Bonzini tcg_out32(s, INSN_DMB_MCR); 1191139c1837SPaolo Bonzini } 1192139c1837SPaolo Bonzini} 1193139c1837SPaolo Bonzini 1194e67ec08cSRichard Hendersonstatic TCGCond tcg_out_cmp(TCGContext *s, TCGCond cond, TCGReg a, 1195e67ec08cSRichard Henderson TCGArg b, int b_const) 1196e67ec08cSRichard Henderson{ 11979f566614SRichard Henderson if (!is_tst_cond(cond)) { 1198e67ec08cSRichard Henderson tcg_out_dat_rIN(s, COND_AL, ARITH_CMP, ARITH_CMN, 0, a, b, b_const); 1199e67ec08cSRichard Henderson return cond; 1200e67ec08cSRichard Henderson } 1201e67ec08cSRichard Henderson 12029f566614SRichard Henderson cond = tcg_tst_eqne_cond(cond); 12039f566614SRichard Henderson if (b_const) { 12049f566614SRichard Henderson int imm12 = encode_imm(b); 12059f566614SRichard Henderson 12069f566614SRichard Henderson /* 12079f566614SRichard Henderson * The compare constraints allow rIN, but TST does not support N. 12089f566614SRichard Henderson * Be prepared to load the constant into a scratch register. 12099f566614SRichard Henderson */ 12109f566614SRichard Henderson if (imm12 >= 0) { 12119f566614SRichard Henderson tcg_out_dat_imm(s, COND_AL, ARITH_TST, 0, a, imm12); 12129f566614SRichard Henderson return cond; 12139f566614SRichard Henderson } 12149f566614SRichard Henderson tcg_out_movi32(s, COND_AL, TCG_REG_TMP, b); 12159f566614SRichard Henderson b = TCG_REG_TMP; 12169f566614SRichard Henderson } 12179f566614SRichard Henderson tcg_out_dat_reg(s, COND_AL, ARITH_TST, 0, a, b, SHIFT_IMM_LSL(0)); 12189f566614SRichard Henderson return cond; 12199f566614SRichard Henderson} 12209f566614SRichard Henderson 1221139c1837SPaolo Bonzinistatic TCGCond tcg_out_cmp2(TCGContext *s, const TCGArg *args, 1222139c1837SPaolo Bonzini const int *const_args) 1223139c1837SPaolo Bonzini{ 1224139c1837SPaolo Bonzini TCGReg al = args[0]; 1225139c1837SPaolo Bonzini TCGReg ah = args[1]; 1226139c1837SPaolo Bonzini TCGArg bl = args[2]; 1227139c1837SPaolo Bonzini TCGArg bh = args[3]; 1228139c1837SPaolo Bonzini TCGCond cond = args[4]; 1229139c1837SPaolo Bonzini int const_bl = const_args[2]; 1230139c1837SPaolo Bonzini int const_bh = const_args[3]; 1231139c1837SPaolo Bonzini 1232139c1837SPaolo Bonzini switch (cond) { 1233139c1837SPaolo Bonzini case TCG_COND_EQ: 1234139c1837SPaolo Bonzini case TCG_COND_NE: 1235139c1837SPaolo Bonzini case TCG_COND_LTU: 1236139c1837SPaolo Bonzini case TCG_COND_LEU: 1237139c1837SPaolo Bonzini case TCG_COND_GTU: 1238139c1837SPaolo Bonzini case TCG_COND_GEU: 12394daad8d9SMichael Tokarev /* 12404daad8d9SMichael Tokarev * We perform a conditional comparison. If the high half is 12414daad8d9SMichael Tokarev * equal, then overwrite the flags with the comparison of the 12424daad8d9SMichael Tokarev * low half. The resulting flags cover the whole. 12434daad8d9SMichael Tokarev */ 1244139c1837SPaolo Bonzini tcg_out_dat_rI(s, COND_AL, ARITH_CMP, 0, ah, bh, const_bh); 1245139c1837SPaolo Bonzini tcg_out_dat_rI(s, COND_EQ, ARITH_CMP, 0, al, bl, const_bl); 1246139c1837SPaolo Bonzini return cond; 1247139c1837SPaolo Bonzini 12489f566614SRichard Henderson case TCG_COND_TSTEQ: 12499f566614SRichard Henderson case TCG_COND_TSTNE: 12509f566614SRichard Henderson /* Similar, but with TST instead of CMP. */ 12519f566614SRichard Henderson tcg_out_dat_rI(s, COND_AL, ARITH_TST, 0, ah, bh, const_bh); 12529f566614SRichard Henderson tcg_out_dat_rI(s, COND_EQ, ARITH_TST, 0, al, bl, const_bl); 12539f566614SRichard Henderson return tcg_tst_eqne_cond(cond); 12549f566614SRichard Henderson 1255139c1837SPaolo Bonzini case TCG_COND_LT: 1256139c1837SPaolo Bonzini case TCG_COND_GE: 1257139c1837SPaolo Bonzini /* We perform a double-word subtraction and examine the result. 1258139c1837SPaolo Bonzini We do not actually need the result of the subtract, so the 1259139c1837SPaolo Bonzini low part "subtract" is a compare. For the high half we have 1260139c1837SPaolo Bonzini no choice but to compute into a temporary. */ 1261139c1837SPaolo Bonzini tcg_out_dat_rI(s, COND_AL, ARITH_CMP, 0, al, bl, const_bl); 1262139c1837SPaolo Bonzini tcg_out_dat_rI(s, COND_AL, ARITH_SBC | TO_CPSR, 1263139c1837SPaolo Bonzini TCG_REG_TMP, ah, bh, const_bh); 1264139c1837SPaolo Bonzini return cond; 1265139c1837SPaolo Bonzini 1266139c1837SPaolo Bonzini case TCG_COND_LE: 1267139c1837SPaolo Bonzini case TCG_COND_GT: 1268139c1837SPaolo Bonzini /* Similar, but with swapped arguments, via reversed subtract. */ 1269139c1837SPaolo Bonzini tcg_out_dat_rI(s, COND_AL, ARITH_RSB | TO_CPSR, 1270139c1837SPaolo Bonzini TCG_REG_TMP, al, bl, const_bl); 1271139c1837SPaolo Bonzini tcg_out_dat_rI(s, COND_AL, ARITH_RSC | TO_CPSR, 1272139c1837SPaolo Bonzini TCG_REG_TMP, ah, bh, const_bh); 1273139c1837SPaolo Bonzini return tcg_swap_cond(cond); 1274139c1837SPaolo Bonzini 1275139c1837SPaolo Bonzini default: 1276139c1837SPaolo Bonzini g_assert_not_reached(); 1277139c1837SPaolo Bonzini } 1278139c1837SPaolo Bonzini} 1279139c1837SPaolo Bonzini 12806e49fad2SRichard Henderson/* 12816e49fad2SRichard Henderson * Note that TCGReg references Q-registers. 12824daad8d9SMichael Tokarev * Q-regno = 2 * D-regno, so shift left by 1 while inserting. 12836e49fad2SRichard Henderson */ 12846e49fad2SRichard Hendersonstatic uint32_t encode_vd(TCGReg rd) 12856e49fad2SRichard Henderson{ 12866e49fad2SRichard Henderson tcg_debug_assert(rd >= TCG_REG_Q0); 12876e49fad2SRichard Henderson return (extract32(rd, 3, 1) << 22) | (extract32(rd, 0, 3) << 13); 12886e49fad2SRichard Henderson} 12896e49fad2SRichard Henderson 12902df2a8cfSRichard Hendersonstatic uint32_t encode_vn(TCGReg rn) 12912df2a8cfSRichard Henderson{ 12922df2a8cfSRichard Henderson tcg_debug_assert(rn >= TCG_REG_Q0); 12932df2a8cfSRichard Henderson return (extract32(rn, 3, 1) << 7) | (extract32(rn, 0, 3) << 17); 12942df2a8cfSRichard Henderson} 12952df2a8cfSRichard Henderson 12962df2a8cfSRichard Hendersonstatic uint32_t encode_vm(TCGReg rm) 12972df2a8cfSRichard Henderson{ 12982df2a8cfSRichard Henderson tcg_debug_assert(rm >= TCG_REG_Q0); 12992df2a8cfSRichard Henderson return (extract32(rm, 3, 1) << 5) | (extract32(rm, 0, 3) << 1); 13002df2a8cfSRichard Henderson} 13012df2a8cfSRichard Henderson 1302d74b86edSRichard Hendersonstatic void tcg_out_vreg2(TCGContext *s, ARMInsn insn, int q, int vece, 1303d74b86edSRichard Henderson TCGReg d, TCGReg m) 1304d74b86edSRichard Henderson{ 1305d74b86edSRichard Henderson tcg_out32(s, insn | (vece << 18) | (q << 6) | 1306d74b86edSRichard Henderson encode_vd(d) | encode_vm(m)); 1307d74b86edSRichard Henderson} 1308d74b86edSRichard Henderson 13092df2a8cfSRichard Hendersonstatic void tcg_out_vreg3(TCGContext *s, ARMInsn insn, int q, int vece, 13102df2a8cfSRichard Henderson TCGReg d, TCGReg n, TCGReg m) 13112df2a8cfSRichard Henderson{ 13122df2a8cfSRichard Henderson tcg_out32(s, insn | (vece << 20) | (q << 6) | 13132df2a8cfSRichard Henderson encode_vd(d) | encode_vn(n) | encode_vm(m)); 13142df2a8cfSRichard Henderson} 13152df2a8cfSRichard Henderson 1316213e8d84SRichard Hendersonstatic void tcg_out_vmovi(TCGContext *s, TCGReg rd, 1317213e8d84SRichard Henderson int q, int op, int cmode, uint8_t imm8) 1318213e8d84SRichard Henderson{ 1319213e8d84SRichard Henderson tcg_out32(s, INSN_VMOVI | encode_vd(rd) | (q << 6) | (op << 5) 1320213e8d84SRichard Henderson | (cmode << 8) | extract32(imm8, 0, 4) 1321213e8d84SRichard Henderson | (extract32(imm8, 4, 3) << 16) 1322213e8d84SRichard Henderson | (extract32(imm8, 7, 1) << 24)); 1323213e8d84SRichard Henderson} 1324213e8d84SRichard Henderson 1325d4c4e9c5SRichard Hendersonstatic void tcg_out_vshifti(TCGContext *s, ARMInsn insn, int q, 1326d4c4e9c5SRichard Henderson TCGReg rd, TCGReg rm, int l_imm6) 1327d4c4e9c5SRichard Henderson{ 1328d4c4e9c5SRichard Henderson tcg_out32(s, insn | (q << 6) | encode_vd(rd) | encode_vm(rm) | 1329d4c4e9c5SRichard Henderson (extract32(l_imm6, 6, 1) << 7) | 1330d4c4e9c5SRichard Henderson (extract32(l_imm6, 0, 6) << 16)); 1331d4c4e9c5SRichard Henderson} 1332d4c4e9c5SRichard Henderson 13336e49fad2SRichard Hendersonstatic void tcg_out_vldst(TCGContext *s, ARMInsn insn, 13346e49fad2SRichard Henderson TCGReg rd, TCGReg rn, int offset) 13356e49fad2SRichard Henderson{ 13366e49fad2SRichard Henderson if (offset != 0) { 13376e49fad2SRichard Henderson if (check_fit_imm(offset) || check_fit_imm(-offset)) { 13386e49fad2SRichard Henderson tcg_out_dat_rIN(s, COND_AL, ARITH_ADD, ARITH_SUB, 13396e49fad2SRichard Henderson TCG_REG_TMP, rn, offset, true); 13406e49fad2SRichard Henderson } else { 13416e49fad2SRichard Henderson tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_TMP, offset); 13426e49fad2SRichard Henderson tcg_out_dat_reg(s, COND_AL, ARITH_ADD, 13436e49fad2SRichard Henderson TCG_REG_TMP, TCG_REG_TMP, rn, 0); 13446e49fad2SRichard Henderson } 13456e49fad2SRichard Henderson rn = TCG_REG_TMP; 13466e49fad2SRichard Henderson } 13476e49fad2SRichard Henderson tcg_out32(s, insn | (rn << 16) | encode_vd(rd) | 0xf); 13486e49fad2SRichard Henderson} 13496e49fad2SRichard Henderson 13501df6d611SRichard Hendersontypedef struct { 13511df6d611SRichard Henderson ARMCond cond; 13521df6d611SRichard Henderson TCGReg base; 13531df6d611SRichard Henderson int index; 13541df6d611SRichard Henderson bool index_scratch; 13553e3d9942SRichard Henderson TCGAtomAlign aa; 13561df6d611SRichard Henderson} HostAddress; 13571df6d611SRichard Henderson 13587b880107SRichard Hendersonbool tcg_target_has_memory_bswap(MemOp memop) 13597b880107SRichard Henderson{ 13607b880107SRichard Henderson return false; 13617b880107SRichard Henderson} 13627b880107SRichard Henderson 136374c17067SRichard Hendersonstatic TCGReg ldst_ra_gen(TCGContext *s, const TCGLabelQemuLdst *l, int arg) 1364139c1837SPaolo Bonzini{ 136574c17067SRichard Henderson /* We arrive at the slow path via "BLNE", so R14 contains l->raddr. */ 136674c17067SRichard Henderson return TCG_REG_R14; 1367139c1837SPaolo Bonzini} 136874c17067SRichard Henderson 136974c17067SRichard Hendersonstatic const TCGLdstHelperParam ldst_helper_param = { 137074c17067SRichard Henderson .ra_gen = ldst_ra_gen, 137174c17067SRichard Henderson .ntmp = 1, 137274c17067SRichard Henderson .tmp = { TCG_REG_TMP }, 137374c17067SRichard Henderson}; 1374139c1837SPaolo Bonzini 1375139c1837SPaolo Bonzinistatic bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) 1376139c1837SPaolo Bonzini{ 137774c17067SRichard Henderson MemOp opc = get_memop(lb->oi); 1378139c1837SPaolo Bonzini 137969478b8bSRichard Henderson if (!reloc_pc24(lb->label_ptr[0], tcg_splitwx_to_rx(s->code_ptr))) { 1380139c1837SPaolo Bonzini return false; 1381139c1837SPaolo Bonzini } 1382139c1837SPaolo Bonzini 138374c17067SRichard Henderson tcg_out_ld_helper_args(s, lb, &ldst_helper_param); 1384cee44b03SRichard Henderson tcg_out_call_int(s, qemu_ld_helpers[opc & MO_SIZE]); 138574c17067SRichard Henderson tcg_out_ld_helper_ret(s, lb, false, &ldst_helper_param); 1386139c1837SPaolo Bonzini 1387139c1837SPaolo Bonzini tcg_out_goto(s, COND_AL, lb->raddr); 1388139c1837SPaolo Bonzini return true; 1389139c1837SPaolo Bonzini} 1390139c1837SPaolo Bonzini 1391139c1837SPaolo Bonzinistatic bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) 1392139c1837SPaolo Bonzini{ 139374c17067SRichard Henderson MemOp opc = get_memop(lb->oi); 1394139c1837SPaolo Bonzini 139569478b8bSRichard Henderson if (!reloc_pc24(lb->label_ptr[0], tcg_splitwx_to_rx(s->code_ptr))) { 1396139c1837SPaolo Bonzini return false; 1397139c1837SPaolo Bonzini } 1398139c1837SPaolo Bonzini 139974c17067SRichard Henderson tcg_out_st_helper_args(s, lb, &ldst_helper_param); 1400139c1837SPaolo Bonzini 1401139c1837SPaolo Bonzini /* Tail-call to the helper, which will return to the fast path. */ 1402843b8242SRichard Henderson tcg_out_goto(s, COND_AL, qemu_st_helpers[opc & MO_SIZE]); 1403139c1837SPaolo Bonzini return true; 1404139c1837SPaolo Bonzini} 1405139c1837SPaolo Bonzini 1406d0a9bb5eSRichard Henderson/* We expect to use an 9-bit sign-magnitude negative offset from ENV. */ 1407d0a9bb5eSRichard Henderson#define MIN_TLB_MASK_TABLE_OFS -256 1408d0a9bb5eSRichard Henderson 14097131d3cfSRichard Hendersonstatic TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h, 14107131d3cfSRichard Henderson TCGReg addrlo, TCGReg addrhi, 14117131d3cfSRichard Henderson MemOpIdx oi, bool is_ld) 14127131d3cfSRichard Henderson{ 14137131d3cfSRichard Henderson TCGLabelQemuLdst *ldst = NULL; 14147131d3cfSRichard Henderson MemOp opc = get_memop(oi); 14153e3d9942SRichard Henderson unsigned a_mask; 14163e3d9942SRichard Henderson 14172c53bdf1SRichard Henderson if (tcg_use_softmmu) { 14183e3d9942SRichard Henderson *h = (HostAddress){ 14193e3d9942SRichard Henderson .cond = COND_AL, 14203e3d9942SRichard Henderson .base = addrlo, 14213e3d9942SRichard Henderson .index = TCG_REG_R1, 14223e3d9942SRichard Henderson .index_scratch = true, 14233e3d9942SRichard Henderson }; 14242c53bdf1SRichard Henderson } else { 14253e3d9942SRichard Henderson *h = (HostAddress){ 14263e3d9942SRichard Henderson .cond = COND_AL, 14273e3d9942SRichard Henderson .base = addrlo, 14283e3d9942SRichard Henderson .index = guest_base ? TCG_REG_GUEST_BASE : -1, 14293e3d9942SRichard Henderson .index_scratch = false, 14303e3d9942SRichard Henderson }; 14312c53bdf1SRichard Henderson } 14323e3d9942SRichard Henderson 14333e3d9942SRichard Henderson h->aa = atom_and_align_for_opc(s, opc, MO_ATOM_IFALIGN, false); 14343e3d9942SRichard Henderson a_mask = (1 << h->aa.align) - 1; 14357131d3cfSRichard Henderson 14362c53bdf1SRichard Henderson if (tcg_use_softmmu) { 14377131d3cfSRichard Henderson int mem_index = get_mmuidx(oi); 14387131d3cfSRichard Henderson int cmp_off = is_ld ? offsetof(CPUTLBEntry, addr_read) 14397131d3cfSRichard Henderson : offsetof(CPUTLBEntry, addr_write); 1440d0a9bb5eSRichard Henderson int fast_off = tlb_mask_table_ofs(s, mem_index); 14417131d3cfSRichard Henderson unsigned s_mask = (1 << (opc & MO_SIZE)) - 1; 14427131d3cfSRichard Henderson TCGReg t_addr; 14437131d3cfSRichard Henderson 14447131d3cfSRichard Henderson ldst = new_ldst_label(s); 14457131d3cfSRichard Henderson ldst->is_ld = is_ld; 14467131d3cfSRichard Henderson ldst->oi = oi; 14477131d3cfSRichard Henderson ldst->addrlo_reg = addrlo; 14487131d3cfSRichard Henderson ldst->addrhi_reg = addrhi; 14497131d3cfSRichard Henderson 1450623912ccSAnton Johansson /* Load cpu->neg.tlb.f[mmu_idx].{mask,table} into {r0,r1}. */ 14517131d3cfSRichard Henderson QEMU_BUILD_BUG_ON(offsetof(CPUTLBDescFast, mask) != 0); 14527131d3cfSRichard Henderson QEMU_BUILD_BUG_ON(offsetof(CPUTLBDescFast, table) != 4); 14537131d3cfSRichard Henderson tcg_out_ldrd_8(s, COND_AL, TCG_REG_R0, TCG_AREG0, fast_off); 14547131d3cfSRichard Henderson 14557131d3cfSRichard Henderson /* Extract the tlb index from the address into R0. */ 14567131d3cfSRichard Henderson tcg_out_dat_reg(s, COND_AL, ARITH_AND, TCG_REG_R0, TCG_REG_R0, addrlo, 1457aece72b7SRichard Henderson SHIFT_IMM_LSR(s->page_bits - CPU_TLB_ENTRY_BITS)); 14587131d3cfSRichard Henderson 14597131d3cfSRichard Henderson /* 14607131d3cfSRichard Henderson * Add the tlb_table pointer, creating the CPUTLBEntry address in R1. 14617131d3cfSRichard Henderson * Load the tlb comparator into R2/R3 and the fast path addend into R1. 14627131d3cfSRichard Henderson */ 1463238f4380SRichard Henderson QEMU_BUILD_BUG_ON(HOST_BIG_ENDIAN); 14647131d3cfSRichard Henderson if (cmp_off == 0) { 146503a2ecdaSRichard Henderson if (s->addr_type == TCG_TYPE_I32) { 14662c53bdf1SRichard Henderson tcg_out_ld32_rwb(s, COND_AL, TCG_REG_R2, 14672c53bdf1SRichard Henderson TCG_REG_R1, TCG_REG_R0); 146803a2ecdaSRichard Henderson } else { 14692c53bdf1SRichard Henderson tcg_out_ldrd_rwb(s, COND_AL, TCG_REG_R2, 14702c53bdf1SRichard Henderson TCG_REG_R1, TCG_REG_R0); 14717131d3cfSRichard Henderson } 14727131d3cfSRichard Henderson } else { 14737131d3cfSRichard Henderson tcg_out_dat_reg(s, COND_AL, ARITH_ADD, 14747131d3cfSRichard Henderson TCG_REG_R1, TCG_REG_R1, TCG_REG_R0, 0); 147503a2ecdaSRichard Henderson if (s->addr_type == TCG_TYPE_I32) { 14767131d3cfSRichard Henderson tcg_out_ld32_12(s, COND_AL, TCG_REG_R2, TCG_REG_R1, cmp_off); 147703a2ecdaSRichard Henderson } else { 147803a2ecdaSRichard Henderson tcg_out_ldrd_8(s, COND_AL, TCG_REG_R2, TCG_REG_R1, cmp_off); 14797131d3cfSRichard Henderson } 14807131d3cfSRichard Henderson } 14817131d3cfSRichard Henderson 14827131d3cfSRichard Henderson /* Load the tlb addend. */ 14837131d3cfSRichard Henderson tcg_out_ld32_12(s, COND_AL, TCG_REG_R1, TCG_REG_R1, 14847131d3cfSRichard Henderson offsetof(CPUTLBEntry, addend)); 14857131d3cfSRichard Henderson 14867131d3cfSRichard Henderson /* 14877131d3cfSRichard Henderson * Check alignment, check comparators. 14887131d3cfSRichard Henderson * Do this in 2-4 insns. Use MOVW for v7, if possible, 14897131d3cfSRichard Henderson * to reduce the number of sequential conditional instructions. 14907131d3cfSRichard Henderson * Almost all guests have at least 4k pages, which means that we need 14917131d3cfSRichard Henderson * to clear at least 9 bits even for an 8-byte memory, which means it 14927131d3cfSRichard Henderson * isn't worth checking for an immediate operand for BIC. 14937131d3cfSRichard Henderson * 14947131d3cfSRichard Henderson * For unaligned accesses, test the page of the last unit of alignment. 14957131d3cfSRichard Henderson * This leaves the least significant alignment bits unchanged, and of 14967131d3cfSRichard Henderson * course must be zero. 14977131d3cfSRichard Henderson */ 14987131d3cfSRichard Henderson t_addr = addrlo; 14997131d3cfSRichard Henderson if (a_mask < s_mask) { 15007131d3cfSRichard Henderson t_addr = TCG_REG_R0; 15017131d3cfSRichard Henderson tcg_out_dat_imm(s, COND_AL, ARITH_ADD, t_addr, 15027131d3cfSRichard Henderson addrlo, s_mask - a_mask); 15037131d3cfSRichard Henderson } 1504aece72b7SRichard Henderson if (use_armv7_instructions && s->page_bits <= 16) { 1505aece72b7SRichard Henderson tcg_out_movi32(s, COND_AL, TCG_REG_TMP, ~(s->page_mask | a_mask)); 15067131d3cfSRichard Henderson tcg_out_dat_reg(s, COND_AL, ARITH_BIC, TCG_REG_TMP, 15077131d3cfSRichard Henderson t_addr, TCG_REG_TMP, 0); 15082c53bdf1SRichard Henderson tcg_out_dat_reg(s, COND_AL, ARITH_CMP, 0, 15092c53bdf1SRichard Henderson TCG_REG_R2, TCG_REG_TMP, 0); 15107131d3cfSRichard Henderson } else { 15117131d3cfSRichard Henderson if (a_mask) { 15127131d3cfSRichard Henderson tcg_debug_assert(a_mask <= 0xff); 15137131d3cfSRichard Henderson tcg_out_dat_imm(s, COND_AL, ARITH_TST, 0, addrlo, a_mask); 15147131d3cfSRichard Henderson } 15157131d3cfSRichard Henderson tcg_out_dat_reg(s, COND_AL, ARITH_MOV, TCG_REG_TMP, 0, t_addr, 1516aece72b7SRichard Henderson SHIFT_IMM_LSR(s->page_bits)); 15177131d3cfSRichard Henderson tcg_out_dat_reg(s, (a_mask ? COND_EQ : COND_AL), ARITH_CMP, 15187131d3cfSRichard Henderson 0, TCG_REG_R2, TCG_REG_TMP, 1519aece72b7SRichard Henderson SHIFT_IMM_LSL(s->page_bits)); 15207131d3cfSRichard Henderson } 15217131d3cfSRichard Henderson 152203a2ecdaSRichard Henderson if (s->addr_type != TCG_TYPE_I32) { 15237131d3cfSRichard Henderson tcg_out_dat_reg(s, COND_EQ, ARITH_CMP, 0, TCG_REG_R3, addrhi, 0); 15247131d3cfSRichard Henderson } 15252c53bdf1SRichard Henderson } else if (a_mask) { 15267131d3cfSRichard Henderson ldst = new_ldst_label(s); 15277131d3cfSRichard Henderson ldst->is_ld = is_ld; 15287131d3cfSRichard Henderson ldst->oi = oi; 15297131d3cfSRichard Henderson ldst->addrlo_reg = addrlo; 15307131d3cfSRichard Henderson ldst->addrhi_reg = addrhi; 15317131d3cfSRichard Henderson 15323e3d9942SRichard Henderson /* We are expecting alignment to max out at 7 */ 15337131d3cfSRichard Henderson tcg_debug_assert(a_mask <= 0xff); 15347131d3cfSRichard Henderson /* tst addr, #mask */ 15357131d3cfSRichard Henderson tcg_out_dat_imm(s, COND_AL, ARITH_TST, 0, addrlo, a_mask); 15367131d3cfSRichard Henderson } 15377131d3cfSRichard Henderson 15387131d3cfSRichard Henderson return ldst; 15397131d3cfSRichard Henderson} 15407131d3cfSRichard Henderson 15411df6d611SRichard Hendersonstatic void tcg_out_qemu_ld_direct(TCGContext *s, MemOp opc, TCGReg datalo, 15421df6d611SRichard Henderson TCGReg datahi, HostAddress h) 1543139c1837SPaolo Bonzini{ 15441df6d611SRichard Henderson TCGReg base; 15451df6d611SRichard Henderson 1546843b8242SRichard Henderson /* Byte swapping is left to middle-end expansion. */ 1547843b8242SRichard Henderson tcg_debug_assert((opc & MO_BSWAP) == 0); 1548139c1837SPaolo Bonzini 1549139c1837SPaolo Bonzini switch (opc & MO_SSIZE) { 1550139c1837SPaolo Bonzini case MO_UB: 15511df6d611SRichard Henderson if (h.index < 0) { 15521df6d611SRichard Henderson tcg_out_ld8_12(s, h.cond, datalo, h.base, 0); 15531df6d611SRichard Henderson } else { 15541df6d611SRichard Henderson tcg_out_ld8_r(s, h.cond, datalo, h.base, h.index); 15551df6d611SRichard Henderson } 1556139c1837SPaolo Bonzini break; 1557139c1837SPaolo Bonzini case MO_SB: 15581df6d611SRichard Henderson if (h.index < 0) { 15591df6d611SRichard Henderson tcg_out_ld8s_8(s, h.cond, datalo, h.base, 0); 15601df6d611SRichard Henderson } else { 15611df6d611SRichard Henderson tcg_out_ld8s_r(s, h.cond, datalo, h.base, h.index); 15621df6d611SRichard Henderson } 1563139c1837SPaolo Bonzini break; 1564139c1837SPaolo Bonzini case MO_UW: 15651df6d611SRichard Henderson if (h.index < 0) { 15661df6d611SRichard Henderson tcg_out_ld16u_8(s, h.cond, datalo, h.base, 0); 15671df6d611SRichard Henderson } else { 15681df6d611SRichard Henderson tcg_out_ld16u_r(s, h.cond, datalo, h.base, h.index); 15691df6d611SRichard Henderson } 1570139c1837SPaolo Bonzini break; 1571139c1837SPaolo Bonzini case MO_SW: 15721df6d611SRichard Henderson if (h.index < 0) { 15731df6d611SRichard Henderson tcg_out_ld16s_8(s, h.cond, datalo, h.base, 0); 15741df6d611SRichard Henderson } else { 15751df6d611SRichard Henderson tcg_out_ld16s_r(s, h.cond, datalo, h.base, h.index); 15761df6d611SRichard Henderson } 1577139c1837SPaolo Bonzini break; 1578139c1837SPaolo Bonzini case MO_UL: 15791df6d611SRichard Henderson if (h.index < 0) { 15801df6d611SRichard Henderson tcg_out_ld32_12(s, h.cond, datalo, h.base, 0); 15811df6d611SRichard Henderson } else { 15821df6d611SRichard Henderson tcg_out_ld32_r(s, h.cond, datalo, h.base, h.index); 15831df6d611SRichard Henderson } 1584139c1837SPaolo Bonzini break; 1585fc313c64SFrédéric Pétrot case MO_UQ: 15861b18d1faSRichard Henderson /* We used pair allocation for datalo, so already should be aligned. */ 15871b18d1faSRichard Henderson tcg_debug_assert((datalo & 1) == 0); 15881b18d1faSRichard Henderson tcg_debug_assert(datahi == datalo + 1); 1589367d43d8SRichard Henderson /* LDRD requires alignment; double-check that. */ 1590*c5809eeeSRichard Henderson if (memop_alignment_bits(opc) >= MO_64) { 15911df6d611SRichard Henderson if (h.index < 0) { 15921df6d611SRichard Henderson tcg_out_ldrd_8(s, h.cond, datalo, h.base, 0); 15931df6d611SRichard Henderson break; 15941df6d611SRichard Henderson } 159576cff100SRichard Henderson /* 159676cff100SRichard Henderson * Rm (the second address op) must not overlap Rt or Rt + 1. 159776cff100SRichard Henderson * Since datalo is aligned, we can simplify the test via alignment. 159876cff100SRichard Henderson * Flip the two address arguments if that works. 159976cff100SRichard Henderson */ 16001df6d611SRichard Henderson if ((h.index & ~1) != datalo) { 16011df6d611SRichard Henderson tcg_out_ldrd_r(s, h.cond, datalo, h.base, h.index); 160276cff100SRichard Henderson break; 160376cff100SRichard Henderson } 16041df6d611SRichard Henderson if ((h.base & ~1) != datalo) { 16051df6d611SRichard Henderson tcg_out_ldrd_r(s, h.cond, datalo, h.index, h.base); 160676cff100SRichard Henderson break; 160776cff100SRichard Henderson } 160876cff100SRichard Henderson } 16091df6d611SRichard Henderson if (h.index < 0) { 16101df6d611SRichard Henderson base = h.base; 16111df6d611SRichard Henderson if (datalo == h.base) { 16121df6d611SRichard Henderson tcg_out_mov_reg(s, h.cond, TCG_REG_TMP, base); 16131df6d611SRichard Henderson base = TCG_REG_TMP; 16141df6d611SRichard Henderson } 16151df6d611SRichard Henderson } else if (h.index_scratch) { 16161df6d611SRichard Henderson tcg_out_ld32_rwb(s, h.cond, datalo, h.index, h.base); 16171df6d611SRichard Henderson tcg_out_ld32_12(s, h.cond, datahi, h.index, 4); 16181df6d611SRichard Henderson break; 1619139c1837SPaolo Bonzini } else { 16201df6d611SRichard Henderson tcg_out_dat_reg(s, h.cond, ARITH_ADD, TCG_REG_TMP, 16211df6d611SRichard Henderson h.base, h.index, SHIFT_IMM_LSL(0)); 16221df6d611SRichard Henderson base = TCG_REG_TMP; 1623139c1837SPaolo Bonzini } 16241df6d611SRichard Henderson tcg_out_ld32_12(s, h.cond, datalo, base, 0); 16251df6d611SRichard Henderson tcg_out_ld32_12(s, h.cond, datahi, base, 4); 1626139c1837SPaolo Bonzini break; 1627843b8242SRichard Henderson default: 1628843b8242SRichard Henderson g_assert_not_reached(); 1629139c1837SPaolo Bonzini } 1630139c1837SPaolo Bonzini} 1631139c1837SPaolo Bonzini 1632737fb471SRichard Hendersonstatic void tcg_out_qemu_ld(TCGContext *s, TCGReg datalo, TCGReg datahi, 1633737fb471SRichard Henderson TCGReg addrlo, TCGReg addrhi, 1634737fb471SRichard Henderson MemOpIdx oi, TCGType data_type) 1635139c1837SPaolo Bonzini{ 1636737fb471SRichard Henderson MemOp opc = get_memop(oi); 16377131d3cfSRichard Henderson TCGLabelQemuLdst *ldst; 16381df6d611SRichard Henderson HostAddress h; 1639139c1837SPaolo Bonzini 16407131d3cfSRichard Henderson ldst = prepare_host_addr(s, &h, addrlo, addrhi, oi, true); 16417131d3cfSRichard Henderson if (ldst) { 16427131d3cfSRichard Henderson ldst->type = data_type; 16437131d3cfSRichard Henderson ldst->datalo_reg = datalo; 16447131d3cfSRichard Henderson ldst->datahi_reg = datahi; 1645139c1837SPaolo Bonzini 1646737fb471SRichard Henderson /* 16477131d3cfSRichard Henderson * This a conditional BL only to load a pointer within this 16487131d3cfSRichard Henderson * opcode into LR for the slow path. We will not be using 16497131d3cfSRichard Henderson * the value for a tail call. 1650737fb471SRichard Henderson */ 16517131d3cfSRichard Henderson ldst->label_ptr[0] = s->code_ptr; 1652326b9669SRichard Henderson tcg_out_bl_imm(s, COND_NE, 0); 1653139c1837SPaolo Bonzini 16541df6d611SRichard Henderson tcg_out_qemu_ld_direct(s, opc, datalo, datahi, h); 16557131d3cfSRichard Henderson ldst->raddr = tcg_splitwx_to_rx(s->code_ptr); 16567131d3cfSRichard Henderson } else { 16571df6d611SRichard Henderson tcg_out_qemu_ld_direct(s, opc, datalo, datahi, h); 16587131d3cfSRichard Henderson } 1659139c1837SPaolo Bonzini} 1660139c1837SPaolo Bonzini 16615f726ebcSRichard Hendersonstatic void tcg_out_qemu_st_direct(TCGContext *s, MemOp opc, TCGReg datalo, 16621df6d611SRichard Henderson TCGReg datahi, HostAddress h) 1663139c1837SPaolo Bonzini{ 1664843b8242SRichard Henderson /* Byte swapping is left to middle-end expansion. */ 1665843b8242SRichard Henderson tcg_debug_assert((opc & MO_BSWAP) == 0); 1666139c1837SPaolo Bonzini 1667139c1837SPaolo Bonzini switch (opc & MO_SIZE) { 1668139c1837SPaolo Bonzini case MO_8: 16691df6d611SRichard Henderson if (h.index < 0) { 16701df6d611SRichard Henderson tcg_out_st8_12(s, h.cond, datalo, h.base, 0); 16711df6d611SRichard Henderson } else { 16721df6d611SRichard Henderson tcg_out_st8_r(s, h.cond, datalo, h.base, h.index); 16731df6d611SRichard Henderson } 1674139c1837SPaolo Bonzini break; 1675139c1837SPaolo Bonzini case MO_16: 16761df6d611SRichard Henderson if (h.index < 0) { 16771df6d611SRichard Henderson tcg_out_st16_8(s, h.cond, datalo, h.base, 0); 16781df6d611SRichard Henderson } else { 16791df6d611SRichard Henderson tcg_out_st16_r(s, h.cond, datalo, h.base, h.index); 16801df6d611SRichard Henderson } 1681139c1837SPaolo Bonzini break; 1682139c1837SPaolo Bonzini case MO_32: 16831df6d611SRichard Henderson if (h.index < 0) { 16841df6d611SRichard Henderson tcg_out_st32_12(s, h.cond, datalo, h.base, 0); 16851df6d611SRichard Henderson } else { 16861df6d611SRichard Henderson tcg_out_st32_r(s, h.cond, datalo, h.base, h.index); 16871df6d611SRichard Henderson } 1688139c1837SPaolo Bonzini break; 1689139c1837SPaolo Bonzini case MO_64: 16901b18d1faSRichard Henderson /* We used pair allocation for datalo, so already should be aligned. */ 16911b18d1faSRichard Henderson tcg_debug_assert((datalo & 1) == 0); 16921b18d1faSRichard Henderson tcg_debug_assert(datahi == datalo + 1); 1693367d43d8SRichard Henderson /* STRD requires alignment; double-check that. */ 1694*c5809eeeSRichard Henderson if (memop_alignment_bits(opc) >= MO_64) { 16951df6d611SRichard Henderson if (h.index < 0) { 16961df6d611SRichard Henderson tcg_out_strd_8(s, h.cond, datalo, h.base, 0); 1697139c1837SPaolo Bonzini } else { 16981df6d611SRichard Henderson tcg_out_strd_r(s, h.cond, datalo, h.base, h.index); 16991df6d611SRichard Henderson } 17009f6523e8SJoseph Burt } else if (h.index < 0) { 17019f6523e8SJoseph Burt tcg_out_st32_12(s, h.cond, datalo, h.base, 0); 17029f6523e8SJoseph Burt tcg_out_st32_12(s, h.cond, datahi, h.base, 4); 17031df6d611SRichard Henderson } else if (h.index_scratch) { 17041df6d611SRichard Henderson tcg_out_st32_rwb(s, h.cond, datalo, h.index, h.base); 17051df6d611SRichard Henderson tcg_out_st32_12(s, h.cond, datahi, h.index, 4); 17061df6d611SRichard Henderson } else { 17071df6d611SRichard Henderson tcg_out_dat_reg(s, h.cond, ARITH_ADD, TCG_REG_TMP, 17081df6d611SRichard Henderson h.base, h.index, SHIFT_IMM_LSL(0)); 17091df6d611SRichard Henderson tcg_out_st32_12(s, h.cond, datalo, TCG_REG_TMP, 0); 17101df6d611SRichard Henderson tcg_out_st32_12(s, h.cond, datahi, TCG_REG_TMP, 4); 1711139c1837SPaolo Bonzini } 1712139c1837SPaolo Bonzini break; 1713843b8242SRichard Henderson default: 1714843b8242SRichard Henderson g_assert_not_reached(); 1715139c1837SPaolo Bonzini } 1716139c1837SPaolo Bonzini} 1717139c1837SPaolo Bonzini 1718737fb471SRichard Hendersonstatic void tcg_out_qemu_st(TCGContext *s, TCGReg datalo, TCGReg datahi, 1719737fb471SRichard Henderson TCGReg addrlo, TCGReg addrhi, 1720737fb471SRichard Henderson MemOpIdx oi, TCGType data_type) 1721139c1837SPaolo Bonzini{ 1722737fb471SRichard Henderson MemOp opc = get_memop(oi); 17237131d3cfSRichard Henderson TCGLabelQemuLdst *ldst; 17241df6d611SRichard Henderson HostAddress h; 1725139c1837SPaolo Bonzini 17267131d3cfSRichard Henderson ldst = prepare_host_addr(s, &h, addrlo, addrhi, oi, false); 17277131d3cfSRichard Henderson if (ldst) { 17287131d3cfSRichard Henderson ldst->type = data_type; 17297131d3cfSRichard Henderson ldst->datalo_reg = datalo; 17307131d3cfSRichard Henderson ldst->datahi_reg = datahi; 17317131d3cfSRichard Henderson 17321df6d611SRichard Henderson h.cond = COND_EQ; 17331df6d611SRichard Henderson tcg_out_qemu_st_direct(s, opc, datalo, datahi, h); 1734139c1837SPaolo Bonzini 17357131d3cfSRichard Henderson /* The conditional call is last, as we're going to return here. */ 17367131d3cfSRichard Henderson ldst->label_ptr[0] = s->code_ptr; 1737326b9669SRichard Henderson tcg_out_bl_imm(s, COND_NE, 0); 17387131d3cfSRichard Henderson ldst->raddr = tcg_splitwx_to_rx(s->code_ptr); 17397131d3cfSRichard Henderson } else { 17401df6d611SRichard Henderson tcg_out_qemu_st_direct(s, opc, datalo, datahi, h); 17417131d3cfSRichard Henderson } 1742139c1837SPaolo Bonzini} 1743139c1837SPaolo Bonzini 1744139c1837SPaolo Bonzinistatic void tcg_out_epilogue(TCGContext *s); 1745139c1837SPaolo Bonzini 1746b55a8d9dSRichard Hendersonstatic void tcg_out_exit_tb(TCGContext *s, uintptr_t arg) 1747b55a8d9dSRichard Henderson{ 1748b55a8d9dSRichard Henderson tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R0, arg); 1749b55a8d9dSRichard Henderson tcg_out_epilogue(s); 1750b55a8d9dSRichard Henderson} 1751b55a8d9dSRichard Henderson 1752cf7d6b8eSRichard Hendersonstatic void tcg_out_goto_tb(TCGContext *s, int which) 1753cf7d6b8eSRichard Henderson{ 175479ffece4SRichard Henderson uintptr_t i_addr; 175579ffece4SRichard Henderson intptr_t i_disp; 1756cf7d6b8eSRichard Henderson 175779ffece4SRichard Henderson /* Direct branch will be patched by tb_target_set_jmp_target. */ 175879ffece4SRichard Henderson set_jmp_insn_offset(s, which); 175979ffece4SRichard Henderson tcg_out32(s, INSN_NOP); 176079ffece4SRichard Henderson 176179ffece4SRichard Henderson /* When branch is out of range, fall through to indirect. */ 176279ffece4SRichard Henderson i_addr = get_jmp_target_addr(s, which); 176379ffece4SRichard Henderson i_disp = tcg_pcrel_diff(s, (void *)i_addr) - 8; 176479ffece4SRichard Henderson tcg_debug_assert(i_disp < 0); 176579ffece4SRichard Henderson if (i_disp >= -0xfff) { 176679ffece4SRichard Henderson tcg_out_ld32_12(s, COND_AL, TCG_REG_PC, TCG_REG_PC, i_disp); 176779ffece4SRichard Henderson } else { 1768cf7d6b8eSRichard Henderson /* 1769cf7d6b8eSRichard Henderson * The TB is close, but outside the 12 bits addressable by 1770cf7d6b8eSRichard Henderson * the load. We can extend this to 20 bits with a sub of a 177179ffece4SRichard Henderson * shifted immediate from pc. 1772cf7d6b8eSRichard Henderson */ 177379ffece4SRichard Henderson int h = -i_disp; 1774e41f1825SRichard Henderson int l = -(h & 0xfff); 177579ffece4SRichard Henderson 1776e41f1825SRichard Henderson h = encode_imm_nofail(h + l); 177779ffece4SRichard Henderson tcg_out_dat_imm(s, COND_AL, ARITH_SUB, TCG_REG_R0, TCG_REG_PC, h); 177879ffece4SRichard Henderson tcg_out_ld32_12(s, COND_AL, TCG_REG_PC, TCG_REG_R0, l); 1779cf7d6b8eSRichard Henderson } 1780cf7d6b8eSRichard Henderson set_jmp_reset_offset(s, which); 1781cf7d6b8eSRichard Henderson} 1782cf7d6b8eSRichard Henderson 178390c0fee3SRichard Hendersonvoid tb_target_set_jmp_target(const TranslationBlock *tb, int n, 178490c0fee3SRichard Henderson uintptr_t jmp_rx, uintptr_t jmp_rw) 178590c0fee3SRichard Henderson{ 178679ffece4SRichard Henderson uintptr_t addr = tb->jmp_target_addr[n]; 178779ffece4SRichard Henderson ptrdiff_t offset = addr - (jmp_rx + 8); 178879ffece4SRichard Henderson tcg_insn_unit insn; 178979ffece4SRichard Henderson 179079ffece4SRichard Henderson /* Either directly branch, or fall through to indirect branch. */ 179179ffece4SRichard Henderson if (offset == sextract64(offset, 0, 26)) { 179279ffece4SRichard Henderson /* B <addr> */ 179379ffece4SRichard Henderson insn = deposit32((COND_AL << 28) | INSN_B, 0, 24, offset >> 2); 179479ffece4SRichard Henderson } else { 179579ffece4SRichard Henderson insn = INSN_NOP; 179679ffece4SRichard Henderson } 179779ffece4SRichard Henderson 179879ffece4SRichard Henderson qatomic_set((uint32_t *)jmp_rw, insn); 179979ffece4SRichard Henderson flush_idcache_range(jmp_rx, jmp_rw, 4); 180090c0fee3SRichard Henderson} 180190c0fee3SRichard Henderson 18025f726ebcSRichard Hendersonstatic void tcg_out_op(TCGContext *s, TCGOpcode opc, 1803c372565dSJose R. Ziviani const TCGArg args[TCG_MAX_OP_ARGS], 1804c372565dSJose R. Ziviani const int const_args[TCG_MAX_OP_ARGS]) 1805139c1837SPaolo Bonzini{ 1806139c1837SPaolo Bonzini TCGArg a0, a1, a2, a3, a4, a5; 1807139c1837SPaolo Bonzini int c; 1808139c1837SPaolo Bonzini 1809139c1837SPaolo Bonzini switch (opc) { 1810139c1837SPaolo Bonzini case INDEX_op_goto_ptr: 1811326b9669SRichard Henderson tcg_out_b_reg(s, COND_AL, args[0]); 1812139c1837SPaolo Bonzini break; 1813139c1837SPaolo Bonzini case INDEX_op_br: 1814139c1837SPaolo Bonzini tcg_out_goto_label(s, COND_AL, arg_label(args[0])); 1815139c1837SPaolo Bonzini break; 1816139c1837SPaolo Bonzini 1817139c1837SPaolo Bonzini case INDEX_op_ld8u_i32: 1818139c1837SPaolo Bonzini tcg_out_ld8u(s, COND_AL, args[0], args[1], args[2]); 1819139c1837SPaolo Bonzini break; 1820139c1837SPaolo Bonzini case INDEX_op_ld8s_i32: 1821139c1837SPaolo Bonzini tcg_out_ld8s(s, COND_AL, args[0], args[1], args[2]); 1822139c1837SPaolo Bonzini break; 1823139c1837SPaolo Bonzini case INDEX_op_ld16u_i32: 1824139c1837SPaolo Bonzini tcg_out_ld16u(s, COND_AL, args[0], args[1], args[2]); 1825139c1837SPaolo Bonzini break; 1826139c1837SPaolo Bonzini case INDEX_op_ld16s_i32: 1827139c1837SPaolo Bonzini tcg_out_ld16s(s, COND_AL, args[0], args[1], args[2]); 1828139c1837SPaolo Bonzini break; 1829139c1837SPaolo Bonzini case INDEX_op_ld_i32: 1830139c1837SPaolo Bonzini tcg_out_ld32u(s, COND_AL, args[0], args[1], args[2]); 1831139c1837SPaolo Bonzini break; 1832139c1837SPaolo Bonzini case INDEX_op_st8_i32: 1833139c1837SPaolo Bonzini tcg_out_st8(s, COND_AL, args[0], args[1], args[2]); 1834139c1837SPaolo Bonzini break; 1835139c1837SPaolo Bonzini case INDEX_op_st16_i32: 1836139c1837SPaolo Bonzini tcg_out_st16(s, COND_AL, args[0], args[1], args[2]); 1837139c1837SPaolo Bonzini break; 1838139c1837SPaolo Bonzini case INDEX_op_st_i32: 1839139c1837SPaolo Bonzini tcg_out_st32(s, COND_AL, args[0], args[1], args[2]); 1840139c1837SPaolo Bonzini break; 1841139c1837SPaolo Bonzini 1842139c1837SPaolo Bonzini case INDEX_op_movcond_i32: 1843139c1837SPaolo Bonzini /* Constraints mean that v2 is always in the same register as dest, 1844139c1837SPaolo Bonzini * so we only need to do "if condition passed, move v1 to dest". 1845139c1837SPaolo Bonzini */ 1846e67ec08cSRichard Henderson c = tcg_out_cmp(s, args[5], args[1], args[2], const_args[2]); 1847e67ec08cSRichard Henderson tcg_out_dat_rIK(s, tcg_cond_to_arm_cond[c], ARITH_MOV, 1848139c1837SPaolo Bonzini ARITH_MVN, args[0], 0, args[3], const_args[3]); 1849139c1837SPaolo Bonzini break; 1850139c1837SPaolo Bonzini case INDEX_op_add_i32: 1851139c1837SPaolo Bonzini tcg_out_dat_rIN(s, COND_AL, ARITH_ADD, ARITH_SUB, 1852139c1837SPaolo Bonzini args[0], args[1], args[2], const_args[2]); 1853139c1837SPaolo Bonzini break; 1854139c1837SPaolo Bonzini case INDEX_op_sub_i32: 1855139c1837SPaolo Bonzini if (const_args[1]) { 1856139c1837SPaolo Bonzini if (const_args[2]) { 1857139c1837SPaolo Bonzini tcg_out_movi32(s, COND_AL, args[0], args[1] - args[2]); 1858139c1837SPaolo Bonzini } else { 1859139c1837SPaolo Bonzini tcg_out_dat_rI(s, COND_AL, ARITH_RSB, 1860139c1837SPaolo Bonzini args[0], args[2], args[1], 1); 1861139c1837SPaolo Bonzini } 1862139c1837SPaolo Bonzini } else { 1863139c1837SPaolo Bonzini tcg_out_dat_rIN(s, COND_AL, ARITH_SUB, ARITH_ADD, 1864139c1837SPaolo Bonzini args[0], args[1], args[2], const_args[2]); 1865139c1837SPaolo Bonzini } 1866139c1837SPaolo Bonzini break; 1867139c1837SPaolo Bonzini case INDEX_op_and_i32: 1868139c1837SPaolo Bonzini tcg_out_dat_rIK(s, COND_AL, ARITH_AND, ARITH_BIC, 1869139c1837SPaolo Bonzini args[0], args[1], args[2], const_args[2]); 1870139c1837SPaolo Bonzini break; 1871139c1837SPaolo Bonzini case INDEX_op_andc_i32: 1872139c1837SPaolo Bonzini tcg_out_dat_rIK(s, COND_AL, ARITH_BIC, ARITH_AND, 1873139c1837SPaolo Bonzini args[0], args[1], args[2], const_args[2]); 1874139c1837SPaolo Bonzini break; 1875139c1837SPaolo Bonzini case INDEX_op_or_i32: 1876139c1837SPaolo Bonzini c = ARITH_ORR; 1877139c1837SPaolo Bonzini goto gen_arith; 1878139c1837SPaolo Bonzini case INDEX_op_xor_i32: 1879139c1837SPaolo Bonzini c = ARITH_EOR; 1880139c1837SPaolo Bonzini /* Fall through. */ 1881139c1837SPaolo Bonzini gen_arith: 1882139c1837SPaolo Bonzini tcg_out_dat_rI(s, COND_AL, c, args[0], args[1], args[2], const_args[2]); 1883139c1837SPaolo Bonzini break; 1884139c1837SPaolo Bonzini case INDEX_op_add2_i32: 1885139c1837SPaolo Bonzini a0 = args[0], a1 = args[1], a2 = args[2]; 1886139c1837SPaolo Bonzini a3 = args[3], a4 = args[4], a5 = args[5]; 1887139c1837SPaolo Bonzini if (a0 == a3 || (a0 == a5 && !const_args[5])) { 1888139c1837SPaolo Bonzini a0 = TCG_REG_TMP; 1889139c1837SPaolo Bonzini } 1890139c1837SPaolo Bonzini tcg_out_dat_rIN(s, COND_AL, ARITH_ADD | TO_CPSR, ARITH_SUB | TO_CPSR, 1891139c1837SPaolo Bonzini a0, a2, a4, const_args[4]); 1892139c1837SPaolo Bonzini tcg_out_dat_rIK(s, COND_AL, ARITH_ADC, ARITH_SBC, 1893139c1837SPaolo Bonzini a1, a3, a5, const_args[5]); 1894139c1837SPaolo Bonzini tcg_out_mov_reg(s, COND_AL, args[0], a0); 1895139c1837SPaolo Bonzini break; 1896139c1837SPaolo Bonzini case INDEX_op_sub2_i32: 1897139c1837SPaolo Bonzini a0 = args[0], a1 = args[1], a2 = args[2]; 1898139c1837SPaolo Bonzini a3 = args[3], a4 = args[4], a5 = args[5]; 1899139c1837SPaolo Bonzini if ((a0 == a3 && !const_args[3]) || (a0 == a5 && !const_args[5])) { 1900139c1837SPaolo Bonzini a0 = TCG_REG_TMP; 1901139c1837SPaolo Bonzini } 1902139c1837SPaolo Bonzini if (const_args[2]) { 1903139c1837SPaolo Bonzini if (const_args[4]) { 1904139c1837SPaolo Bonzini tcg_out_movi32(s, COND_AL, a0, a4); 1905139c1837SPaolo Bonzini a4 = a0; 1906139c1837SPaolo Bonzini } 1907139c1837SPaolo Bonzini tcg_out_dat_rI(s, COND_AL, ARITH_RSB | TO_CPSR, a0, a4, a2, 1); 1908139c1837SPaolo Bonzini } else { 1909139c1837SPaolo Bonzini tcg_out_dat_rIN(s, COND_AL, ARITH_SUB | TO_CPSR, 1910139c1837SPaolo Bonzini ARITH_ADD | TO_CPSR, a0, a2, a4, const_args[4]); 1911139c1837SPaolo Bonzini } 1912139c1837SPaolo Bonzini if (const_args[3]) { 1913139c1837SPaolo Bonzini if (const_args[5]) { 1914139c1837SPaolo Bonzini tcg_out_movi32(s, COND_AL, a1, a5); 1915139c1837SPaolo Bonzini a5 = a1; 1916139c1837SPaolo Bonzini } 1917139c1837SPaolo Bonzini tcg_out_dat_rI(s, COND_AL, ARITH_RSC, a1, a5, a3, 1); 1918139c1837SPaolo Bonzini } else { 1919139c1837SPaolo Bonzini tcg_out_dat_rIK(s, COND_AL, ARITH_SBC, ARITH_ADC, 1920139c1837SPaolo Bonzini a1, a3, a5, const_args[5]); 1921139c1837SPaolo Bonzini } 1922139c1837SPaolo Bonzini tcg_out_mov_reg(s, COND_AL, args[0], a0); 1923139c1837SPaolo Bonzini break; 1924139c1837SPaolo Bonzini case INDEX_op_neg_i32: 1925139c1837SPaolo Bonzini tcg_out_dat_imm(s, COND_AL, ARITH_RSB, args[0], args[1], 0); 1926139c1837SPaolo Bonzini break; 1927139c1837SPaolo Bonzini case INDEX_op_not_i32: 1928139c1837SPaolo Bonzini tcg_out_dat_reg(s, COND_AL, 1929139c1837SPaolo Bonzini ARITH_MVN, args[0], 0, args[1], SHIFT_IMM_LSL(0)); 1930139c1837SPaolo Bonzini break; 1931139c1837SPaolo Bonzini case INDEX_op_mul_i32: 1932139c1837SPaolo Bonzini tcg_out_mul32(s, COND_AL, args[0], args[1], args[2]); 1933139c1837SPaolo Bonzini break; 1934139c1837SPaolo Bonzini case INDEX_op_mulu2_i32: 1935139c1837SPaolo Bonzini tcg_out_umull32(s, COND_AL, args[0], args[1], args[2], args[3]); 1936139c1837SPaolo Bonzini break; 1937139c1837SPaolo Bonzini case INDEX_op_muls2_i32: 1938139c1837SPaolo Bonzini tcg_out_smull32(s, COND_AL, args[0], args[1], args[2], args[3]); 1939139c1837SPaolo Bonzini break; 1940139c1837SPaolo Bonzini /* XXX: Perhaps args[2] & 0x1f is wrong */ 1941139c1837SPaolo Bonzini case INDEX_op_shl_i32: 1942139c1837SPaolo Bonzini c = const_args[2] ? 1943139c1837SPaolo Bonzini SHIFT_IMM_LSL(args[2] & 0x1f) : SHIFT_REG_LSL(args[2]); 1944139c1837SPaolo Bonzini goto gen_shift32; 1945139c1837SPaolo Bonzini case INDEX_op_shr_i32: 1946139c1837SPaolo Bonzini c = const_args[2] ? (args[2] & 0x1f) ? SHIFT_IMM_LSR(args[2] & 0x1f) : 1947139c1837SPaolo Bonzini SHIFT_IMM_LSL(0) : SHIFT_REG_LSR(args[2]); 1948139c1837SPaolo Bonzini goto gen_shift32; 1949139c1837SPaolo Bonzini case INDEX_op_sar_i32: 1950139c1837SPaolo Bonzini c = const_args[2] ? (args[2] & 0x1f) ? SHIFT_IMM_ASR(args[2] & 0x1f) : 1951139c1837SPaolo Bonzini SHIFT_IMM_LSL(0) : SHIFT_REG_ASR(args[2]); 1952139c1837SPaolo Bonzini goto gen_shift32; 1953139c1837SPaolo Bonzini case INDEX_op_rotr_i32: 1954139c1837SPaolo Bonzini c = const_args[2] ? (args[2] & 0x1f) ? SHIFT_IMM_ROR(args[2] & 0x1f) : 1955139c1837SPaolo Bonzini SHIFT_IMM_LSL(0) : SHIFT_REG_ROR(args[2]); 1956139c1837SPaolo Bonzini /* Fall through. */ 1957139c1837SPaolo Bonzini gen_shift32: 1958139c1837SPaolo Bonzini tcg_out_dat_reg(s, COND_AL, ARITH_MOV, args[0], 0, args[1], c); 1959139c1837SPaolo Bonzini break; 1960139c1837SPaolo Bonzini 1961139c1837SPaolo Bonzini case INDEX_op_rotl_i32: 1962139c1837SPaolo Bonzini if (const_args[2]) { 1963139c1837SPaolo Bonzini tcg_out_dat_reg(s, COND_AL, ARITH_MOV, args[0], 0, args[1], 1964139c1837SPaolo Bonzini ((0x20 - args[2]) & 0x1f) ? 1965139c1837SPaolo Bonzini SHIFT_IMM_ROR((0x20 - args[2]) & 0x1f) : 1966139c1837SPaolo Bonzini SHIFT_IMM_LSL(0)); 1967139c1837SPaolo Bonzini } else { 1968139c1837SPaolo Bonzini tcg_out_dat_imm(s, COND_AL, ARITH_RSB, TCG_REG_TMP, args[2], 0x20); 1969139c1837SPaolo Bonzini tcg_out_dat_reg(s, COND_AL, ARITH_MOV, args[0], 0, args[1], 1970139c1837SPaolo Bonzini SHIFT_REG_ROR(TCG_REG_TMP)); 1971139c1837SPaolo Bonzini } 1972139c1837SPaolo Bonzini break; 1973139c1837SPaolo Bonzini 1974139c1837SPaolo Bonzini case INDEX_op_ctz_i32: 1975139c1837SPaolo Bonzini tcg_out_dat_reg(s, COND_AL, INSN_RBIT, TCG_REG_TMP, 0, args[1], 0); 1976139c1837SPaolo Bonzini a1 = TCG_REG_TMP; 1977139c1837SPaolo Bonzini goto do_clz; 1978139c1837SPaolo Bonzini 1979139c1837SPaolo Bonzini case INDEX_op_clz_i32: 1980139c1837SPaolo Bonzini a1 = args[1]; 1981139c1837SPaolo Bonzini do_clz: 1982139c1837SPaolo Bonzini a0 = args[0]; 1983139c1837SPaolo Bonzini a2 = args[2]; 1984139c1837SPaolo Bonzini c = const_args[2]; 1985139c1837SPaolo Bonzini if (c && a2 == 32) { 1986139c1837SPaolo Bonzini tcg_out_dat_reg(s, COND_AL, INSN_CLZ, a0, 0, a1, 0); 1987139c1837SPaolo Bonzini break; 1988139c1837SPaolo Bonzini } 1989139c1837SPaolo Bonzini tcg_out_dat_imm(s, COND_AL, ARITH_CMP, 0, a1, 0); 1990139c1837SPaolo Bonzini tcg_out_dat_reg(s, COND_NE, INSN_CLZ, a0, 0, a1, 0); 1991139c1837SPaolo Bonzini if (c || a0 != a2) { 1992139c1837SPaolo Bonzini tcg_out_dat_rIK(s, COND_EQ, ARITH_MOV, ARITH_MVN, a0, 0, a2, c); 1993139c1837SPaolo Bonzini } 1994139c1837SPaolo Bonzini break; 1995139c1837SPaolo Bonzini 1996139c1837SPaolo Bonzini case INDEX_op_brcond_i32: 1997e67ec08cSRichard Henderson c = tcg_out_cmp(s, args[2], args[0], args[1], const_args[1]); 1998e67ec08cSRichard Henderson tcg_out_goto_label(s, tcg_cond_to_arm_cond[c], arg_label(args[3])); 1999139c1837SPaolo Bonzini break; 2000139c1837SPaolo Bonzini case INDEX_op_setcond_i32: 2001e67ec08cSRichard Henderson c = tcg_out_cmp(s, args[3], args[1], args[2], const_args[2]); 2002e67ec08cSRichard Henderson tcg_out_dat_imm(s, tcg_cond_to_arm_cond[c], 2003139c1837SPaolo Bonzini ARITH_MOV, args[0], 0, 1); 2004e67ec08cSRichard Henderson tcg_out_dat_imm(s, tcg_cond_to_arm_cond[tcg_invert_cond(c)], 2005139c1837SPaolo Bonzini ARITH_MOV, args[0], 0, 0); 2006139c1837SPaolo Bonzini break; 2007fe06b897SRichard Henderson case INDEX_op_negsetcond_i32: 2008e67ec08cSRichard Henderson c = tcg_out_cmp(s, args[3], args[1], args[2], const_args[2]); 2009e67ec08cSRichard Henderson tcg_out_dat_imm(s, tcg_cond_to_arm_cond[c], 2010fe06b897SRichard Henderson ARITH_MVN, args[0], 0, 0); 2011e67ec08cSRichard Henderson tcg_out_dat_imm(s, tcg_cond_to_arm_cond[tcg_invert_cond(c)], 2012fe06b897SRichard Henderson ARITH_MOV, args[0], 0, 0); 2013fe06b897SRichard Henderson break; 2014139c1837SPaolo Bonzini 2015139c1837SPaolo Bonzini case INDEX_op_brcond2_i32: 2016139c1837SPaolo Bonzini c = tcg_out_cmp2(s, args, const_args); 2017139c1837SPaolo Bonzini tcg_out_goto_label(s, tcg_cond_to_arm_cond[c], arg_label(args[5])); 2018139c1837SPaolo Bonzini break; 2019139c1837SPaolo Bonzini case INDEX_op_setcond2_i32: 2020139c1837SPaolo Bonzini c = tcg_out_cmp2(s, args + 1, const_args + 1); 2021139c1837SPaolo Bonzini tcg_out_dat_imm(s, tcg_cond_to_arm_cond[c], ARITH_MOV, args[0], 0, 1); 2022139c1837SPaolo Bonzini tcg_out_dat_imm(s, tcg_cond_to_arm_cond[tcg_invert_cond(c)], 2023139c1837SPaolo Bonzini ARITH_MOV, args[0], 0, 0); 2024139c1837SPaolo Bonzini break; 2025139c1837SPaolo Bonzini 2026fecccfccSRichard Henderson case INDEX_op_qemu_ld_a32_i32: 2027fecccfccSRichard Henderson tcg_out_qemu_ld(s, args[0], -1, args[1], -1, args[2], TCG_TYPE_I32); 2028fecccfccSRichard Henderson break; 2029fecccfccSRichard Henderson case INDEX_op_qemu_ld_a64_i32: 2030737fb471SRichard Henderson tcg_out_qemu_ld(s, args[0], -1, args[1], args[2], 2031737fb471SRichard Henderson args[3], TCG_TYPE_I32); 2032139c1837SPaolo Bonzini break; 2033fecccfccSRichard Henderson case INDEX_op_qemu_ld_a32_i64: 2034737fb471SRichard Henderson tcg_out_qemu_ld(s, args[0], args[1], args[2], -1, 2035737fb471SRichard Henderson args[3], TCG_TYPE_I64); 2036fecccfccSRichard Henderson break; 2037fecccfccSRichard Henderson case INDEX_op_qemu_ld_a64_i64: 2038737fb471SRichard Henderson tcg_out_qemu_ld(s, args[0], args[1], args[2], args[3], 2039737fb471SRichard Henderson args[4], TCG_TYPE_I64); 2040139c1837SPaolo Bonzini break; 2041fecccfccSRichard Henderson 2042fecccfccSRichard Henderson case INDEX_op_qemu_st_a32_i32: 2043fecccfccSRichard Henderson tcg_out_qemu_st(s, args[0], -1, args[1], -1, args[2], TCG_TYPE_I32); 2044fecccfccSRichard Henderson break; 2045fecccfccSRichard Henderson case INDEX_op_qemu_st_a64_i32: 2046737fb471SRichard Henderson tcg_out_qemu_st(s, args[0], -1, args[1], args[2], 2047737fb471SRichard Henderson args[3], TCG_TYPE_I32); 2048139c1837SPaolo Bonzini break; 2049fecccfccSRichard Henderson case INDEX_op_qemu_st_a32_i64: 2050737fb471SRichard Henderson tcg_out_qemu_st(s, args[0], args[1], args[2], -1, 2051737fb471SRichard Henderson args[3], TCG_TYPE_I64); 2052fecccfccSRichard Henderson break; 2053fecccfccSRichard Henderson case INDEX_op_qemu_st_a64_i64: 2054737fb471SRichard Henderson tcg_out_qemu_st(s, args[0], args[1], args[2], args[3], 2055737fb471SRichard Henderson args[4], TCG_TYPE_I64); 2056139c1837SPaolo Bonzini break; 2057139c1837SPaolo Bonzini 2058139c1837SPaolo Bonzini case INDEX_op_bswap16_i32: 20592ec89a78SRichard Henderson tcg_out_bswap16(s, COND_AL, args[0], args[1], args[2]); 2060139c1837SPaolo Bonzini break; 2061139c1837SPaolo Bonzini case INDEX_op_bswap32_i32: 2062139c1837SPaolo Bonzini tcg_out_bswap32(s, COND_AL, args[0], args[1]); 2063139c1837SPaolo Bonzini break; 2064139c1837SPaolo Bonzini 2065139c1837SPaolo Bonzini case INDEX_op_deposit_i32: 2066139c1837SPaolo Bonzini tcg_out_deposit(s, COND_AL, args[0], args[2], 2067139c1837SPaolo Bonzini args[3], args[4], const_args[2]); 2068139c1837SPaolo Bonzini break; 2069139c1837SPaolo Bonzini case INDEX_op_extract_i32: 2070139c1837SPaolo Bonzini tcg_out_extract(s, COND_AL, args[0], args[1], args[2], args[3]); 2071139c1837SPaolo Bonzini break; 2072139c1837SPaolo Bonzini case INDEX_op_sextract_i32: 2073139c1837SPaolo Bonzini tcg_out_sextract(s, COND_AL, args[0], args[1], args[2], args[3]); 2074139c1837SPaolo Bonzini break; 2075139c1837SPaolo Bonzini case INDEX_op_extract2_i32: 2076139c1837SPaolo Bonzini /* ??? These optimization vs zero should be generic. */ 2077139c1837SPaolo Bonzini /* ??? But we can't substitute 2 for 1 in the opcode stream yet. */ 2078139c1837SPaolo Bonzini if (const_args[1]) { 2079139c1837SPaolo Bonzini if (const_args[2]) { 2080139c1837SPaolo Bonzini tcg_out_movi(s, TCG_TYPE_REG, args[0], 0); 2081139c1837SPaolo Bonzini } else { 2082139c1837SPaolo Bonzini tcg_out_dat_reg(s, COND_AL, ARITH_MOV, args[0], 0, 2083139c1837SPaolo Bonzini args[2], SHIFT_IMM_LSL(32 - args[3])); 2084139c1837SPaolo Bonzini } 2085139c1837SPaolo Bonzini } else if (const_args[2]) { 2086139c1837SPaolo Bonzini tcg_out_dat_reg(s, COND_AL, ARITH_MOV, args[0], 0, 2087139c1837SPaolo Bonzini args[1], SHIFT_IMM_LSR(args[3])); 2088139c1837SPaolo Bonzini } else { 2089139c1837SPaolo Bonzini /* We can do extract2 in 2 insns, vs the 3 required otherwise. */ 2090139c1837SPaolo Bonzini tcg_out_dat_reg(s, COND_AL, ARITH_MOV, TCG_REG_TMP, 0, 2091139c1837SPaolo Bonzini args[2], SHIFT_IMM_LSL(32 - args[3])); 2092139c1837SPaolo Bonzini tcg_out_dat_reg(s, COND_AL, ARITH_ORR, args[0], TCG_REG_TMP, 2093139c1837SPaolo Bonzini args[1], SHIFT_IMM_LSR(args[3])); 2094139c1837SPaolo Bonzini } 2095139c1837SPaolo Bonzini break; 2096139c1837SPaolo Bonzini 2097139c1837SPaolo Bonzini case INDEX_op_div_i32: 2098139c1837SPaolo Bonzini tcg_out_sdiv(s, COND_AL, args[0], args[1], args[2]); 2099139c1837SPaolo Bonzini break; 2100139c1837SPaolo Bonzini case INDEX_op_divu_i32: 2101139c1837SPaolo Bonzini tcg_out_udiv(s, COND_AL, args[0], args[1], args[2]); 2102139c1837SPaolo Bonzini break; 2103139c1837SPaolo Bonzini 2104139c1837SPaolo Bonzini case INDEX_op_mb: 2105139c1837SPaolo Bonzini tcg_out_mb(s, args[0]); 2106139c1837SPaolo Bonzini break; 2107139c1837SPaolo Bonzini 2108139c1837SPaolo Bonzini case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */ 2109139c1837SPaolo Bonzini case INDEX_op_call: /* Always emitted via tcg_out_call. */ 2110b55a8d9dSRichard Henderson case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ 2111cf7d6b8eSRichard Henderson case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ 2112678155b2SRichard Henderson case INDEX_op_ext8s_i32: /* Always emitted via tcg_reg_alloc_op. */ 2113d0e66c89SRichard Henderson case INDEX_op_ext8u_i32: 2114753e42eaSRichard Henderson case INDEX_op_ext16s_i32: 2115379afdffSRichard Henderson case INDEX_op_ext16u_i32: 2116139c1837SPaolo Bonzini default: 2117732e89f4SRichard Henderson g_assert_not_reached(); 2118139c1837SPaolo Bonzini } 2119139c1837SPaolo Bonzini} 2120139c1837SPaolo Bonzini 21217166eebbSRichard Hendersonstatic TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op) 2122139c1837SPaolo Bonzini{ 2123139c1837SPaolo Bonzini switch (op) { 2124139c1837SPaolo Bonzini case INDEX_op_goto_ptr: 21257166eebbSRichard Henderson return C_O0_I1(r); 2126139c1837SPaolo Bonzini 2127139c1837SPaolo Bonzini case INDEX_op_ld8u_i32: 2128139c1837SPaolo Bonzini case INDEX_op_ld8s_i32: 2129139c1837SPaolo Bonzini case INDEX_op_ld16u_i32: 2130139c1837SPaolo Bonzini case INDEX_op_ld16s_i32: 2131139c1837SPaolo Bonzini case INDEX_op_ld_i32: 2132139c1837SPaolo Bonzini case INDEX_op_neg_i32: 2133139c1837SPaolo Bonzini case INDEX_op_not_i32: 2134139c1837SPaolo Bonzini case INDEX_op_bswap16_i32: 2135139c1837SPaolo Bonzini case INDEX_op_bswap32_i32: 2136139c1837SPaolo Bonzini case INDEX_op_ext8s_i32: 2137139c1837SPaolo Bonzini case INDEX_op_ext16s_i32: 2138139c1837SPaolo Bonzini case INDEX_op_ext16u_i32: 2139139c1837SPaolo Bonzini case INDEX_op_extract_i32: 2140139c1837SPaolo Bonzini case INDEX_op_sextract_i32: 21417166eebbSRichard Henderson return C_O1_I1(r, r); 21427166eebbSRichard Henderson 21437166eebbSRichard Henderson case INDEX_op_st8_i32: 21447166eebbSRichard Henderson case INDEX_op_st16_i32: 21457166eebbSRichard Henderson case INDEX_op_st_i32: 21467166eebbSRichard Henderson return C_O0_I2(r, r); 2147139c1837SPaolo Bonzini 2148139c1837SPaolo Bonzini case INDEX_op_add_i32: 2149139c1837SPaolo Bonzini case INDEX_op_sub_i32: 2150139c1837SPaolo Bonzini case INDEX_op_setcond_i32: 2151fe06b897SRichard Henderson case INDEX_op_negsetcond_i32: 21527166eebbSRichard Henderson return C_O1_I2(r, r, rIN); 21537166eebbSRichard Henderson 2154139c1837SPaolo Bonzini case INDEX_op_and_i32: 2155139c1837SPaolo Bonzini case INDEX_op_andc_i32: 2156139c1837SPaolo Bonzini case INDEX_op_clz_i32: 2157139c1837SPaolo Bonzini case INDEX_op_ctz_i32: 21587166eebbSRichard Henderson return C_O1_I2(r, r, rIK); 21597166eebbSRichard Henderson 2160139c1837SPaolo Bonzini case INDEX_op_mul_i32: 2161139c1837SPaolo Bonzini case INDEX_op_div_i32: 2162139c1837SPaolo Bonzini case INDEX_op_divu_i32: 21637166eebbSRichard Henderson return C_O1_I2(r, r, r); 21647166eebbSRichard Henderson 2165139c1837SPaolo Bonzini case INDEX_op_mulu2_i32: 2166139c1837SPaolo Bonzini case INDEX_op_muls2_i32: 21677166eebbSRichard Henderson return C_O2_I2(r, r, r, r); 21687166eebbSRichard Henderson 2169139c1837SPaolo Bonzini case INDEX_op_or_i32: 2170139c1837SPaolo Bonzini case INDEX_op_xor_i32: 21717166eebbSRichard Henderson return C_O1_I2(r, r, rI); 21727166eebbSRichard Henderson 2173139c1837SPaolo Bonzini case INDEX_op_shl_i32: 2174139c1837SPaolo Bonzini case INDEX_op_shr_i32: 2175139c1837SPaolo Bonzini case INDEX_op_sar_i32: 2176139c1837SPaolo Bonzini case INDEX_op_rotl_i32: 2177139c1837SPaolo Bonzini case INDEX_op_rotr_i32: 21787166eebbSRichard Henderson return C_O1_I2(r, r, ri); 2179139c1837SPaolo Bonzini 2180139c1837SPaolo Bonzini case INDEX_op_brcond_i32: 21817166eebbSRichard Henderson return C_O0_I2(r, rIN); 2182139c1837SPaolo Bonzini case INDEX_op_deposit_i32: 21837166eebbSRichard Henderson return C_O1_I2(r, 0, rZ); 2184139c1837SPaolo Bonzini case INDEX_op_extract2_i32: 21857166eebbSRichard Henderson return C_O1_I2(r, rZ, rZ); 2186139c1837SPaolo Bonzini case INDEX_op_movcond_i32: 21877166eebbSRichard Henderson return C_O1_I4(r, r, rIN, rIK, 0); 2188139c1837SPaolo Bonzini case INDEX_op_add2_i32: 21897166eebbSRichard Henderson return C_O2_I4(r, r, r, r, rIN, rIK); 2190139c1837SPaolo Bonzini case INDEX_op_sub2_i32: 21917166eebbSRichard Henderson return C_O2_I4(r, r, rI, rI, rIN, rIK); 2192139c1837SPaolo Bonzini case INDEX_op_brcond2_i32: 21937166eebbSRichard Henderson return C_O0_I4(r, r, rI, rI); 2194139c1837SPaolo Bonzini case INDEX_op_setcond2_i32: 21957166eebbSRichard Henderson return C_O1_I4(r, r, r, rI, rI); 2196139c1837SPaolo Bonzini 2197fecccfccSRichard Henderson case INDEX_op_qemu_ld_a32_i32: 2198fecccfccSRichard Henderson return C_O1_I1(r, q); 2199fecccfccSRichard Henderson case INDEX_op_qemu_ld_a64_i32: 2200fecccfccSRichard Henderson return C_O1_I2(r, q, q); 2201fecccfccSRichard Henderson case INDEX_op_qemu_ld_a32_i64: 2202fecccfccSRichard Henderson return C_O2_I1(e, p, q); 2203fecccfccSRichard Henderson case INDEX_op_qemu_ld_a64_i64: 2204fecccfccSRichard Henderson return C_O2_I2(e, p, q, q); 2205fecccfccSRichard Henderson case INDEX_op_qemu_st_a32_i32: 2206fecccfccSRichard Henderson return C_O0_I2(q, q); 2207fecccfccSRichard Henderson case INDEX_op_qemu_st_a64_i32: 2208fecccfccSRichard Henderson return C_O0_I3(q, q, q); 2209fecccfccSRichard Henderson case INDEX_op_qemu_st_a32_i64: 2210fecccfccSRichard Henderson return C_O0_I3(Q, p, q); 2211fecccfccSRichard Henderson case INDEX_op_qemu_st_a64_i64: 2212fecccfccSRichard Henderson return C_O0_I4(Q, p, q, q); 2213139c1837SPaolo Bonzini 2214000cf477SRichard Henderson case INDEX_op_st_vec: 2215000cf477SRichard Henderson return C_O0_I2(w, r); 2216000cf477SRichard Henderson case INDEX_op_ld_vec: 2217000cf477SRichard Henderson case INDEX_op_dupm_vec: 2218000cf477SRichard Henderson return C_O1_I1(w, r); 2219000cf477SRichard Henderson case INDEX_op_dup_vec: 2220000cf477SRichard Henderson return C_O1_I1(w, wr); 22217df44cf6SRichard Henderson case INDEX_op_abs_vec: 22227df44cf6SRichard Henderson case INDEX_op_neg_vec: 22237df44cf6SRichard Henderson case INDEX_op_not_vec: 2224d4c4e9c5SRichard Henderson case INDEX_op_shli_vec: 2225d4c4e9c5SRichard Henderson case INDEX_op_shri_vec: 2226d4c4e9c5SRichard Henderson case INDEX_op_sari_vec: 22277df44cf6SRichard Henderson return C_O1_I1(w, w); 2228000cf477SRichard Henderson case INDEX_op_dup2_vec: 2229000cf477SRichard Henderson case INDEX_op_add_vec: 2230752b1769SRichard Henderson case INDEX_op_mul_vec: 2231dbbeff77SRichard Henderson case INDEX_op_smax_vec: 2232dbbeff77SRichard Henderson case INDEX_op_smin_vec: 22334fcd3017SRichard Henderson case INDEX_op_ssadd_vec: 22344fcd3017SRichard Henderson case INDEX_op_sssub_vec: 2235000cf477SRichard Henderson case INDEX_op_sub_vec: 2236dbbeff77SRichard Henderson case INDEX_op_umax_vec: 2237dbbeff77SRichard Henderson case INDEX_op_umin_vec: 22384fcd3017SRichard Henderson case INDEX_op_usadd_vec: 22394fcd3017SRichard Henderson case INDEX_op_ussub_vec: 2240000cf477SRichard Henderson case INDEX_op_xor_vec: 224131d36639SRichard Henderson case INDEX_op_arm_sshl_vec: 224231d36639SRichard Henderson case INDEX_op_arm_ushl_vec: 2243000cf477SRichard Henderson return C_O1_I2(w, w, w); 22445047ae64SRichard Henderson case INDEX_op_arm_sli_vec: 22455047ae64SRichard Henderson return C_O1_I2(w, 0, w); 2246d74b86edSRichard Henderson case INDEX_op_or_vec: 22477df44cf6SRichard Henderson case INDEX_op_andc_vec: 2248d74b86edSRichard Henderson return C_O1_I2(w, w, wO); 2249d74b86edSRichard Henderson case INDEX_op_and_vec: 22507df44cf6SRichard Henderson case INDEX_op_orc_vec: 2251d74b86edSRichard Henderson return C_O1_I2(w, w, wV); 2252d74b86edSRichard Henderson case INDEX_op_cmp_vec: 2253d74b86edSRichard Henderson return C_O1_I2(w, w, wZ); 2254f2b46c71SRichard Henderson case INDEX_op_bitsel_vec: 2255f2b46c71SRichard Henderson return C_O1_I3(w, w, w, w); 2256139c1837SPaolo Bonzini default: 22577166eebbSRichard Henderson g_assert_not_reached(); 2258139c1837SPaolo Bonzini } 2259139c1837SPaolo Bonzini} 2260139c1837SPaolo Bonzini 2261139c1837SPaolo Bonzinistatic void tcg_target_init(TCGContext *s) 2262139c1837SPaolo Bonzini{ 2263a4761232SPhilippe Mathieu-Daudé /* 2264a4761232SPhilippe Mathieu-Daudé * Only probe for the platform and capabilities if we haven't already 2265a4761232SPhilippe Mathieu-Daudé * determined maximum values at compile time. 2266a4761232SPhilippe Mathieu-Daudé */ 2267000cf477SRichard Henderson#if !defined(use_idiv_instructions) || !defined(use_neon_instructions) 2268139c1837SPaolo Bonzini { 2269139c1837SPaolo Bonzini unsigned long hwcap = qemu_getauxval(AT_HWCAP); 2270000cf477SRichard Henderson#ifndef use_idiv_instructions 2271139c1837SPaolo Bonzini use_idiv_instructions = (hwcap & HWCAP_ARM_IDIVA) != 0; 2272000cf477SRichard Henderson#endif 2273000cf477SRichard Henderson#ifndef use_neon_instructions 2274000cf477SRichard Henderson use_neon_instructions = (hwcap & HWCAP_ARM_NEON) != 0; 2275000cf477SRichard Henderson#endif 2276139c1837SPaolo Bonzini } 2277139c1837SPaolo Bonzini#endif 2278000cf477SRichard Henderson 2279139c1837SPaolo Bonzini if (__ARM_ARCH < 7) { 2280139c1837SPaolo Bonzini const char *pl = (const char *)qemu_getauxval(AT_PLATFORM); 2281139c1837SPaolo Bonzini if (pl != NULL && pl[0] == 'v' && pl[1] >= '4' && pl[1] <= '9') { 2282139c1837SPaolo Bonzini arm_arch = pl[1] - '0'; 2283139c1837SPaolo Bonzini } 228401dfc0edSRichard Henderson 228501dfc0edSRichard Henderson if (arm_arch < 6) { 228601dfc0edSRichard Henderson error_report("TCG: ARMv%d is unsupported; exiting", arm_arch); 228701dfc0edSRichard Henderson exit(EXIT_FAILURE); 228801dfc0edSRichard Henderson } 2289139c1837SPaolo Bonzini } 2290139c1837SPaolo Bonzini 2291000cf477SRichard Henderson tcg_target_available_regs[TCG_TYPE_I32] = ALL_GENERAL_REGS; 2292139c1837SPaolo Bonzini 2293139c1837SPaolo Bonzini tcg_target_call_clobber_regs = 0; 2294139c1837SPaolo Bonzini tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R0); 2295139c1837SPaolo Bonzini tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R1); 2296139c1837SPaolo Bonzini tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R2); 2297139c1837SPaolo Bonzini tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R3); 2298139c1837SPaolo Bonzini tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R12); 2299139c1837SPaolo Bonzini tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R14); 2300139c1837SPaolo Bonzini 2301000cf477SRichard Henderson if (use_neon_instructions) { 2302000cf477SRichard Henderson tcg_target_available_regs[TCG_TYPE_V64] = ALL_VECTOR_REGS; 2303000cf477SRichard Henderson tcg_target_available_regs[TCG_TYPE_V128] = ALL_VECTOR_REGS; 2304000cf477SRichard Henderson 2305000cf477SRichard Henderson tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_Q0); 2306000cf477SRichard Henderson tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_Q1); 2307000cf477SRichard Henderson tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_Q2); 2308000cf477SRichard Henderson tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_Q3); 2309000cf477SRichard Henderson tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_Q8); 2310000cf477SRichard Henderson tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_Q9); 2311000cf477SRichard Henderson tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_Q10); 2312000cf477SRichard Henderson tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_Q11); 2313000cf477SRichard Henderson tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_Q12); 2314000cf477SRichard Henderson tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_Q13); 2315000cf477SRichard Henderson tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_Q14); 2316000cf477SRichard Henderson tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_Q15); 2317000cf477SRichard Henderson } 2318000cf477SRichard Henderson 2319139c1837SPaolo Bonzini s->reserved_regs = 0; 2320139c1837SPaolo Bonzini tcg_regset_set_reg(s->reserved_regs, TCG_REG_CALL_STACK); 2321139c1837SPaolo Bonzini tcg_regset_set_reg(s->reserved_regs, TCG_REG_TMP); 2322139c1837SPaolo Bonzini tcg_regset_set_reg(s->reserved_regs, TCG_REG_PC); 2323000cf477SRichard Henderson tcg_regset_set_reg(s->reserved_regs, TCG_VEC_TMP); 2324139c1837SPaolo Bonzini} 2325139c1837SPaolo Bonzini 23266e49fad2SRichard Hendersonstatic void tcg_out_ld(TCGContext *s, TCGType type, TCGReg arg, 2327139c1837SPaolo Bonzini TCGReg arg1, intptr_t arg2) 2328139c1837SPaolo Bonzini{ 23296e49fad2SRichard Henderson switch (type) { 23306e49fad2SRichard Henderson case TCG_TYPE_I32: 2331139c1837SPaolo Bonzini tcg_out_ld32u(s, COND_AL, arg, arg1, arg2); 23326e49fad2SRichard Henderson return; 23336e49fad2SRichard Henderson case TCG_TYPE_V64: 23346e49fad2SRichard Henderson /* regs 1; size 8; align 8 */ 23356e49fad2SRichard Henderson tcg_out_vldst(s, INSN_VLD1 | 0x7d0, arg, arg1, arg2); 23366e49fad2SRichard Henderson return; 23376e49fad2SRichard Henderson case TCG_TYPE_V128: 2338b9537d59SRichard Henderson /* 2339b9537d59SRichard Henderson * We have only 8-byte alignment for the stack per the ABI. 2340b9537d59SRichard Henderson * Rather than dynamically re-align the stack, it's easier 2341b9537d59SRichard Henderson * to simply not request alignment beyond that. So: 2342b9537d59SRichard Henderson * regs 2; size 8; align 8 2343b9537d59SRichard Henderson */ 2344b9537d59SRichard Henderson tcg_out_vldst(s, INSN_VLD1 | 0xad0, arg, arg1, arg2); 23456e49fad2SRichard Henderson return; 23466e49fad2SRichard Henderson default: 23476e49fad2SRichard Henderson g_assert_not_reached(); 23486e49fad2SRichard Henderson } 2349139c1837SPaolo Bonzini} 2350139c1837SPaolo Bonzini 23516e49fad2SRichard Hendersonstatic void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, 2352139c1837SPaolo Bonzini TCGReg arg1, intptr_t arg2) 2353139c1837SPaolo Bonzini{ 23546e49fad2SRichard Henderson switch (type) { 23556e49fad2SRichard Henderson case TCG_TYPE_I32: 2356139c1837SPaolo Bonzini tcg_out_st32(s, COND_AL, arg, arg1, arg2); 23576e49fad2SRichard Henderson return; 23586e49fad2SRichard Henderson case TCG_TYPE_V64: 23596e49fad2SRichard Henderson /* regs 1; size 8; align 8 */ 23606e49fad2SRichard Henderson tcg_out_vldst(s, INSN_VST1 | 0x7d0, arg, arg1, arg2); 23616e49fad2SRichard Henderson return; 23626e49fad2SRichard Henderson case TCG_TYPE_V128: 2363b9537d59SRichard Henderson /* See tcg_out_ld re alignment: regs 2; size 8; align 8 */ 2364b9537d59SRichard Henderson tcg_out_vldst(s, INSN_VST1 | 0xad0, arg, arg1, arg2); 23656e49fad2SRichard Henderson return; 23666e49fad2SRichard Henderson default: 23676e49fad2SRichard Henderson g_assert_not_reached(); 23686e49fad2SRichard Henderson } 2369139c1837SPaolo Bonzini} 2370139c1837SPaolo Bonzini 23715f726ebcSRichard Hendersonstatic bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val, 2372139c1837SPaolo Bonzini TCGReg base, intptr_t ofs) 2373139c1837SPaolo Bonzini{ 2374139c1837SPaolo Bonzini return false; 2375139c1837SPaolo Bonzini} 2376139c1837SPaolo Bonzini 23772df2a8cfSRichard Hendersonstatic bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg) 2378139c1837SPaolo Bonzini{ 23792df2a8cfSRichard Henderson if (ret == arg) { 23802df2a8cfSRichard Henderson return true; 23812df2a8cfSRichard Henderson } 23822df2a8cfSRichard Henderson switch (type) { 23832df2a8cfSRichard Henderson case TCG_TYPE_I32: 23842df2a8cfSRichard Henderson if (ret < TCG_REG_Q0 && arg < TCG_REG_Q0) { 2385139c1837SPaolo Bonzini tcg_out_mov_reg(s, COND_AL, ret, arg); 2386139c1837SPaolo Bonzini return true; 2387139c1837SPaolo Bonzini } 23882df2a8cfSRichard Henderson return false; 2389139c1837SPaolo Bonzini 23902df2a8cfSRichard Henderson case TCG_TYPE_V64: 23912df2a8cfSRichard Henderson case TCG_TYPE_V128: 23922df2a8cfSRichard Henderson /* "VMOV D,N" is an alias for "VORR D,N,N". */ 23932df2a8cfSRichard Henderson tcg_out_vreg3(s, INSN_VORR, type - TCG_TYPE_V64, 0, ret, arg, arg); 23942df2a8cfSRichard Henderson return true; 23952df2a8cfSRichard Henderson 23962df2a8cfSRichard Henderson default: 23972df2a8cfSRichard Henderson g_assert_not_reached(); 23982df2a8cfSRichard Henderson } 23992df2a8cfSRichard Henderson} 24002df2a8cfSRichard Henderson 24012df2a8cfSRichard Hendersonstatic void tcg_out_movi(TCGContext *s, TCGType type, 2402139c1837SPaolo Bonzini TCGReg ret, tcg_target_long arg) 2403139c1837SPaolo Bonzini{ 24042df2a8cfSRichard Henderson tcg_debug_assert(type == TCG_TYPE_I32); 24052df2a8cfSRichard Henderson tcg_debug_assert(ret < TCG_REG_Q0); 2406139c1837SPaolo Bonzini tcg_out_movi32(s, COND_AL, ret, arg); 2407139c1837SPaolo Bonzini} 2408139c1837SPaolo Bonzini 2409767c2503SRichard Hendersonstatic bool tcg_out_xchg(TCGContext *s, TCGType type, TCGReg r1, TCGReg r2) 2410767c2503SRichard Henderson{ 2411767c2503SRichard Henderson return false; 2412767c2503SRichard Henderson} 2413767c2503SRichard Henderson 24146a6d772eSRichard Hendersonstatic void tcg_out_addi_ptr(TCGContext *s, TCGReg rd, TCGReg rs, 24156a6d772eSRichard Henderson tcg_target_long imm) 24166a6d772eSRichard Henderson{ 24176a6d772eSRichard Henderson int enc, opc = ARITH_ADD; 24186a6d772eSRichard Henderson 24196a6d772eSRichard Henderson /* All of the easiest immediates to encode are positive. */ 24206a6d772eSRichard Henderson if (imm < 0) { 24216a6d772eSRichard Henderson imm = -imm; 24226a6d772eSRichard Henderson opc = ARITH_SUB; 24236a6d772eSRichard Henderson } 24246a6d772eSRichard Henderson enc = encode_imm(imm); 24256a6d772eSRichard Henderson if (enc >= 0) { 24266a6d772eSRichard Henderson tcg_out_dat_imm(s, COND_AL, opc, rd, rs, enc); 24276a6d772eSRichard Henderson } else { 24286a6d772eSRichard Henderson tcg_out_movi32(s, COND_AL, TCG_REG_TMP, imm); 24296a6d772eSRichard Henderson tcg_out_dat_reg(s, COND_AL, opc, rd, rs, 24306a6d772eSRichard Henderson TCG_REG_TMP, SHIFT_IMM_LSL(0)); 24316a6d772eSRichard Henderson } 24326a6d772eSRichard Henderson} 24336a6d772eSRichard Henderson 2434213e8d84SRichard Henderson/* Type is always V128, with I64 elements. */ 2435213e8d84SRichard Hendersonstatic void tcg_out_dup2_vec(TCGContext *s, TCGReg rd, TCGReg rl, TCGReg rh) 2436213e8d84SRichard Henderson{ 2437213e8d84SRichard Henderson /* Move high element into place first. */ 2438213e8d84SRichard Henderson /* VMOV Dd+1, Ds */ 2439213e8d84SRichard Henderson tcg_out_vreg3(s, INSN_VORR | (1 << 12), 0, 0, rd, rh, rh); 2440213e8d84SRichard Henderson /* Move low element into place; tcg_out_mov will check for nop. */ 2441213e8d84SRichard Henderson tcg_out_mov(s, TCG_TYPE_V64, rd, rl); 2442213e8d84SRichard Henderson} 2443213e8d84SRichard Henderson 2444000cf477SRichard Hendersonstatic bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece, 2445000cf477SRichard Henderson TCGReg rd, TCGReg rs) 2446000cf477SRichard Henderson{ 2447213e8d84SRichard Henderson int q = type - TCG_TYPE_V64; 2448213e8d84SRichard Henderson 2449213e8d84SRichard Henderson if (vece == MO_64) { 2450213e8d84SRichard Henderson if (type == TCG_TYPE_V128) { 2451213e8d84SRichard Henderson tcg_out_dup2_vec(s, rd, rs, rs); 2452213e8d84SRichard Henderson } else { 2453213e8d84SRichard Henderson tcg_out_mov(s, TCG_TYPE_V64, rd, rs); 2454213e8d84SRichard Henderson } 2455213e8d84SRichard Henderson } else if (rs < TCG_REG_Q0) { 2456213e8d84SRichard Henderson int b = (vece == MO_8); 2457213e8d84SRichard Henderson int e = (vece == MO_16); 2458213e8d84SRichard Henderson tcg_out32(s, INSN_VDUP_G | (b << 22) | (q << 21) | (e << 5) | 2459213e8d84SRichard Henderson encode_vn(rd) | (rs << 12)); 2460213e8d84SRichard Henderson } else { 2461213e8d84SRichard Henderson int imm4 = 1 << vece; 2462213e8d84SRichard Henderson tcg_out32(s, INSN_VDUP_S | (imm4 << 16) | (q << 6) | 2463213e8d84SRichard Henderson encode_vd(rd) | encode_vm(rs)); 2464213e8d84SRichard Henderson } 2465213e8d84SRichard Henderson return true; 2466000cf477SRichard Henderson} 2467000cf477SRichard Henderson 2468000cf477SRichard Hendersonstatic bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece, 2469000cf477SRichard Henderson TCGReg rd, TCGReg base, intptr_t offset) 2470000cf477SRichard Henderson{ 2471213e8d84SRichard Henderson if (vece == MO_64) { 2472213e8d84SRichard Henderson tcg_out_ld(s, TCG_TYPE_V64, rd, base, offset); 2473213e8d84SRichard Henderson if (type == TCG_TYPE_V128) { 2474213e8d84SRichard Henderson tcg_out_dup2_vec(s, rd, rd, rd); 2475213e8d84SRichard Henderson } 2476213e8d84SRichard Henderson } else { 2477213e8d84SRichard Henderson int q = type - TCG_TYPE_V64; 2478213e8d84SRichard Henderson tcg_out_vldst(s, INSN_VLD1R | (vece << 6) | (q << 5), 2479213e8d84SRichard Henderson rd, base, offset); 2480213e8d84SRichard Henderson } 2481213e8d84SRichard Henderson return true; 2482000cf477SRichard Henderson} 2483000cf477SRichard Henderson 2484000cf477SRichard Hendersonstatic void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece, 2485000cf477SRichard Henderson TCGReg rd, int64_t v64) 2486000cf477SRichard Henderson{ 2487213e8d84SRichard Henderson int q = type - TCG_TYPE_V64; 2488213e8d84SRichard Henderson int cmode, imm8, i; 2489213e8d84SRichard Henderson 2490213e8d84SRichard Henderson /* Test all bytes equal first. */ 2491213e8d84SRichard Henderson if (vece == MO_8) { 2492213e8d84SRichard Henderson tcg_out_vmovi(s, rd, q, 0, 0xe, v64); 2493213e8d84SRichard Henderson return; 2494213e8d84SRichard Henderson } 2495213e8d84SRichard Henderson 2496213e8d84SRichard Henderson /* 2497213e8d84SRichard Henderson * Test all bytes 0x00 or 0xff second. This can match cases that 2498213e8d84SRichard Henderson * might otherwise take 2 or 3 insns for MO_16 or MO_32 below. 2499213e8d84SRichard Henderson */ 2500213e8d84SRichard Henderson for (i = imm8 = 0; i < 8; i++) { 2501213e8d84SRichard Henderson uint8_t byte = v64 >> (i * 8); 2502213e8d84SRichard Henderson if (byte == 0xff) { 2503213e8d84SRichard Henderson imm8 |= 1 << i; 2504213e8d84SRichard Henderson } else if (byte != 0) { 2505213e8d84SRichard Henderson goto fail_bytes; 2506213e8d84SRichard Henderson } 2507213e8d84SRichard Henderson } 2508213e8d84SRichard Henderson tcg_out_vmovi(s, rd, q, 1, 0xe, imm8); 2509213e8d84SRichard Henderson return; 2510213e8d84SRichard Henderson fail_bytes: 2511213e8d84SRichard Henderson 2512213e8d84SRichard Henderson /* 2513213e8d84SRichard Henderson * Tests for various replications. For each element width, if we 2514213e8d84SRichard Henderson * cannot find an expansion there's no point checking a larger 2515213e8d84SRichard Henderson * width because we already know by replication it cannot match. 2516213e8d84SRichard Henderson */ 2517213e8d84SRichard Henderson if (vece == MO_16) { 2518213e8d84SRichard Henderson uint16_t v16 = v64; 2519213e8d84SRichard Henderson 2520213e8d84SRichard Henderson if (is_shimm16(v16, &cmode, &imm8)) { 2521213e8d84SRichard Henderson tcg_out_vmovi(s, rd, q, 0, cmode, imm8); 2522213e8d84SRichard Henderson return; 2523213e8d84SRichard Henderson } 2524213e8d84SRichard Henderson if (is_shimm16(~v16, &cmode, &imm8)) { 2525213e8d84SRichard Henderson tcg_out_vmovi(s, rd, q, 1, cmode, imm8); 2526213e8d84SRichard Henderson return; 2527213e8d84SRichard Henderson } 2528213e8d84SRichard Henderson 2529213e8d84SRichard Henderson /* 2530213e8d84SRichard Henderson * Otherwise, all remaining constants can be loaded in two insns: 2531213e8d84SRichard Henderson * rd = v16 & 0xff, rd |= v16 & 0xff00. 2532213e8d84SRichard Henderson */ 2533213e8d84SRichard Henderson tcg_out_vmovi(s, rd, q, 0, 0x8, v16 & 0xff); 2534213e8d84SRichard Henderson tcg_out_vmovi(s, rd, q, 0, 0xb, v16 >> 8); /* VORRI */ 2535213e8d84SRichard Henderson return; 2536213e8d84SRichard Henderson } 2537213e8d84SRichard Henderson 2538213e8d84SRichard Henderson if (vece == MO_32) { 2539213e8d84SRichard Henderson uint32_t v32 = v64; 2540213e8d84SRichard Henderson 2541213e8d84SRichard Henderson if (is_shimm32(v32, &cmode, &imm8) || 2542213e8d84SRichard Henderson is_soimm32(v32, &cmode, &imm8)) { 2543213e8d84SRichard Henderson tcg_out_vmovi(s, rd, q, 0, cmode, imm8); 2544213e8d84SRichard Henderson return; 2545213e8d84SRichard Henderson } 2546213e8d84SRichard Henderson if (is_shimm32(~v32, &cmode, &imm8) || 2547213e8d84SRichard Henderson is_soimm32(~v32, &cmode, &imm8)) { 2548213e8d84SRichard Henderson tcg_out_vmovi(s, rd, q, 1, cmode, imm8); 2549213e8d84SRichard Henderson return; 2550213e8d84SRichard Henderson } 2551213e8d84SRichard Henderson 2552213e8d84SRichard Henderson /* 2553213e8d84SRichard Henderson * Restrict the set of constants to those we can load with 2554213e8d84SRichard Henderson * two instructions. Others we load from the pool. 2555213e8d84SRichard Henderson */ 2556213e8d84SRichard Henderson i = is_shimm32_pair(v32, &cmode, &imm8); 2557213e8d84SRichard Henderson if (i) { 2558213e8d84SRichard Henderson tcg_out_vmovi(s, rd, q, 0, cmode, imm8); 2559213e8d84SRichard Henderson tcg_out_vmovi(s, rd, q, 0, i | 1, extract32(v32, i * 4, 8)); 2560213e8d84SRichard Henderson return; 2561213e8d84SRichard Henderson } 2562213e8d84SRichard Henderson i = is_shimm32_pair(~v32, &cmode, &imm8); 2563213e8d84SRichard Henderson if (i) { 2564213e8d84SRichard Henderson tcg_out_vmovi(s, rd, q, 1, cmode, imm8); 2565213e8d84SRichard Henderson tcg_out_vmovi(s, rd, q, 1, i | 1, extract32(~v32, i * 4, 8)); 2566213e8d84SRichard Henderson return; 2567213e8d84SRichard Henderson } 2568213e8d84SRichard Henderson } 2569213e8d84SRichard Henderson 2570213e8d84SRichard Henderson /* 2571213e8d84SRichard Henderson * As a last resort, load from the constant pool. 2572213e8d84SRichard Henderson */ 2573213e8d84SRichard Henderson if (!q || vece == MO_64) { 2574213e8d84SRichard Henderson new_pool_l2(s, R_ARM_PC11, s->code_ptr, 0, v64, v64 >> 32); 2575213e8d84SRichard Henderson /* VLDR Dd, [pc + offset] */ 2576213e8d84SRichard Henderson tcg_out32(s, INSN_VLDR_D | encode_vd(rd) | (0xf << 16)); 2577213e8d84SRichard Henderson if (q) { 2578213e8d84SRichard Henderson tcg_out_dup2_vec(s, rd, rd, rd); 2579213e8d84SRichard Henderson } 2580213e8d84SRichard Henderson } else { 2581213e8d84SRichard Henderson new_pool_label(s, (uint32_t)v64, R_ARM_PC8, s->code_ptr, 0); 2582213e8d84SRichard Henderson /* add tmp, pc, offset */ 2583213e8d84SRichard Henderson tcg_out_dat_imm(s, COND_AL, ARITH_ADD, TCG_REG_TMP, TCG_REG_PC, 0); 2584213e8d84SRichard Henderson tcg_out_dupm_vec(s, type, MO_32, rd, TCG_REG_TMP, 0); 2585213e8d84SRichard Henderson } 2586000cf477SRichard Henderson} 2587000cf477SRichard Henderson 2588d74b86edSRichard Hendersonstatic const ARMInsn vec_cmp_insn[16] = { 2589d74b86edSRichard Henderson [TCG_COND_EQ] = INSN_VCEQ, 2590d74b86edSRichard Henderson [TCG_COND_GT] = INSN_VCGT, 2591d74b86edSRichard Henderson [TCG_COND_GE] = INSN_VCGE, 2592d74b86edSRichard Henderson [TCG_COND_GTU] = INSN_VCGT_U, 2593d74b86edSRichard Henderson [TCG_COND_GEU] = INSN_VCGE_U, 2594d74b86edSRichard Henderson}; 2595d74b86edSRichard Henderson 2596d74b86edSRichard Hendersonstatic const ARMInsn vec_cmp0_insn[16] = { 2597d74b86edSRichard Henderson [TCG_COND_EQ] = INSN_VCEQ0, 2598d74b86edSRichard Henderson [TCG_COND_GT] = INSN_VCGT0, 2599d74b86edSRichard Henderson [TCG_COND_GE] = INSN_VCGE0, 2600d74b86edSRichard Henderson [TCG_COND_LT] = INSN_VCLT0, 2601d74b86edSRichard Henderson [TCG_COND_LE] = INSN_VCLE0, 2602d74b86edSRichard Henderson}; 2603d74b86edSRichard Henderson 2604000cf477SRichard Hendersonstatic void tcg_out_vec_op(TCGContext *s, TCGOpcode opc, 2605000cf477SRichard Henderson unsigned vecl, unsigned vece, 2606421519d8SJose R. Ziviani const TCGArg args[TCG_MAX_OP_ARGS], 2607421519d8SJose R. Ziviani const int const_args[TCG_MAX_OP_ARGS]) 2608000cf477SRichard Henderson{ 2609d74b86edSRichard Henderson TCGType type = vecl + TCG_TYPE_V64; 2610d74b86edSRichard Henderson unsigned q = vecl; 2611f2b46c71SRichard Henderson TCGArg a0, a1, a2, a3; 2612d74b86edSRichard Henderson int cmode, imm8; 2613d74b86edSRichard Henderson 2614d74b86edSRichard Henderson a0 = args[0]; 2615d74b86edSRichard Henderson a1 = args[1]; 2616d74b86edSRichard Henderson a2 = args[2]; 2617d74b86edSRichard Henderson 2618d74b86edSRichard Henderson switch (opc) { 2619d74b86edSRichard Henderson case INDEX_op_ld_vec: 2620d74b86edSRichard Henderson tcg_out_ld(s, type, a0, a1, a2); 2621d74b86edSRichard Henderson return; 2622d74b86edSRichard Henderson case INDEX_op_st_vec: 2623d74b86edSRichard Henderson tcg_out_st(s, type, a0, a1, a2); 2624d74b86edSRichard Henderson return; 2625d74b86edSRichard Henderson case INDEX_op_dupm_vec: 2626d74b86edSRichard Henderson tcg_out_dupm_vec(s, type, vece, a0, a1, a2); 2627d74b86edSRichard Henderson return; 2628d74b86edSRichard Henderson case INDEX_op_dup2_vec: 2629d74b86edSRichard Henderson tcg_out_dup2_vec(s, a0, a1, a2); 2630d74b86edSRichard Henderson return; 26317df44cf6SRichard Henderson case INDEX_op_abs_vec: 26327df44cf6SRichard Henderson tcg_out_vreg2(s, INSN_VABS, q, vece, a0, a1); 26337df44cf6SRichard Henderson return; 26347df44cf6SRichard Henderson case INDEX_op_neg_vec: 26357df44cf6SRichard Henderson tcg_out_vreg2(s, INSN_VNEG, q, vece, a0, a1); 26367df44cf6SRichard Henderson return; 26377df44cf6SRichard Henderson case INDEX_op_not_vec: 26387df44cf6SRichard Henderson tcg_out_vreg2(s, INSN_VMVN, q, 0, a0, a1); 26397df44cf6SRichard Henderson return; 2640d74b86edSRichard Henderson case INDEX_op_add_vec: 2641d74b86edSRichard Henderson tcg_out_vreg3(s, INSN_VADD, q, vece, a0, a1, a2); 2642d74b86edSRichard Henderson return; 2643752b1769SRichard Henderson case INDEX_op_mul_vec: 2644752b1769SRichard Henderson tcg_out_vreg3(s, INSN_VMUL, q, vece, a0, a1, a2); 2645752b1769SRichard Henderson return; 2646dbbeff77SRichard Henderson case INDEX_op_smax_vec: 2647dbbeff77SRichard Henderson tcg_out_vreg3(s, INSN_VMAX, q, vece, a0, a1, a2); 2648dbbeff77SRichard Henderson return; 2649dbbeff77SRichard Henderson case INDEX_op_smin_vec: 2650dbbeff77SRichard Henderson tcg_out_vreg3(s, INSN_VMIN, q, vece, a0, a1, a2); 2651dbbeff77SRichard Henderson return; 2652d74b86edSRichard Henderson case INDEX_op_sub_vec: 2653d74b86edSRichard Henderson tcg_out_vreg3(s, INSN_VSUB, q, vece, a0, a1, a2); 2654d74b86edSRichard Henderson return; 26554fcd3017SRichard Henderson case INDEX_op_ssadd_vec: 26564fcd3017SRichard Henderson tcg_out_vreg3(s, INSN_VQADD, q, vece, a0, a1, a2); 26574fcd3017SRichard Henderson return; 26584fcd3017SRichard Henderson case INDEX_op_sssub_vec: 26594fcd3017SRichard Henderson tcg_out_vreg3(s, INSN_VQSUB, q, vece, a0, a1, a2); 26604fcd3017SRichard Henderson return; 2661dbbeff77SRichard Henderson case INDEX_op_umax_vec: 2662dbbeff77SRichard Henderson tcg_out_vreg3(s, INSN_VMAX_U, q, vece, a0, a1, a2); 2663dbbeff77SRichard Henderson return; 2664dbbeff77SRichard Henderson case INDEX_op_umin_vec: 2665dbbeff77SRichard Henderson tcg_out_vreg3(s, INSN_VMIN_U, q, vece, a0, a1, a2); 2666dbbeff77SRichard Henderson return; 26674fcd3017SRichard Henderson case INDEX_op_usadd_vec: 26684fcd3017SRichard Henderson tcg_out_vreg3(s, INSN_VQADD_U, q, vece, a0, a1, a2); 26694fcd3017SRichard Henderson return; 26704fcd3017SRichard Henderson case INDEX_op_ussub_vec: 26714fcd3017SRichard Henderson tcg_out_vreg3(s, INSN_VQSUB_U, q, vece, a0, a1, a2); 26724fcd3017SRichard Henderson return; 2673d74b86edSRichard Henderson case INDEX_op_xor_vec: 2674d74b86edSRichard Henderson tcg_out_vreg3(s, INSN_VEOR, q, 0, a0, a1, a2); 2675d74b86edSRichard Henderson return; 267631d36639SRichard Henderson case INDEX_op_arm_sshl_vec: 267731d36639SRichard Henderson /* 267831d36639SRichard Henderson * Note that Vm is the data and Vn is the shift count, 267931d36639SRichard Henderson * therefore the arguments appear reversed. 268031d36639SRichard Henderson */ 268131d36639SRichard Henderson tcg_out_vreg3(s, INSN_VSHL_S, q, vece, a0, a2, a1); 268231d36639SRichard Henderson return; 268331d36639SRichard Henderson case INDEX_op_arm_ushl_vec: 268431d36639SRichard Henderson /* See above. */ 268531d36639SRichard Henderson tcg_out_vreg3(s, INSN_VSHL_U, q, vece, a0, a2, a1); 268631d36639SRichard Henderson return; 2687d4c4e9c5SRichard Henderson case INDEX_op_shli_vec: 2688d4c4e9c5SRichard Henderson tcg_out_vshifti(s, INSN_VSHLI, q, a0, a1, a2 + (8 << vece)); 2689d4c4e9c5SRichard Henderson return; 2690d4c4e9c5SRichard Henderson case INDEX_op_shri_vec: 2691d4c4e9c5SRichard Henderson tcg_out_vshifti(s, INSN_VSHRI, q, a0, a1, (16 << vece) - a2); 2692d4c4e9c5SRichard Henderson return; 2693d4c4e9c5SRichard Henderson case INDEX_op_sari_vec: 2694d4c4e9c5SRichard Henderson tcg_out_vshifti(s, INSN_VSARI, q, a0, a1, (16 << vece) - a2); 2695d4c4e9c5SRichard Henderson return; 26965047ae64SRichard Henderson case INDEX_op_arm_sli_vec: 26975047ae64SRichard Henderson tcg_out_vshifti(s, INSN_VSLI, q, a0, a2, args[3] + (8 << vece)); 26985047ae64SRichard Henderson return; 2699d74b86edSRichard Henderson 27007df44cf6SRichard Henderson case INDEX_op_andc_vec: 27017df44cf6SRichard Henderson if (!const_args[2]) { 27027df44cf6SRichard Henderson tcg_out_vreg3(s, INSN_VBIC, q, 0, a0, a1, a2); 27037df44cf6SRichard Henderson return; 27047df44cf6SRichard Henderson } 27057df44cf6SRichard Henderson a2 = ~a2; 27067df44cf6SRichard Henderson /* fall through */ 2707d74b86edSRichard Henderson case INDEX_op_and_vec: 2708d74b86edSRichard Henderson if (const_args[2]) { 2709d74b86edSRichard Henderson is_shimm1632(~a2, &cmode, &imm8); 2710d74b86edSRichard Henderson if (a0 == a1) { 2711d74b86edSRichard Henderson tcg_out_vmovi(s, a0, q, 1, cmode | 1, imm8); /* VBICI */ 2712d74b86edSRichard Henderson return; 2713d74b86edSRichard Henderson } 2714d74b86edSRichard Henderson tcg_out_vmovi(s, a0, q, 1, cmode, imm8); /* VMVNI */ 2715d74b86edSRichard Henderson a2 = a0; 2716d74b86edSRichard Henderson } 2717d74b86edSRichard Henderson tcg_out_vreg3(s, INSN_VAND, q, 0, a0, a1, a2); 2718d74b86edSRichard Henderson return; 2719d74b86edSRichard Henderson 27207df44cf6SRichard Henderson case INDEX_op_orc_vec: 27217df44cf6SRichard Henderson if (!const_args[2]) { 27227df44cf6SRichard Henderson tcg_out_vreg3(s, INSN_VORN, q, 0, a0, a1, a2); 27237df44cf6SRichard Henderson return; 27247df44cf6SRichard Henderson } 27257df44cf6SRichard Henderson a2 = ~a2; 27267df44cf6SRichard Henderson /* fall through */ 2727d74b86edSRichard Henderson case INDEX_op_or_vec: 2728d74b86edSRichard Henderson if (const_args[2]) { 2729d74b86edSRichard Henderson is_shimm1632(a2, &cmode, &imm8); 2730d74b86edSRichard Henderson if (a0 == a1) { 2731d74b86edSRichard Henderson tcg_out_vmovi(s, a0, q, 0, cmode | 1, imm8); /* VORRI */ 2732d74b86edSRichard Henderson return; 2733d74b86edSRichard Henderson } 2734d74b86edSRichard Henderson tcg_out_vmovi(s, a0, q, 0, cmode, imm8); /* VMOVI */ 2735d74b86edSRichard Henderson a2 = a0; 2736d74b86edSRichard Henderson } 2737d74b86edSRichard Henderson tcg_out_vreg3(s, INSN_VORR, q, 0, a0, a1, a2); 2738d74b86edSRichard Henderson return; 2739d74b86edSRichard Henderson 2740d74b86edSRichard Henderson case INDEX_op_cmp_vec: 2741d74b86edSRichard Henderson { 2742d74b86edSRichard Henderson TCGCond cond = args[3]; 2743f230c793SRichard Henderson ARMInsn insn; 2744d74b86edSRichard Henderson 2745f230c793SRichard Henderson switch (cond) { 2746f230c793SRichard Henderson case TCG_COND_NE: 2747d74b86edSRichard Henderson if (const_args[2]) { 2748d74b86edSRichard Henderson tcg_out_vreg3(s, INSN_VTST, q, vece, a0, a1, a1); 2749d74b86edSRichard Henderson } else { 2750d74b86edSRichard Henderson tcg_out_vreg3(s, INSN_VCEQ, q, vece, a0, a1, a2); 2751d74b86edSRichard Henderson tcg_out_vreg2(s, INSN_VMVN, q, 0, a0, a0); 2752d74b86edSRichard Henderson } 2753f230c793SRichard Henderson break; 2754d74b86edSRichard Henderson 2755f230c793SRichard Henderson case TCG_COND_TSTNE: 2756f230c793SRichard Henderson case TCG_COND_TSTEQ: 2757f230c793SRichard Henderson if (const_args[2]) { 2758f230c793SRichard Henderson /* (x & 0) == 0 */ 2759f230c793SRichard Henderson tcg_out_dupi_vec(s, type, MO_8, a0, 2760f230c793SRichard Henderson -(cond == TCG_COND_TSTEQ)); 2761f230c793SRichard Henderson break; 2762f230c793SRichard Henderson } 2763f230c793SRichard Henderson tcg_out_vreg3(s, INSN_VTST, q, vece, a0, a1, a2); 2764f230c793SRichard Henderson if (cond == TCG_COND_TSTEQ) { 2765f230c793SRichard Henderson tcg_out_vreg2(s, INSN_VMVN, q, 0, a0, a0); 2766f230c793SRichard Henderson } 2767f230c793SRichard Henderson break; 2768f230c793SRichard Henderson 2769f230c793SRichard Henderson default: 2770d74b86edSRichard Henderson if (const_args[2]) { 2771d74b86edSRichard Henderson insn = vec_cmp0_insn[cond]; 2772d74b86edSRichard Henderson if (insn) { 2773d74b86edSRichard Henderson tcg_out_vreg2(s, insn, q, vece, a0, a1); 2774d74b86edSRichard Henderson return; 2775d74b86edSRichard Henderson } 2776d74b86edSRichard Henderson tcg_out_dupi_vec(s, type, MO_8, TCG_VEC_TMP, 0); 2777d74b86edSRichard Henderson a2 = TCG_VEC_TMP; 2778d74b86edSRichard Henderson } 2779d74b86edSRichard Henderson insn = vec_cmp_insn[cond]; 2780d74b86edSRichard Henderson if (insn == 0) { 2781d74b86edSRichard Henderson TCGArg t; 2782d74b86edSRichard Henderson t = a1, a1 = a2, a2 = t; 2783d74b86edSRichard Henderson cond = tcg_swap_cond(cond); 2784d74b86edSRichard Henderson insn = vec_cmp_insn[cond]; 2785d74b86edSRichard Henderson tcg_debug_assert(insn != 0); 2786d74b86edSRichard Henderson } 2787d74b86edSRichard Henderson tcg_out_vreg3(s, insn, q, vece, a0, a1, a2); 2788f230c793SRichard Henderson break; 2789d74b86edSRichard Henderson } 2790d74b86edSRichard Henderson } 2791d74b86edSRichard Henderson return; 2792d74b86edSRichard Henderson 2793f2b46c71SRichard Henderson case INDEX_op_bitsel_vec: 2794f2b46c71SRichard Henderson a3 = args[3]; 2795f2b46c71SRichard Henderson if (a0 == a3) { 2796f2b46c71SRichard Henderson tcg_out_vreg3(s, INSN_VBIT, q, 0, a0, a2, a1); 2797f2b46c71SRichard Henderson } else if (a0 == a2) { 2798f2b46c71SRichard Henderson tcg_out_vreg3(s, INSN_VBIF, q, 0, a0, a3, a1); 2799f2b46c71SRichard Henderson } else { 2800f2b46c71SRichard Henderson tcg_out_mov(s, type, a0, a1); 2801f2b46c71SRichard Henderson tcg_out_vreg3(s, INSN_VBSL, q, 0, a0, a2, a3); 2802f2b46c71SRichard Henderson } 2803f2b46c71SRichard Henderson return; 2804f2b46c71SRichard Henderson 2805d74b86edSRichard Henderson case INDEX_op_mov_vec: /* Always emitted via tcg_out_mov. */ 2806d74b86edSRichard Henderson case INDEX_op_dup_vec: /* Always emitted via tcg_out_dup_vec. */ 2807d74b86edSRichard Henderson default: 2808000cf477SRichard Henderson g_assert_not_reached(); 2809000cf477SRichard Henderson } 2810d74b86edSRichard Henderson} 2811000cf477SRichard Henderson 2812000cf477SRichard Hendersonint tcg_can_emit_vec_op(TCGOpcode opc, TCGType type, unsigned vece) 2813000cf477SRichard Henderson{ 2814d74b86edSRichard Henderson switch (opc) { 2815d74b86edSRichard Henderson case INDEX_op_add_vec: 2816d74b86edSRichard Henderson case INDEX_op_sub_vec: 2817d74b86edSRichard Henderson case INDEX_op_and_vec: 28187df44cf6SRichard Henderson case INDEX_op_andc_vec: 2819d74b86edSRichard Henderson case INDEX_op_or_vec: 28207df44cf6SRichard Henderson case INDEX_op_orc_vec: 2821d74b86edSRichard Henderson case INDEX_op_xor_vec: 28227df44cf6SRichard Henderson case INDEX_op_not_vec: 2823d4c4e9c5SRichard Henderson case INDEX_op_shli_vec: 2824d4c4e9c5SRichard Henderson case INDEX_op_shri_vec: 2825d4c4e9c5SRichard Henderson case INDEX_op_sari_vec: 28264fcd3017SRichard Henderson case INDEX_op_ssadd_vec: 28274fcd3017SRichard Henderson case INDEX_op_sssub_vec: 28284fcd3017SRichard Henderson case INDEX_op_usadd_vec: 28294fcd3017SRichard Henderson case INDEX_op_ussub_vec: 2830f2b46c71SRichard Henderson case INDEX_op_bitsel_vec: 2831d74b86edSRichard Henderson return 1; 28327df44cf6SRichard Henderson case INDEX_op_abs_vec: 2833d74b86edSRichard Henderson case INDEX_op_cmp_vec: 2834752b1769SRichard Henderson case INDEX_op_mul_vec: 28357df44cf6SRichard Henderson case INDEX_op_neg_vec: 2836dbbeff77SRichard Henderson case INDEX_op_smax_vec: 2837dbbeff77SRichard Henderson case INDEX_op_smin_vec: 2838dbbeff77SRichard Henderson case INDEX_op_umax_vec: 2839dbbeff77SRichard Henderson case INDEX_op_umin_vec: 2840d74b86edSRichard Henderson return vece < MO_64; 284131d36639SRichard Henderson case INDEX_op_shlv_vec: 284231d36639SRichard Henderson case INDEX_op_shrv_vec: 284331d36639SRichard Henderson case INDEX_op_sarv_vec: 28445047ae64SRichard Henderson case INDEX_op_rotli_vec: 28450006039eSRichard Henderson case INDEX_op_rotlv_vec: 28460006039eSRichard Henderson case INDEX_op_rotrv_vec: 284731d36639SRichard Henderson return -1; 2848d74b86edSRichard Henderson default: 2849000cf477SRichard Henderson return 0; 2850000cf477SRichard Henderson } 2851d74b86edSRichard Henderson} 2852000cf477SRichard Henderson 2853000cf477SRichard Hendersonvoid tcg_expand_vec_op(TCGOpcode opc, TCGType type, unsigned vece, 2854000cf477SRichard Henderson TCGArg a0, ...) 2855000cf477SRichard Henderson{ 285631d36639SRichard Henderson va_list va; 28570006039eSRichard Henderson TCGv_vec v0, v1, v2, t1, t2, c1; 285831d36639SRichard Henderson TCGArg a2; 285931d36639SRichard Henderson 286031d36639SRichard Henderson va_start(va, a0); 286131d36639SRichard Henderson v0 = temp_tcgv_vec(arg_temp(a0)); 286231d36639SRichard Henderson v1 = temp_tcgv_vec(arg_temp(va_arg(va, TCGArg))); 286331d36639SRichard Henderson a2 = va_arg(va, TCGArg); 286431d36639SRichard Henderson va_end(va); 286531d36639SRichard Henderson 286631d36639SRichard Henderson switch (opc) { 286731d36639SRichard Henderson case INDEX_op_shlv_vec: 286831d36639SRichard Henderson /* 286931d36639SRichard Henderson * Merely propagate shlv_vec to arm_ushl_vec. 287031d36639SRichard Henderson * In this way we don't set TCG_TARGET_HAS_shv_vec 287131d36639SRichard Henderson * because everything is done via expansion. 287231d36639SRichard Henderson */ 287331d36639SRichard Henderson v2 = temp_tcgv_vec(arg_temp(a2)); 287431d36639SRichard Henderson vec_gen_3(INDEX_op_arm_ushl_vec, type, vece, tcgv_vec_arg(v0), 287531d36639SRichard Henderson tcgv_vec_arg(v1), tcgv_vec_arg(v2)); 287631d36639SRichard Henderson break; 287731d36639SRichard Henderson 287831d36639SRichard Henderson case INDEX_op_shrv_vec: 287931d36639SRichard Henderson case INDEX_op_sarv_vec: 288031d36639SRichard Henderson /* Right shifts are negative left shifts for NEON. */ 288131d36639SRichard Henderson v2 = temp_tcgv_vec(arg_temp(a2)); 288231d36639SRichard Henderson t1 = tcg_temp_new_vec(type); 288331d36639SRichard Henderson tcg_gen_neg_vec(vece, t1, v2); 288431d36639SRichard Henderson if (opc == INDEX_op_shrv_vec) { 288531d36639SRichard Henderson opc = INDEX_op_arm_ushl_vec; 288631d36639SRichard Henderson } else { 288731d36639SRichard Henderson opc = INDEX_op_arm_sshl_vec; 288831d36639SRichard Henderson } 288931d36639SRichard Henderson vec_gen_3(opc, type, vece, tcgv_vec_arg(v0), 289031d36639SRichard Henderson tcgv_vec_arg(v1), tcgv_vec_arg(t1)); 289131d36639SRichard Henderson tcg_temp_free_vec(t1); 289231d36639SRichard Henderson break; 289331d36639SRichard Henderson 28945047ae64SRichard Henderson case INDEX_op_rotli_vec: 28955047ae64SRichard Henderson t1 = tcg_temp_new_vec(type); 28965047ae64SRichard Henderson tcg_gen_shri_vec(vece, t1, v1, -a2 & ((8 << vece) - 1)); 28975047ae64SRichard Henderson vec_gen_4(INDEX_op_arm_sli_vec, type, vece, 28985047ae64SRichard Henderson tcgv_vec_arg(v0), tcgv_vec_arg(t1), tcgv_vec_arg(v1), a2); 28995047ae64SRichard Henderson tcg_temp_free_vec(t1); 29005047ae64SRichard Henderson break; 29015047ae64SRichard Henderson 29020006039eSRichard Henderson case INDEX_op_rotlv_vec: 29030006039eSRichard Henderson v2 = temp_tcgv_vec(arg_temp(a2)); 29040006039eSRichard Henderson t1 = tcg_temp_new_vec(type); 29050006039eSRichard Henderson c1 = tcg_constant_vec(type, vece, 8 << vece); 29060006039eSRichard Henderson tcg_gen_sub_vec(vece, t1, v2, c1); 29070006039eSRichard Henderson /* Right shifts are negative left shifts for NEON. */ 29080006039eSRichard Henderson vec_gen_3(INDEX_op_arm_ushl_vec, type, vece, tcgv_vec_arg(t1), 29090006039eSRichard Henderson tcgv_vec_arg(v1), tcgv_vec_arg(t1)); 29100006039eSRichard Henderson vec_gen_3(INDEX_op_arm_ushl_vec, type, vece, tcgv_vec_arg(v0), 29110006039eSRichard Henderson tcgv_vec_arg(v1), tcgv_vec_arg(v2)); 29120006039eSRichard Henderson tcg_gen_or_vec(vece, v0, v0, t1); 29130006039eSRichard Henderson tcg_temp_free_vec(t1); 29140006039eSRichard Henderson break; 29150006039eSRichard Henderson 29160006039eSRichard Henderson case INDEX_op_rotrv_vec: 29170006039eSRichard Henderson v2 = temp_tcgv_vec(arg_temp(a2)); 29180006039eSRichard Henderson t1 = tcg_temp_new_vec(type); 29190006039eSRichard Henderson t2 = tcg_temp_new_vec(type); 29200006039eSRichard Henderson c1 = tcg_constant_vec(type, vece, 8 << vece); 29210006039eSRichard Henderson tcg_gen_neg_vec(vece, t1, v2); 29220006039eSRichard Henderson tcg_gen_sub_vec(vece, t2, c1, v2); 29230006039eSRichard Henderson /* Right shifts are negative left shifts for NEON. */ 29240006039eSRichard Henderson vec_gen_3(INDEX_op_arm_ushl_vec, type, vece, tcgv_vec_arg(t1), 29250006039eSRichard Henderson tcgv_vec_arg(v1), tcgv_vec_arg(t1)); 29260006039eSRichard Henderson vec_gen_3(INDEX_op_arm_ushl_vec, type, vece, tcgv_vec_arg(t2), 29270006039eSRichard Henderson tcgv_vec_arg(v1), tcgv_vec_arg(t2)); 29280006039eSRichard Henderson tcg_gen_or_vec(vece, v0, t1, t2); 29290006039eSRichard Henderson tcg_temp_free_vec(t1); 29300006039eSRichard Henderson tcg_temp_free_vec(t2); 29310006039eSRichard Henderson break; 29320006039eSRichard Henderson 293331d36639SRichard Henderson default: 2934000cf477SRichard Henderson g_assert_not_reached(); 2935000cf477SRichard Henderson } 293631d36639SRichard Henderson} 2937000cf477SRichard Henderson 2938139c1837SPaolo Bonzinistatic void tcg_out_nop_fill(tcg_insn_unit *p, int count) 2939139c1837SPaolo Bonzini{ 2940139c1837SPaolo Bonzini int i; 2941139c1837SPaolo Bonzini for (i = 0; i < count; ++i) { 2942139c1837SPaolo Bonzini p[i] = INSN_NOP; 2943139c1837SPaolo Bonzini } 2944139c1837SPaolo Bonzini} 2945139c1837SPaolo Bonzini 2946139c1837SPaolo Bonzini/* Compute frame size via macros, to share between tcg_target_qemu_prologue 2947139c1837SPaolo Bonzini and tcg_register_jit. */ 2948139c1837SPaolo Bonzini 2949139c1837SPaolo Bonzini#define PUSH_SIZE ((11 - 4 + 1 + 1) * sizeof(tcg_target_long)) 2950139c1837SPaolo Bonzini 2951139c1837SPaolo Bonzini#define FRAME_SIZE \ 2952139c1837SPaolo Bonzini ((PUSH_SIZE \ 2953139c1837SPaolo Bonzini + TCG_STATIC_CALL_ARGS_SIZE \ 2954139c1837SPaolo Bonzini + CPU_TEMP_BUF_NLONGS * sizeof(long) \ 2955139c1837SPaolo Bonzini + TCG_TARGET_STACK_ALIGN - 1) \ 2956139c1837SPaolo Bonzini & -TCG_TARGET_STACK_ALIGN) 2957139c1837SPaolo Bonzini 2958139c1837SPaolo Bonzini#define STACK_ADDEND (FRAME_SIZE - PUSH_SIZE) 2959139c1837SPaolo Bonzini 2960139c1837SPaolo Bonzinistatic void tcg_target_qemu_prologue(TCGContext *s) 2961139c1837SPaolo Bonzini{ 2962139c1837SPaolo Bonzini /* Calling convention requires us to save r4-r11 and lr. */ 2963139c1837SPaolo Bonzini /* stmdb sp!, { r4 - r11, lr } */ 296431d160adSRichard Henderson tcg_out_ldstm(s, COND_AL, INSN_STMDB, TCG_REG_CALL_STACK, 296531d160adSRichard Henderson (1 << TCG_REG_R4) | (1 << TCG_REG_R5) | (1 << TCG_REG_R6) | 296631d160adSRichard Henderson (1 << TCG_REG_R7) | (1 << TCG_REG_R8) | (1 << TCG_REG_R9) | 296731d160adSRichard Henderson (1 << TCG_REG_R10) | (1 << TCG_REG_R11) | (1 << TCG_REG_R14)); 2968139c1837SPaolo Bonzini 2969139c1837SPaolo Bonzini /* Reserve callee argument and tcg temp space. */ 2970139c1837SPaolo Bonzini tcg_out_dat_rI(s, COND_AL, ARITH_SUB, TCG_REG_CALL_STACK, 2971139c1837SPaolo Bonzini TCG_REG_CALL_STACK, STACK_ADDEND, 1); 2972139c1837SPaolo Bonzini tcg_set_frame(s, TCG_REG_CALL_STACK, TCG_STATIC_CALL_ARGS_SIZE, 2973139c1837SPaolo Bonzini CPU_TEMP_BUF_NLONGS * sizeof(long)); 2974139c1837SPaolo Bonzini 2975139c1837SPaolo Bonzini tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]); 2976139c1837SPaolo Bonzini 29772c53bdf1SRichard Henderson if (!tcg_use_softmmu && guest_base) { 29784bb80207SRichard Henderson tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_GUEST_BASE, guest_base); 29794bb80207SRichard Henderson tcg_regset_set_reg(s->reserved_regs, TCG_REG_GUEST_BASE); 29804bb80207SRichard Henderson } 29814bb80207SRichard Henderson 2982326b9669SRichard Henderson tcg_out_b_reg(s, COND_AL, tcg_target_call_iarg_regs[1]); 2983139c1837SPaolo Bonzini 2984139c1837SPaolo Bonzini /* 2985139c1837SPaolo Bonzini * Return path for goto_ptr. Set return value to 0, a-la exit_tb, 2986139c1837SPaolo Bonzini * and fall through to the rest of the epilogue. 2987139c1837SPaolo Bonzini */ 2988c8bc1168SRichard Henderson tcg_code_gen_epilogue = tcg_splitwx_to_rx(s->code_ptr); 2989139c1837SPaolo Bonzini tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R0, 0); 2990139c1837SPaolo Bonzini tcg_out_epilogue(s); 2991139c1837SPaolo Bonzini} 2992139c1837SPaolo Bonzini 2993139c1837SPaolo Bonzinistatic void tcg_out_epilogue(TCGContext *s) 2994139c1837SPaolo Bonzini{ 2995139c1837SPaolo Bonzini /* Release local stack frame. */ 2996139c1837SPaolo Bonzini tcg_out_dat_rI(s, COND_AL, ARITH_ADD, TCG_REG_CALL_STACK, 2997139c1837SPaolo Bonzini TCG_REG_CALL_STACK, STACK_ADDEND, 1); 2998139c1837SPaolo Bonzini 2999139c1837SPaolo Bonzini /* ldmia sp!, { r4 - r11, pc } */ 300031d160adSRichard Henderson tcg_out_ldstm(s, COND_AL, INSN_LDMIA, TCG_REG_CALL_STACK, 300131d160adSRichard Henderson (1 << TCG_REG_R4) | (1 << TCG_REG_R5) | (1 << TCG_REG_R6) | 300231d160adSRichard Henderson (1 << TCG_REG_R7) | (1 << TCG_REG_R8) | (1 << TCG_REG_R9) | 300331d160adSRichard Henderson (1 << TCG_REG_R10) | (1 << TCG_REG_R11) | (1 << TCG_REG_PC)); 3004139c1837SPaolo Bonzini} 3005139c1837SPaolo Bonzini 30069358fbbfSRichard Hendersonstatic void tcg_out_tb_start(TCGContext *s) 30079358fbbfSRichard Henderson{ 30089358fbbfSRichard Henderson /* nothing to do */ 30099358fbbfSRichard Henderson} 30109358fbbfSRichard Henderson 3011139c1837SPaolo Bonzinitypedef struct { 3012139c1837SPaolo Bonzini DebugFrameHeader h; 3013139c1837SPaolo Bonzini uint8_t fde_def_cfa[4]; 3014139c1837SPaolo Bonzini uint8_t fde_reg_ofs[18]; 3015139c1837SPaolo Bonzini} DebugFrame; 3016139c1837SPaolo Bonzini 3017139c1837SPaolo Bonzini#define ELF_HOST_MACHINE EM_ARM 3018139c1837SPaolo Bonzini 3019139c1837SPaolo Bonzini/* We're expecting a 2 byte uleb128 encoded value. */ 3020139c1837SPaolo BonziniQEMU_BUILD_BUG_ON(FRAME_SIZE >= (1 << 14)); 3021139c1837SPaolo Bonzini 3022139c1837SPaolo Bonzinistatic const DebugFrame debug_frame = { 3023139c1837SPaolo Bonzini .h.cie.len = sizeof(DebugFrameCIE)-4, /* length after .len member */ 3024139c1837SPaolo Bonzini .h.cie.id = -1, 3025139c1837SPaolo Bonzini .h.cie.version = 1, 3026139c1837SPaolo Bonzini .h.cie.code_align = 1, 3027139c1837SPaolo Bonzini .h.cie.data_align = 0x7c, /* sleb128 -4 */ 3028139c1837SPaolo Bonzini .h.cie.return_column = 14, 3029139c1837SPaolo Bonzini 3030139c1837SPaolo Bonzini /* Total FDE size does not include the "len" member. */ 3031139c1837SPaolo Bonzini .h.fde.len = sizeof(DebugFrame) - offsetof(DebugFrame, h.fde.cie_offset), 3032139c1837SPaolo Bonzini 3033139c1837SPaolo Bonzini .fde_def_cfa = { 3034139c1837SPaolo Bonzini 12, 13, /* DW_CFA_def_cfa sp, ... */ 3035139c1837SPaolo Bonzini (FRAME_SIZE & 0x7f) | 0x80, /* ... uleb128 FRAME_SIZE */ 3036139c1837SPaolo Bonzini (FRAME_SIZE >> 7) 3037139c1837SPaolo Bonzini }, 3038139c1837SPaolo Bonzini .fde_reg_ofs = { 3039139c1837SPaolo Bonzini /* The following must match the stmdb in the prologue. */ 3040139c1837SPaolo Bonzini 0x8e, 1, /* DW_CFA_offset, lr, -4 */ 3041139c1837SPaolo Bonzini 0x8b, 2, /* DW_CFA_offset, r11, -8 */ 3042139c1837SPaolo Bonzini 0x8a, 3, /* DW_CFA_offset, r10, -12 */ 3043139c1837SPaolo Bonzini 0x89, 4, /* DW_CFA_offset, r9, -16 */ 3044139c1837SPaolo Bonzini 0x88, 5, /* DW_CFA_offset, r8, -20 */ 3045139c1837SPaolo Bonzini 0x87, 6, /* DW_CFA_offset, r7, -24 */ 3046139c1837SPaolo Bonzini 0x86, 7, /* DW_CFA_offset, r6, -28 */ 3047139c1837SPaolo Bonzini 0x85, 8, /* DW_CFA_offset, r5, -32 */ 3048139c1837SPaolo Bonzini 0x84, 9, /* DW_CFA_offset, r4, -36 */ 3049139c1837SPaolo Bonzini } 3050139c1837SPaolo Bonzini}; 3051139c1837SPaolo Bonzini 3052755bf9e5SRichard Hendersonvoid tcg_register_jit(const void *buf, size_t buf_size) 3053139c1837SPaolo Bonzini{ 3054139c1837SPaolo Bonzini tcg_register_jit_int(buf, buf_size, &debug_frame, sizeof(debug_frame)); 3055139c1837SPaolo Bonzini} 3056