xref: /openbmc/qemu/tcg/arm/tcg-target.c.inc (revision 3860a2a8de56fad71db42f4ad120eb7eff03b51f)
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