xref: /openbmc/qemu/tcg/tcg-op.c (revision 79b1af90)
1951c6300SRichard Henderson /*
2951c6300SRichard Henderson  * Tiny Code Generator for QEMU
3951c6300SRichard Henderson  *
4951c6300SRichard Henderson  * Copyright (c) 2008 Fabrice Bellard
5951c6300SRichard Henderson  *
6951c6300SRichard Henderson  * Permission is hereby granted, free of charge, to any person obtaining a copy
7951c6300SRichard Henderson  * of this software and associated documentation files (the "Software"), to deal
8951c6300SRichard Henderson  * in the Software without restriction, including without limitation the rights
9951c6300SRichard Henderson  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10951c6300SRichard Henderson  * copies of the Software, and to permit persons to whom the Software is
11951c6300SRichard Henderson  * furnished to do so, subject to the following conditions:
12951c6300SRichard Henderson  *
13951c6300SRichard Henderson  * The above copyright notice and this permission notice shall be included in
14951c6300SRichard Henderson  * all copies or substantial portions of the Software.
15951c6300SRichard Henderson  *
16951c6300SRichard Henderson  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17951c6300SRichard Henderson  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18951c6300SRichard Henderson  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19951c6300SRichard Henderson  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20951c6300SRichard Henderson  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21951c6300SRichard Henderson  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22951c6300SRichard Henderson  * THE SOFTWARE.
23951c6300SRichard Henderson  */
24951c6300SRichard Henderson 
25757e725bSPeter Maydell #include "qemu/osdep.h"
2633c11879SPaolo Bonzini #include "qemu-common.h"
2733c11879SPaolo Bonzini #include "cpu.h"
2863c91552SPaolo Bonzini #include "exec/exec-all.h"
29951c6300SRichard Henderson #include "tcg.h"
30951c6300SRichard Henderson #include "tcg-op.h"
31dcdaadb6SLluís Vilanova #include "trace-tcg.h"
32dcdaadb6SLluís Vilanova #include "trace/mem.h"
33951c6300SRichard Henderson 
343a13c3f3SRichard Henderson /* Reduce the number of ifdefs below.  This assumes that all uses of
353a13c3f3SRichard Henderson    TCGV_HIGH and TCGV_LOW are properly protected by a conditional that
363a13c3f3SRichard Henderson    the compiler can eliminate.  */
373a13c3f3SRichard Henderson #if TCG_TARGET_REG_BITS == 64
383a13c3f3SRichard Henderson extern TCGv_i32 TCGV_LOW_link_error(TCGv_i64);
393a13c3f3SRichard Henderson extern TCGv_i32 TCGV_HIGH_link_error(TCGv_i64);
403a13c3f3SRichard Henderson #define TCGV_LOW  TCGV_LOW_link_error
413a13c3f3SRichard Henderson #define TCGV_HIGH TCGV_HIGH_link_error
423a13c3f3SRichard Henderson #endif
43951c6300SRichard Henderson 
44c45cb8bbSRichard Henderson /* Note that this is optimized for sequential allocation during translate.
45c45cb8bbSRichard Henderson    Up to and including filling in the forward link immediately.  We'll do
46c45cb8bbSRichard Henderson    proper termination of the end of the list after we finish translation.  */
47c45cb8bbSRichard Henderson 
48c45cb8bbSRichard Henderson static void tcg_emit_op(TCGContext *ctx, TCGOpcode opc, int args)
49c45cb8bbSRichard Henderson {
50c45cb8bbSRichard Henderson     int oi = ctx->gen_next_op_idx;
51c45cb8bbSRichard Henderson     int ni = oi + 1;
52c45cb8bbSRichard Henderson     int pi = oi - 1;
53c45cb8bbSRichard Henderson 
54c45cb8bbSRichard Henderson     tcg_debug_assert(oi < OPC_BUF_SIZE);
55dcb8e758SRichard Henderson     ctx->gen_op_buf[0].prev = oi;
56c45cb8bbSRichard Henderson     ctx->gen_next_op_idx = ni;
57c45cb8bbSRichard Henderson 
58c45cb8bbSRichard Henderson     ctx->gen_op_buf[oi] = (TCGOp){
59c45cb8bbSRichard Henderson         .opc = opc,
60c45cb8bbSRichard Henderson         .args = args,
61c45cb8bbSRichard Henderson         .prev = pi,
62c45cb8bbSRichard Henderson         .next = ni
63c45cb8bbSRichard Henderson     };
64c45cb8bbSRichard Henderson }
65c45cb8bbSRichard Henderson 
66951c6300SRichard Henderson void tcg_gen_op1(TCGContext *ctx, TCGOpcode opc, TCGArg a1)
67951c6300SRichard Henderson {
68c45cb8bbSRichard Henderson     int pi = ctx->gen_next_parm_idx;
69951c6300SRichard Henderson 
70c45cb8bbSRichard Henderson     tcg_debug_assert(pi + 1 <= OPPARAM_BUF_SIZE);
71c45cb8bbSRichard Henderson     ctx->gen_next_parm_idx = pi + 1;
72c45cb8bbSRichard Henderson     ctx->gen_opparam_buf[pi] = a1;
73951c6300SRichard Henderson 
74c45cb8bbSRichard Henderson     tcg_emit_op(ctx, opc, pi);
75951c6300SRichard Henderson }
76951c6300SRichard Henderson 
77951c6300SRichard Henderson void tcg_gen_op2(TCGContext *ctx, TCGOpcode opc, TCGArg a1, TCGArg a2)
78951c6300SRichard Henderson {
79c45cb8bbSRichard Henderson     int pi = ctx->gen_next_parm_idx;
80951c6300SRichard Henderson 
81c45cb8bbSRichard Henderson     tcg_debug_assert(pi + 2 <= OPPARAM_BUF_SIZE);
82c45cb8bbSRichard Henderson     ctx->gen_next_parm_idx = pi + 2;
83c45cb8bbSRichard Henderson     ctx->gen_opparam_buf[pi + 0] = a1;
84c45cb8bbSRichard Henderson     ctx->gen_opparam_buf[pi + 1] = a2;
85951c6300SRichard Henderson 
86c45cb8bbSRichard Henderson     tcg_emit_op(ctx, opc, pi);
87951c6300SRichard Henderson }
88951c6300SRichard Henderson 
89951c6300SRichard Henderson void tcg_gen_op3(TCGContext *ctx, TCGOpcode opc, TCGArg a1,
90951c6300SRichard Henderson                  TCGArg a2, TCGArg a3)
91951c6300SRichard Henderson {
92c45cb8bbSRichard Henderson     int pi = ctx->gen_next_parm_idx;
93951c6300SRichard Henderson 
94c45cb8bbSRichard Henderson     tcg_debug_assert(pi + 3 <= OPPARAM_BUF_SIZE);
95c45cb8bbSRichard Henderson     ctx->gen_next_parm_idx = pi + 3;
96c45cb8bbSRichard Henderson     ctx->gen_opparam_buf[pi + 0] = a1;
97c45cb8bbSRichard Henderson     ctx->gen_opparam_buf[pi + 1] = a2;
98c45cb8bbSRichard Henderson     ctx->gen_opparam_buf[pi + 2] = a3;
99951c6300SRichard Henderson 
100c45cb8bbSRichard Henderson     tcg_emit_op(ctx, opc, pi);
101951c6300SRichard Henderson }
102951c6300SRichard Henderson 
103951c6300SRichard Henderson void tcg_gen_op4(TCGContext *ctx, TCGOpcode opc, TCGArg a1,
104951c6300SRichard Henderson                  TCGArg a2, TCGArg a3, TCGArg a4)
105951c6300SRichard Henderson {
106c45cb8bbSRichard Henderson     int pi = ctx->gen_next_parm_idx;
107951c6300SRichard Henderson 
108c45cb8bbSRichard Henderson     tcg_debug_assert(pi + 4 <= OPPARAM_BUF_SIZE);
109c45cb8bbSRichard Henderson     ctx->gen_next_parm_idx = pi + 4;
110c45cb8bbSRichard Henderson     ctx->gen_opparam_buf[pi + 0] = a1;
111c45cb8bbSRichard Henderson     ctx->gen_opparam_buf[pi + 1] = a2;
112c45cb8bbSRichard Henderson     ctx->gen_opparam_buf[pi + 2] = a3;
113c45cb8bbSRichard Henderson     ctx->gen_opparam_buf[pi + 3] = a4;
114951c6300SRichard Henderson 
115c45cb8bbSRichard Henderson     tcg_emit_op(ctx, opc, pi);
116951c6300SRichard Henderson }
117951c6300SRichard Henderson 
118951c6300SRichard Henderson void tcg_gen_op5(TCGContext *ctx, TCGOpcode opc, TCGArg a1,
119951c6300SRichard Henderson                  TCGArg a2, TCGArg a3, TCGArg a4, TCGArg a5)
120951c6300SRichard Henderson {
121c45cb8bbSRichard Henderson     int pi = ctx->gen_next_parm_idx;
122951c6300SRichard Henderson 
123c45cb8bbSRichard Henderson     tcg_debug_assert(pi + 5 <= OPPARAM_BUF_SIZE);
124c45cb8bbSRichard Henderson     ctx->gen_next_parm_idx = pi + 5;
125c45cb8bbSRichard Henderson     ctx->gen_opparam_buf[pi + 0] = a1;
126c45cb8bbSRichard Henderson     ctx->gen_opparam_buf[pi + 1] = a2;
127c45cb8bbSRichard Henderson     ctx->gen_opparam_buf[pi + 2] = a3;
128c45cb8bbSRichard Henderson     ctx->gen_opparam_buf[pi + 3] = a4;
129c45cb8bbSRichard Henderson     ctx->gen_opparam_buf[pi + 4] = a5;
130951c6300SRichard Henderson 
131c45cb8bbSRichard Henderson     tcg_emit_op(ctx, opc, pi);
132951c6300SRichard Henderson }
133951c6300SRichard Henderson 
134951c6300SRichard Henderson void tcg_gen_op6(TCGContext *ctx, TCGOpcode opc, TCGArg a1, TCGArg a2,
135951c6300SRichard Henderson                  TCGArg a3, TCGArg a4, TCGArg a5, TCGArg a6)
136951c6300SRichard Henderson {
137c45cb8bbSRichard Henderson     int pi = ctx->gen_next_parm_idx;
138951c6300SRichard Henderson 
139c45cb8bbSRichard Henderson     tcg_debug_assert(pi + 6 <= OPPARAM_BUF_SIZE);
140c45cb8bbSRichard Henderson     ctx->gen_next_parm_idx = pi + 6;
141c45cb8bbSRichard Henderson     ctx->gen_opparam_buf[pi + 0] = a1;
142c45cb8bbSRichard Henderson     ctx->gen_opparam_buf[pi + 1] = a2;
143c45cb8bbSRichard Henderson     ctx->gen_opparam_buf[pi + 2] = a3;
144c45cb8bbSRichard Henderson     ctx->gen_opparam_buf[pi + 3] = a4;
145c45cb8bbSRichard Henderson     ctx->gen_opparam_buf[pi + 4] = a5;
146c45cb8bbSRichard Henderson     ctx->gen_opparam_buf[pi + 5] = a6;
147951c6300SRichard Henderson 
148c45cb8bbSRichard Henderson     tcg_emit_op(ctx, opc, pi);
149951c6300SRichard Henderson }
150951c6300SRichard Henderson 
151f65e19bcSPranith Kumar void tcg_gen_mb(TCGBar mb_type)
152f65e19bcSPranith Kumar {
15391682118SRichard Henderson     if (parallel_cpus) {
154f65e19bcSPranith Kumar         tcg_gen_op1(&tcg_ctx, INDEX_op_mb, mb_type);
155f65e19bcSPranith Kumar     }
156f65e19bcSPranith Kumar }
157f65e19bcSPranith Kumar 
158951c6300SRichard Henderson /* 32 bit ops */
159951c6300SRichard Henderson 
160951c6300SRichard Henderson void tcg_gen_addi_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2)
161951c6300SRichard Henderson {
162951c6300SRichard Henderson     /* some cases can be optimized here */
163951c6300SRichard Henderson     if (arg2 == 0) {
164951c6300SRichard Henderson         tcg_gen_mov_i32(ret, arg1);
165951c6300SRichard Henderson     } else {
166951c6300SRichard Henderson         TCGv_i32 t0 = tcg_const_i32(arg2);
167951c6300SRichard Henderson         tcg_gen_add_i32(ret, arg1, t0);
168951c6300SRichard Henderson         tcg_temp_free_i32(t0);
169951c6300SRichard Henderson     }
170951c6300SRichard Henderson }
171951c6300SRichard Henderson 
172951c6300SRichard Henderson void tcg_gen_subfi_i32(TCGv_i32 ret, int32_t arg1, TCGv_i32 arg2)
173951c6300SRichard Henderson {
174951c6300SRichard Henderson     if (arg1 == 0 && TCG_TARGET_HAS_neg_i32) {
175951c6300SRichard Henderson         /* Don't recurse with tcg_gen_neg_i32.  */
176951c6300SRichard Henderson         tcg_gen_op2_i32(INDEX_op_neg_i32, ret, arg2);
177951c6300SRichard Henderson     } else {
178951c6300SRichard Henderson         TCGv_i32 t0 = tcg_const_i32(arg1);
179951c6300SRichard Henderson         tcg_gen_sub_i32(ret, t0, arg2);
180951c6300SRichard Henderson         tcg_temp_free_i32(t0);
181951c6300SRichard Henderson     }
182951c6300SRichard Henderson }
183951c6300SRichard Henderson 
184951c6300SRichard Henderson void tcg_gen_subi_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2)
185951c6300SRichard Henderson {
186951c6300SRichard Henderson     /* some cases can be optimized here */
187951c6300SRichard Henderson     if (arg2 == 0) {
188951c6300SRichard Henderson         tcg_gen_mov_i32(ret, arg1);
189951c6300SRichard Henderson     } else {
190951c6300SRichard Henderson         TCGv_i32 t0 = tcg_const_i32(arg2);
191951c6300SRichard Henderson         tcg_gen_sub_i32(ret, arg1, t0);
192951c6300SRichard Henderson         tcg_temp_free_i32(t0);
193951c6300SRichard Henderson     }
194951c6300SRichard Henderson }
195951c6300SRichard Henderson 
196951c6300SRichard Henderson void tcg_gen_andi_i32(TCGv_i32 ret, TCGv_i32 arg1, uint32_t arg2)
197951c6300SRichard Henderson {
198951c6300SRichard Henderson     TCGv_i32 t0;
199951c6300SRichard Henderson     /* Some cases can be optimized here.  */
200951c6300SRichard Henderson     switch (arg2) {
201951c6300SRichard Henderson     case 0:
202951c6300SRichard Henderson         tcg_gen_movi_i32(ret, 0);
203951c6300SRichard Henderson         return;
204951c6300SRichard Henderson     case 0xffffffffu:
205951c6300SRichard Henderson         tcg_gen_mov_i32(ret, arg1);
206951c6300SRichard Henderson         return;
207951c6300SRichard Henderson     case 0xffu:
208951c6300SRichard Henderson         /* Don't recurse with tcg_gen_ext8u_i32.  */
209951c6300SRichard Henderson         if (TCG_TARGET_HAS_ext8u_i32) {
210951c6300SRichard Henderson             tcg_gen_op2_i32(INDEX_op_ext8u_i32, ret, arg1);
211951c6300SRichard Henderson             return;
212951c6300SRichard Henderson         }
213951c6300SRichard Henderson         break;
214951c6300SRichard Henderson     case 0xffffu:
215951c6300SRichard Henderson         if (TCG_TARGET_HAS_ext16u_i32) {
216951c6300SRichard Henderson             tcg_gen_op2_i32(INDEX_op_ext16u_i32, ret, arg1);
217951c6300SRichard Henderson             return;
218951c6300SRichard Henderson         }
219951c6300SRichard Henderson         break;
220951c6300SRichard Henderson     }
221951c6300SRichard Henderson     t0 = tcg_const_i32(arg2);
222951c6300SRichard Henderson     tcg_gen_and_i32(ret, arg1, t0);
223951c6300SRichard Henderson     tcg_temp_free_i32(t0);
224951c6300SRichard Henderson }
225951c6300SRichard Henderson 
226951c6300SRichard Henderson void tcg_gen_ori_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2)
227951c6300SRichard Henderson {
228951c6300SRichard Henderson     /* Some cases can be optimized here.  */
229951c6300SRichard Henderson     if (arg2 == -1) {
230951c6300SRichard Henderson         tcg_gen_movi_i32(ret, -1);
231951c6300SRichard Henderson     } else if (arg2 == 0) {
232951c6300SRichard Henderson         tcg_gen_mov_i32(ret, arg1);
233951c6300SRichard Henderson     } else {
234951c6300SRichard Henderson         TCGv_i32 t0 = tcg_const_i32(arg2);
235951c6300SRichard Henderson         tcg_gen_or_i32(ret, arg1, t0);
236951c6300SRichard Henderson         tcg_temp_free_i32(t0);
237951c6300SRichard Henderson     }
238951c6300SRichard Henderson }
239951c6300SRichard Henderson 
240951c6300SRichard Henderson void tcg_gen_xori_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2)
241951c6300SRichard Henderson {
242951c6300SRichard Henderson     /* Some cases can be optimized here.  */
243951c6300SRichard Henderson     if (arg2 == 0) {
244951c6300SRichard Henderson         tcg_gen_mov_i32(ret, arg1);
245951c6300SRichard Henderson     } else if (arg2 == -1 && TCG_TARGET_HAS_not_i32) {
246951c6300SRichard Henderson         /* Don't recurse with tcg_gen_not_i32.  */
247951c6300SRichard Henderson         tcg_gen_op2_i32(INDEX_op_not_i32, ret, arg1);
248951c6300SRichard Henderson     } else {
249951c6300SRichard Henderson         TCGv_i32 t0 = tcg_const_i32(arg2);
250951c6300SRichard Henderson         tcg_gen_xor_i32(ret, arg1, t0);
251951c6300SRichard Henderson         tcg_temp_free_i32(t0);
252951c6300SRichard Henderson     }
253951c6300SRichard Henderson }
254951c6300SRichard Henderson 
255951c6300SRichard Henderson void tcg_gen_shli_i32(TCGv_i32 ret, TCGv_i32 arg1, unsigned arg2)
256951c6300SRichard Henderson {
257951c6300SRichard Henderson     tcg_debug_assert(arg2 < 32);
258951c6300SRichard Henderson     if (arg2 == 0) {
259951c6300SRichard Henderson         tcg_gen_mov_i32(ret, arg1);
260951c6300SRichard Henderson     } else {
261951c6300SRichard Henderson         TCGv_i32 t0 = tcg_const_i32(arg2);
262951c6300SRichard Henderson         tcg_gen_shl_i32(ret, arg1, t0);
263951c6300SRichard Henderson         tcg_temp_free_i32(t0);
264951c6300SRichard Henderson     }
265951c6300SRichard Henderson }
266951c6300SRichard Henderson 
267951c6300SRichard Henderson void tcg_gen_shri_i32(TCGv_i32 ret, TCGv_i32 arg1, unsigned arg2)
268951c6300SRichard Henderson {
269951c6300SRichard Henderson     tcg_debug_assert(arg2 < 32);
270951c6300SRichard Henderson     if (arg2 == 0) {
271951c6300SRichard Henderson         tcg_gen_mov_i32(ret, arg1);
272951c6300SRichard Henderson     } else {
273951c6300SRichard Henderson         TCGv_i32 t0 = tcg_const_i32(arg2);
274951c6300SRichard Henderson         tcg_gen_shr_i32(ret, arg1, t0);
275951c6300SRichard Henderson         tcg_temp_free_i32(t0);
276951c6300SRichard Henderson     }
277951c6300SRichard Henderson }
278951c6300SRichard Henderson 
279951c6300SRichard Henderson void tcg_gen_sari_i32(TCGv_i32 ret, TCGv_i32 arg1, unsigned arg2)
280951c6300SRichard Henderson {
281951c6300SRichard Henderson     tcg_debug_assert(arg2 < 32);
282951c6300SRichard Henderson     if (arg2 == 0) {
283951c6300SRichard Henderson         tcg_gen_mov_i32(ret, arg1);
284951c6300SRichard Henderson     } else {
285951c6300SRichard Henderson         TCGv_i32 t0 = tcg_const_i32(arg2);
286951c6300SRichard Henderson         tcg_gen_sar_i32(ret, arg1, t0);
287951c6300SRichard Henderson         tcg_temp_free_i32(t0);
288951c6300SRichard Henderson     }
289951c6300SRichard Henderson }
290951c6300SRichard Henderson 
29142a268c2SRichard Henderson void tcg_gen_brcond_i32(TCGCond cond, TCGv_i32 arg1, TCGv_i32 arg2, TCGLabel *l)
292951c6300SRichard Henderson {
293951c6300SRichard Henderson     if (cond == TCG_COND_ALWAYS) {
29442a268c2SRichard Henderson         tcg_gen_br(l);
295951c6300SRichard Henderson     } else if (cond != TCG_COND_NEVER) {
29642a268c2SRichard Henderson         tcg_gen_op4ii_i32(INDEX_op_brcond_i32, arg1, arg2, cond, label_arg(l));
297951c6300SRichard Henderson     }
298951c6300SRichard Henderson }
299951c6300SRichard Henderson 
30042a268c2SRichard Henderson void tcg_gen_brcondi_i32(TCGCond cond, TCGv_i32 arg1, int32_t arg2, TCGLabel *l)
301951c6300SRichard Henderson {
30237ed3bf1SRichard Henderson     if (cond == TCG_COND_ALWAYS) {
30337ed3bf1SRichard Henderson         tcg_gen_br(l);
30437ed3bf1SRichard Henderson     } else if (cond != TCG_COND_NEVER) {
305951c6300SRichard Henderson         TCGv_i32 t0 = tcg_const_i32(arg2);
30642a268c2SRichard Henderson         tcg_gen_brcond_i32(cond, arg1, t0, l);
307951c6300SRichard Henderson         tcg_temp_free_i32(t0);
308951c6300SRichard Henderson     }
30937ed3bf1SRichard Henderson }
310951c6300SRichard Henderson 
311951c6300SRichard Henderson void tcg_gen_setcond_i32(TCGCond cond, TCGv_i32 ret,
312951c6300SRichard Henderson                          TCGv_i32 arg1, TCGv_i32 arg2)
313951c6300SRichard Henderson {
314951c6300SRichard Henderson     if (cond == TCG_COND_ALWAYS) {
315951c6300SRichard Henderson         tcg_gen_movi_i32(ret, 1);
316951c6300SRichard Henderson     } else if (cond == TCG_COND_NEVER) {
317951c6300SRichard Henderson         tcg_gen_movi_i32(ret, 0);
318951c6300SRichard Henderson     } else {
319951c6300SRichard Henderson         tcg_gen_op4i_i32(INDEX_op_setcond_i32, ret, arg1, arg2, cond);
320951c6300SRichard Henderson     }
321951c6300SRichard Henderson }
322951c6300SRichard Henderson 
323951c6300SRichard Henderson void tcg_gen_setcondi_i32(TCGCond cond, TCGv_i32 ret,
324951c6300SRichard Henderson                           TCGv_i32 arg1, int32_t arg2)
325951c6300SRichard Henderson {
326951c6300SRichard Henderson     TCGv_i32 t0 = tcg_const_i32(arg2);
327951c6300SRichard Henderson     tcg_gen_setcond_i32(cond, ret, arg1, t0);
328951c6300SRichard Henderson     tcg_temp_free_i32(t0);
329951c6300SRichard Henderson }
330951c6300SRichard Henderson 
331951c6300SRichard Henderson void tcg_gen_muli_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2)
332951c6300SRichard Henderson {
333951c6300SRichard Henderson     TCGv_i32 t0 = tcg_const_i32(arg2);
334951c6300SRichard Henderson     tcg_gen_mul_i32(ret, arg1, t0);
335951c6300SRichard Henderson     tcg_temp_free_i32(t0);
336951c6300SRichard Henderson }
337951c6300SRichard Henderson 
338951c6300SRichard Henderson void tcg_gen_div_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
339951c6300SRichard Henderson {
340951c6300SRichard Henderson     if (TCG_TARGET_HAS_div_i32) {
341951c6300SRichard Henderson         tcg_gen_op3_i32(INDEX_op_div_i32, ret, arg1, arg2);
342951c6300SRichard Henderson     } else if (TCG_TARGET_HAS_div2_i32) {
343951c6300SRichard Henderson         TCGv_i32 t0 = tcg_temp_new_i32();
344951c6300SRichard Henderson         tcg_gen_sari_i32(t0, arg1, 31);
345951c6300SRichard Henderson         tcg_gen_op5_i32(INDEX_op_div2_i32, ret, t0, arg1, t0, arg2);
346951c6300SRichard Henderson         tcg_temp_free_i32(t0);
347951c6300SRichard Henderson     } else {
348951c6300SRichard Henderson         gen_helper_div_i32(ret, arg1, arg2);
349951c6300SRichard Henderson     }
350951c6300SRichard Henderson }
351951c6300SRichard Henderson 
352951c6300SRichard Henderson void tcg_gen_rem_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
353951c6300SRichard Henderson {
354951c6300SRichard Henderson     if (TCG_TARGET_HAS_rem_i32) {
355951c6300SRichard Henderson         tcg_gen_op3_i32(INDEX_op_rem_i32, ret, arg1, arg2);
356951c6300SRichard Henderson     } else if (TCG_TARGET_HAS_div_i32) {
357951c6300SRichard Henderson         TCGv_i32 t0 = tcg_temp_new_i32();
358951c6300SRichard Henderson         tcg_gen_op3_i32(INDEX_op_div_i32, t0, arg1, arg2);
359951c6300SRichard Henderson         tcg_gen_mul_i32(t0, t0, arg2);
360951c6300SRichard Henderson         tcg_gen_sub_i32(ret, arg1, t0);
361951c6300SRichard Henderson         tcg_temp_free_i32(t0);
362951c6300SRichard Henderson     } else if (TCG_TARGET_HAS_div2_i32) {
363951c6300SRichard Henderson         TCGv_i32 t0 = tcg_temp_new_i32();
364951c6300SRichard Henderson         tcg_gen_sari_i32(t0, arg1, 31);
365951c6300SRichard Henderson         tcg_gen_op5_i32(INDEX_op_div2_i32, t0, ret, arg1, t0, arg2);
366951c6300SRichard Henderson         tcg_temp_free_i32(t0);
367951c6300SRichard Henderson     } else {
368951c6300SRichard Henderson         gen_helper_rem_i32(ret, arg1, arg2);
369951c6300SRichard Henderson     }
370951c6300SRichard Henderson }
371951c6300SRichard Henderson 
372951c6300SRichard Henderson void tcg_gen_divu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
373951c6300SRichard Henderson {
374951c6300SRichard Henderson     if (TCG_TARGET_HAS_div_i32) {
375951c6300SRichard Henderson         tcg_gen_op3_i32(INDEX_op_divu_i32, ret, arg1, arg2);
376951c6300SRichard Henderson     } else if (TCG_TARGET_HAS_div2_i32) {
377951c6300SRichard Henderson         TCGv_i32 t0 = tcg_temp_new_i32();
378951c6300SRichard Henderson         tcg_gen_movi_i32(t0, 0);
379951c6300SRichard Henderson         tcg_gen_op5_i32(INDEX_op_divu2_i32, ret, t0, arg1, t0, arg2);
380951c6300SRichard Henderson         tcg_temp_free_i32(t0);
381951c6300SRichard Henderson     } else {
382951c6300SRichard Henderson         gen_helper_divu_i32(ret, arg1, arg2);
383951c6300SRichard Henderson     }
384951c6300SRichard Henderson }
385951c6300SRichard Henderson 
386951c6300SRichard Henderson void tcg_gen_remu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
387951c6300SRichard Henderson {
388951c6300SRichard Henderson     if (TCG_TARGET_HAS_rem_i32) {
389951c6300SRichard Henderson         tcg_gen_op3_i32(INDEX_op_remu_i32, ret, arg1, arg2);
390951c6300SRichard Henderson     } else if (TCG_TARGET_HAS_div_i32) {
391951c6300SRichard Henderson         TCGv_i32 t0 = tcg_temp_new_i32();
392951c6300SRichard Henderson         tcg_gen_op3_i32(INDEX_op_divu_i32, t0, arg1, arg2);
393951c6300SRichard Henderson         tcg_gen_mul_i32(t0, t0, arg2);
394951c6300SRichard Henderson         tcg_gen_sub_i32(ret, arg1, t0);
395951c6300SRichard Henderson         tcg_temp_free_i32(t0);
396951c6300SRichard Henderson     } else if (TCG_TARGET_HAS_div2_i32) {
397951c6300SRichard Henderson         TCGv_i32 t0 = tcg_temp_new_i32();
398951c6300SRichard Henderson         tcg_gen_movi_i32(t0, 0);
399951c6300SRichard Henderson         tcg_gen_op5_i32(INDEX_op_divu2_i32, t0, ret, arg1, t0, arg2);
400951c6300SRichard Henderson         tcg_temp_free_i32(t0);
401951c6300SRichard Henderson     } else {
402951c6300SRichard Henderson         gen_helper_remu_i32(ret, arg1, arg2);
403951c6300SRichard Henderson     }
404951c6300SRichard Henderson }
405951c6300SRichard Henderson 
406951c6300SRichard Henderson void tcg_gen_andc_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
407951c6300SRichard Henderson {
408951c6300SRichard Henderson     if (TCG_TARGET_HAS_andc_i32) {
409951c6300SRichard Henderson         tcg_gen_op3_i32(INDEX_op_andc_i32, ret, arg1, arg2);
410951c6300SRichard Henderson     } else {
411951c6300SRichard Henderson         TCGv_i32 t0 = tcg_temp_new_i32();
412951c6300SRichard Henderson         tcg_gen_not_i32(t0, arg2);
413951c6300SRichard Henderson         tcg_gen_and_i32(ret, arg1, t0);
414951c6300SRichard Henderson         tcg_temp_free_i32(t0);
415951c6300SRichard Henderson     }
416951c6300SRichard Henderson }
417951c6300SRichard Henderson 
418951c6300SRichard Henderson void tcg_gen_eqv_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
419951c6300SRichard Henderson {
420951c6300SRichard Henderson     if (TCG_TARGET_HAS_eqv_i32) {
421951c6300SRichard Henderson         tcg_gen_op3_i32(INDEX_op_eqv_i32, ret, arg1, arg2);
422951c6300SRichard Henderson     } else {
423951c6300SRichard Henderson         tcg_gen_xor_i32(ret, arg1, arg2);
424951c6300SRichard Henderson         tcg_gen_not_i32(ret, ret);
425951c6300SRichard Henderson     }
426951c6300SRichard Henderson }
427951c6300SRichard Henderson 
428951c6300SRichard Henderson void tcg_gen_nand_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
429951c6300SRichard Henderson {
430951c6300SRichard Henderson     if (TCG_TARGET_HAS_nand_i32) {
431951c6300SRichard Henderson         tcg_gen_op3_i32(INDEX_op_nand_i32, ret, arg1, arg2);
432951c6300SRichard Henderson     } else {
433951c6300SRichard Henderson         tcg_gen_and_i32(ret, arg1, arg2);
434951c6300SRichard Henderson         tcg_gen_not_i32(ret, ret);
435951c6300SRichard Henderson     }
436951c6300SRichard Henderson }
437951c6300SRichard Henderson 
438951c6300SRichard Henderson void tcg_gen_nor_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
439951c6300SRichard Henderson {
440951c6300SRichard Henderson     if (TCG_TARGET_HAS_nor_i32) {
441951c6300SRichard Henderson         tcg_gen_op3_i32(INDEX_op_nor_i32, ret, arg1, arg2);
442951c6300SRichard Henderson     } else {
443951c6300SRichard Henderson         tcg_gen_or_i32(ret, arg1, arg2);
444951c6300SRichard Henderson         tcg_gen_not_i32(ret, ret);
445951c6300SRichard Henderson     }
446951c6300SRichard Henderson }
447951c6300SRichard Henderson 
448951c6300SRichard Henderson void tcg_gen_orc_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
449951c6300SRichard Henderson {
450951c6300SRichard Henderson     if (TCG_TARGET_HAS_orc_i32) {
451951c6300SRichard Henderson         tcg_gen_op3_i32(INDEX_op_orc_i32, ret, arg1, arg2);
452951c6300SRichard Henderson     } else {
453951c6300SRichard Henderson         TCGv_i32 t0 = tcg_temp_new_i32();
454951c6300SRichard Henderson         tcg_gen_not_i32(t0, arg2);
455951c6300SRichard Henderson         tcg_gen_or_i32(ret, arg1, t0);
456951c6300SRichard Henderson         tcg_temp_free_i32(t0);
457951c6300SRichard Henderson     }
458951c6300SRichard Henderson }
459951c6300SRichard Henderson 
4600e28d006SRichard Henderson void tcg_gen_clz_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
4610e28d006SRichard Henderson {
4620e28d006SRichard Henderson     if (TCG_TARGET_HAS_clz_i32) {
4630e28d006SRichard Henderson         tcg_gen_op3_i32(INDEX_op_clz_i32, ret, arg1, arg2);
4640e28d006SRichard Henderson     } else if (TCG_TARGET_HAS_clz_i64) {
4650e28d006SRichard Henderson         TCGv_i64 t1 = tcg_temp_new_i64();
4660e28d006SRichard Henderson         TCGv_i64 t2 = tcg_temp_new_i64();
4670e28d006SRichard Henderson         tcg_gen_extu_i32_i64(t1, arg1);
4680e28d006SRichard Henderson         tcg_gen_extu_i32_i64(t2, arg2);
4690e28d006SRichard Henderson         tcg_gen_addi_i64(t2, t2, 32);
4700e28d006SRichard Henderson         tcg_gen_clz_i64(t1, t1, t2);
4710e28d006SRichard Henderson         tcg_gen_extrl_i64_i32(ret, t1);
4720e28d006SRichard Henderson         tcg_temp_free_i64(t1);
4730e28d006SRichard Henderson         tcg_temp_free_i64(t2);
4740e28d006SRichard Henderson         tcg_gen_subi_i32(ret, ret, 32);
4750e28d006SRichard Henderson     } else {
4760e28d006SRichard Henderson         gen_helper_clz_i32(ret, arg1, arg2);
4770e28d006SRichard Henderson     }
4780e28d006SRichard Henderson }
4790e28d006SRichard Henderson 
4800e28d006SRichard Henderson void tcg_gen_clzi_i32(TCGv_i32 ret, TCGv_i32 arg1, uint32_t arg2)
4810e28d006SRichard Henderson {
4820e28d006SRichard Henderson     TCGv_i32 t = tcg_const_i32(arg2);
4830e28d006SRichard Henderson     tcg_gen_clz_i32(ret, arg1, t);
4840e28d006SRichard Henderson     tcg_temp_free_i32(t);
4850e28d006SRichard Henderson }
4860e28d006SRichard Henderson 
4870e28d006SRichard Henderson void tcg_gen_ctz_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
4880e28d006SRichard Henderson {
4890e28d006SRichard Henderson     if (TCG_TARGET_HAS_ctz_i32) {
4900e28d006SRichard Henderson         tcg_gen_op3_i32(INDEX_op_ctz_i32, ret, arg1, arg2);
4910e28d006SRichard Henderson     } else if (TCG_TARGET_HAS_ctz_i64) {
4920e28d006SRichard Henderson         TCGv_i64 t1 = tcg_temp_new_i64();
4930e28d006SRichard Henderson         TCGv_i64 t2 = tcg_temp_new_i64();
4940e28d006SRichard Henderson         tcg_gen_extu_i32_i64(t1, arg1);
4950e28d006SRichard Henderson         tcg_gen_extu_i32_i64(t2, arg2);
4960e28d006SRichard Henderson         tcg_gen_ctz_i64(t1, t1, t2);
4970e28d006SRichard Henderson         tcg_gen_extrl_i64_i32(ret, t1);
4980e28d006SRichard Henderson         tcg_temp_free_i64(t1);
4990e28d006SRichard Henderson         tcg_temp_free_i64(t2);
50014e99210SRichard Henderson     } else if (TCG_TARGET_HAS_ctpop_i32
50114e99210SRichard Henderson                || TCG_TARGET_HAS_ctpop_i64
50214e99210SRichard Henderson                || TCG_TARGET_HAS_clz_i32
50314e99210SRichard Henderson                || TCG_TARGET_HAS_clz_i64) {
50414e99210SRichard Henderson         TCGv_i32 z, t = tcg_temp_new_i32();
50514e99210SRichard Henderson 
50614e99210SRichard Henderson         if (TCG_TARGET_HAS_ctpop_i32 || TCG_TARGET_HAS_ctpop_i64) {
50714e99210SRichard Henderson             tcg_gen_subi_i32(t, arg1, 1);
50814e99210SRichard Henderson             tcg_gen_andc_i32(t, t, arg1);
50914e99210SRichard Henderson             tcg_gen_ctpop_i32(t, t);
51014e99210SRichard Henderson         } else {
51114e99210SRichard Henderson             /* Since all non-x86 hosts have clz(0) == 32, don't fight it.  */
51214e99210SRichard Henderson             tcg_gen_neg_i32(t, arg1);
51314e99210SRichard Henderson             tcg_gen_and_i32(t, t, arg1);
51414e99210SRichard Henderson             tcg_gen_clzi_i32(t, t, 32);
51514e99210SRichard Henderson             tcg_gen_xori_i32(t, t, 31);
51614e99210SRichard Henderson         }
51714e99210SRichard Henderson         z = tcg_const_i32(0);
51814e99210SRichard Henderson         tcg_gen_movcond_i32(TCG_COND_EQ, ret, arg1, z, arg2, t);
51914e99210SRichard Henderson         tcg_temp_free_i32(t);
52014e99210SRichard Henderson         tcg_temp_free_i32(z);
5210e28d006SRichard Henderson     } else {
5220e28d006SRichard Henderson         gen_helper_ctz_i32(ret, arg1, arg2);
5230e28d006SRichard Henderson     }
5240e28d006SRichard Henderson }
5250e28d006SRichard Henderson 
5260e28d006SRichard Henderson void tcg_gen_ctzi_i32(TCGv_i32 ret, TCGv_i32 arg1, uint32_t arg2)
5270e28d006SRichard Henderson {
52814e99210SRichard Henderson     if (!TCG_TARGET_HAS_ctz_i32 && TCG_TARGET_HAS_ctpop_i32 && arg2 == 32) {
52914e99210SRichard Henderson         /* This equivalence has the advantage of not requiring a fixup.  */
53014e99210SRichard Henderson         TCGv_i32 t = tcg_temp_new_i32();
53114e99210SRichard Henderson         tcg_gen_subi_i32(t, arg1, 1);
53214e99210SRichard Henderson         tcg_gen_andc_i32(t, t, arg1);
53314e99210SRichard Henderson         tcg_gen_ctpop_i32(ret, t);
53414e99210SRichard Henderson         tcg_temp_free_i32(t);
53514e99210SRichard Henderson     } else {
5360e28d006SRichard Henderson         TCGv_i32 t = tcg_const_i32(arg2);
5370e28d006SRichard Henderson         tcg_gen_ctz_i32(ret, arg1, t);
5380e28d006SRichard Henderson         tcg_temp_free_i32(t);
5390e28d006SRichard Henderson     }
54014e99210SRichard Henderson }
5410e28d006SRichard Henderson 
542086920c2SRichard Henderson void tcg_gen_clrsb_i32(TCGv_i32 ret, TCGv_i32 arg)
543086920c2SRichard Henderson {
544086920c2SRichard Henderson     if (TCG_TARGET_HAS_clz_i32) {
545086920c2SRichard Henderson         TCGv_i32 t = tcg_temp_new_i32();
546086920c2SRichard Henderson         tcg_gen_sari_i32(t, arg, 31);
547086920c2SRichard Henderson         tcg_gen_xor_i32(t, t, arg);
548086920c2SRichard Henderson         tcg_gen_clzi_i32(t, t, 32);
549086920c2SRichard Henderson         tcg_gen_subi_i32(ret, t, 1);
550086920c2SRichard Henderson         tcg_temp_free_i32(t);
551086920c2SRichard Henderson     } else {
552086920c2SRichard Henderson         gen_helper_clrsb_i32(ret, arg);
553086920c2SRichard Henderson     }
554086920c2SRichard Henderson }
555086920c2SRichard Henderson 
556a768e4e9SRichard Henderson void tcg_gen_ctpop_i32(TCGv_i32 ret, TCGv_i32 arg1)
557a768e4e9SRichard Henderson {
558a768e4e9SRichard Henderson     if (TCG_TARGET_HAS_ctpop_i32) {
559a768e4e9SRichard Henderson         tcg_gen_op2_i32(INDEX_op_ctpop_i32, ret, arg1);
560a768e4e9SRichard Henderson     } else if (TCG_TARGET_HAS_ctpop_i64) {
561a768e4e9SRichard Henderson         TCGv_i64 t = tcg_temp_new_i64();
562a768e4e9SRichard Henderson         tcg_gen_extu_i32_i64(t, arg1);
563a768e4e9SRichard Henderson         tcg_gen_ctpop_i64(t, t);
564a768e4e9SRichard Henderson         tcg_gen_extrl_i64_i32(ret, t);
565a768e4e9SRichard Henderson         tcg_temp_free_i64(t);
566a768e4e9SRichard Henderson     } else {
567a768e4e9SRichard Henderson         gen_helper_ctpop_i32(ret, arg1);
568a768e4e9SRichard Henderson     }
569a768e4e9SRichard Henderson }
570a768e4e9SRichard Henderson 
571951c6300SRichard Henderson void tcg_gen_rotl_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
572951c6300SRichard Henderson {
573951c6300SRichard Henderson     if (TCG_TARGET_HAS_rot_i32) {
574951c6300SRichard Henderson         tcg_gen_op3_i32(INDEX_op_rotl_i32, ret, arg1, arg2);
575951c6300SRichard Henderson     } else {
576951c6300SRichard Henderson         TCGv_i32 t0, t1;
577951c6300SRichard Henderson 
578951c6300SRichard Henderson         t0 = tcg_temp_new_i32();
579951c6300SRichard Henderson         t1 = tcg_temp_new_i32();
580951c6300SRichard Henderson         tcg_gen_shl_i32(t0, arg1, arg2);
581951c6300SRichard Henderson         tcg_gen_subfi_i32(t1, 32, arg2);
582951c6300SRichard Henderson         tcg_gen_shr_i32(t1, arg1, t1);
583951c6300SRichard Henderson         tcg_gen_or_i32(ret, t0, t1);
584951c6300SRichard Henderson         tcg_temp_free_i32(t0);
585951c6300SRichard Henderson         tcg_temp_free_i32(t1);
586951c6300SRichard Henderson     }
587951c6300SRichard Henderson }
588951c6300SRichard Henderson 
589951c6300SRichard Henderson void tcg_gen_rotli_i32(TCGv_i32 ret, TCGv_i32 arg1, unsigned arg2)
590951c6300SRichard Henderson {
591951c6300SRichard Henderson     tcg_debug_assert(arg2 < 32);
592951c6300SRichard Henderson     /* some cases can be optimized here */
593951c6300SRichard Henderson     if (arg2 == 0) {
594951c6300SRichard Henderson         tcg_gen_mov_i32(ret, arg1);
595951c6300SRichard Henderson     } else if (TCG_TARGET_HAS_rot_i32) {
596951c6300SRichard Henderson         TCGv_i32 t0 = tcg_const_i32(arg2);
597951c6300SRichard Henderson         tcg_gen_rotl_i32(ret, arg1, t0);
598951c6300SRichard Henderson         tcg_temp_free_i32(t0);
599951c6300SRichard Henderson     } else {
600951c6300SRichard Henderson         TCGv_i32 t0, t1;
601951c6300SRichard Henderson         t0 = tcg_temp_new_i32();
602951c6300SRichard Henderson         t1 = tcg_temp_new_i32();
603951c6300SRichard Henderson         tcg_gen_shli_i32(t0, arg1, arg2);
604951c6300SRichard Henderson         tcg_gen_shri_i32(t1, arg1, 32 - arg2);
605951c6300SRichard Henderson         tcg_gen_or_i32(ret, t0, t1);
606951c6300SRichard Henderson         tcg_temp_free_i32(t0);
607951c6300SRichard Henderson         tcg_temp_free_i32(t1);
608951c6300SRichard Henderson     }
609951c6300SRichard Henderson }
610951c6300SRichard Henderson 
611951c6300SRichard Henderson void tcg_gen_rotr_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
612951c6300SRichard Henderson {
613951c6300SRichard Henderson     if (TCG_TARGET_HAS_rot_i32) {
614951c6300SRichard Henderson         tcg_gen_op3_i32(INDEX_op_rotr_i32, ret, arg1, arg2);
615951c6300SRichard Henderson     } else {
616951c6300SRichard Henderson         TCGv_i32 t0, t1;
617951c6300SRichard Henderson 
618951c6300SRichard Henderson         t0 = tcg_temp_new_i32();
619951c6300SRichard Henderson         t1 = tcg_temp_new_i32();
620951c6300SRichard Henderson         tcg_gen_shr_i32(t0, arg1, arg2);
621951c6300SRichard Henderson         tcg_gen_subfi_i32(t1, 32, arg2);
622951c6300SRichard Henderson         tcg_gen_shl_i32(t1, arg1, t1);
623951c6300SRichard Henderson         tcg_gen_or_i32(ret, t0, t1);
624951c6300SRichard Henderson         tcg_temp_free_i32(t0);
625951c6300SRichard Henderson         tcg_temp_free_i32(t1);
626951c6300SRichard Henderson     }
627951c6300SRichard Henderson }
628951c6300SRichard Henderson 
629951c6300SRichard Henderson void tcg_gen_rotri_i32(TCGv_i32 ret, TCGv_i32 arg1, unsigned arg2)
630951c6300SRichard Henderson {
631951c6300SRichard Henderson     tcg_debug_assert(arg2 < 32);
632951c6300SRichard Henderson     /* some cases can be optimized here */
633951c6300SRichard Henderson     if (arg2 == 0) {
634951c6300SRichard Henderson         tcg_gen_mov_i32(ret, arg1);
635951c6300SRichard Henderson     } else {
636951c6300SRichard Henderson         tcg_gen_rotli_i32(ret, arg1, 32 - arg2);
637951c6300SRichard Henderson     }
638951c6300SRichard Henderson }
639951c6300SRichard Henderson 
640951c6300SRichard Henderson void tcg_gen_deposit_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2,
641951c6300SRichard Henderson                          unsigned int ofs, unsigned int len)
642951c6300SRichard Henderson {
643951c6300SRichard Henderson     uint32_t mask;
644951c6300SRichard Henderson     TCGv_i32 t1;
645951c6300SRichard Henderson 
646951c6300SRichard Henderson     tcg_debug_assert(ofs < 32);
6470d0d309dSRichard Henderson     tcg_debug_assert(len > 0);
648951c6300SRichard Henderson     tcg_debug_assert(len <= 32);
649951c6300SRichard Henderson     tcg_debug_assert(ofs + len <= 32);
650951c6300SRichard Henderson 
6510d0d309dSRichard Henderson     if (len == 32) {
652951c6300SRichard Henderson         tcg_gen_mov_i32(ret, arg2);
653951c6300SRichard Henderson         return;
654951c6300SRichard Henderson     }
655951c6300SRichard Henderson     if (TCG_TARGET_HAS_deposit_i32 && TCG_TARGET_deposit_i32_valid(ofs, len)) {
656951c6300SRichard Henderson         tcg_gen_op5ii_i32(INDEX_op_deposit_i32, ret, arg1, arg2, ofs, len);
657951c6300SRichard Henderson         return;
658951c6300SRichard Henderson     }
659951c6300SRichard Henderson 
660951c6300SRichard Henderson     mask = (1u << len) - 1;
661951c6300SRichard Henderson     t1 = tcg_temp_new_i32();
662951c6300SRichard Henderson 
663951c6300SRichard Henderson     if (ofs + len < 32) {
664951c6300SRichard Henderson         tcg_gen_andi_i32(t1, arg2, mask);
665951c6300SRichard Henderson         tcg_gen_shli_i32(t1, t1, ofs);
666951c6300SRichard Henderson     } else {
667951c6300SRichard Henderson         tcg_gen_shli_i32(t1, arg2, ofs);
668951c6300SRichard Henderson     }
669951c6300SRichard Henderson     tcg_gen_andi_i32(ret, arg1, ~(mask << ofs));
670951c6300SRichard Henderson     tcg_gen_or_i32(ret, ret, t1);
671951c6300SRichard Henderson 
672951c6300SRichard Henderson     tcg_temp_free_i32(t1);
673951c6300SRichard Henderson }
674951c6300SRichard Henderson 
67507cc68d5SRichard Henderson void tcg_gen_deposit_z_i32(TCGv_i32 ret, TCGv_i32 arg,
67607cc68d5SRichard Henderson                            unsigned int ofs, unsigned int len)
67707cc68d5SRichard Henderson {
67807cc68d5SRichard Henderson     tcg_debug_assert(ofs < 32);
67907cc68d5SRichard Henderson     tcg_debug_assert(len > 0);
68007cc68d5SRichard Henderson     tcg_debug_assert(len <= 32);
68107cc68d5SRichard Henderson     tcg_debug_assert(ofs + len <= 32);
68207cc68d5SRichard Henderson 
68307cc68d5SRichard Henderson     if (ofs + len == 32) {
68407cc68d5SRichard Henderson         tcg_gen_shli_i32(ret, arg, ofs);
68507cc68d5SRichard Henderson     } else if (ofs == 0) {
68607cc68d5SRichard Henderson         tcg_gen_andi_i32(ret, arg, (1u << len) - 1);
68707cc68d5SRichard Henderson     } else if (TCG_TARGET_HAS_deposit_i32
68807cc68d5SRichard Henderson                && TCG_TARGET_deposit_i32_valid(ofs, len)) {
68907cc68d5SRichard Henderson         TCGv_i32 zero = tcg_const_i32(0);
69007cc68d5SRichard Henderson         tcg_gen_op5ii_i32(INDEX_op_deposit_i32, ret, zero, arg, ofs, len);
69107cc68d5SRichard Henderson         tcg_temp_free_i32(zero);
69207cc68d5SRichard Henderson     } else {
69307cc68d5SRichard Henderson         /* To help two-operand hosts we prefer to zero-extend first,
69407cc68d5SRichard Henderson            which allows ARG to stay live.  */
69507cc68d5SRichard Henderson         switch (len) {
69607cc68d5SRichard Henderson         case 16:
69707cc68d5SRichard Henderson             if (TCG_TARGET_HAS_ext16u_i32) {
69807cc68d5SRichard Henderson                 tcg_gen_ext16u_i32(ret, arg);
69907cc68d5SRichard Henderson                 tcg_gen_shli_i32(ret, ret, ofs);
70007cc68d5SRichard Henderson                 return;
70107cc68d5SRichard Henderson             }
70207cc68d5SRichard Henderson             break;
70307cc68d5SRichard Henderson         case 8:
70407cc68d5SRichard Henderson             if (TCG_TARGET_HAS_ext8u_i32) {
70507cc68d5SRichard Henderson                 tcg_gen_ext8u_i32(ret, arg);
70607cc68d5SRichard Henderson                 tcg_gen_shli_i32(ret, ret, ofs);
70707cc68d5SRichard Henderson                 return;
70807cc68d5SRichard Henderson             }
70907cc68d5SRichard Henderson             break;
71007cc68d5SRichard Henderson         }
71107cc68d5SRichard Henderson         /* Otherwise prefer zero-extension over AND for code size.  */
71207cc68d5SRichard Henderson         switch (ofs + len) {
71307cc68d5SRichard Henderson         case 16:
71407cc68d5SRichard Henderson             if (TCG_TARGET_HAS_ext16u_i32) {
71507cc68d5SRichard Henderson                 tcg_gen_shli_i32(ret, arg, ofs);
71607cc68d5SRichard Henderson                 tcg_gen_ext16u_i32(ret, ret);
71707cc68d5SRichard Henderson                 return;
71807cc68d5SRichard Henderson             }
71907cc68d5SRichard Henderson             break;
72007cc68d5SRichard Henderson         case 8:
72107cc68d5SRichard Henderson             if (TCG_TARGET_HAS_ext8u_i32) {
72207cc68d5SRichard Henderson                 tcg_gen_shli_i32(ret, arg, ofs);
72307cc68d5SRichard Henderson                 tcg_gen_ext8u_i32(ret, ret);
72407cc68d5SRichard Henderson                 return;
72507cc68d5SRichard Henderson             }
72607cc68d5SRichard Henderson             break;
72707cc68d5SRichard Henderson         }
72807cc68d5SRichard Henderson         tcg_gen_andi_i32(ret, arg, (1u << len) - 1);
72907cc68d5SRichard Henderson         tcg_gen_shli_i32(ret, ret, ofs);
73007cc68d5SRichard Henderson     }
73107cc68d5SRichard Henderson }
73207cc68d5SRichard Henderson 
7337ec8bab3SRichard Henderson void tcg_gen_extract_i32(TCGv_i32 ret, TCGv_i32 arg,
7347ec8bab3SRichard Henderson                          unsigned int ofs, unsigned int len)
7357ec8bab3SRichard Henderson {
7367ec8bab3SRichard Henderson     tcg_debug_assert(ofs < 32);
7377ec8bab3SRichard Henderson     tcg_debug_assert(len > 0);
7387ec8bab3SRichard Henderson     tcg_debug_assert(len <= 32);
7397ec8bab3SRichard Henderson     tcg_debug_assert(ofs + len <= 32);
7407ec8bab3SRichard Henderson 
7417ec8bab3SRichard Henderson     /* Canonicalize certain special cases, even if extract is supported.  */
7427ec8bab3SRichard Henderson     if (ofs + len == 32) {
7437ec8bab3SRichard Henderson         tcg_gen_shri_i32(ret, arg, 32 - len);
7447ec8bab3SRichard Henderson         return;
7457ec8bab3SRichard Henderson     }
7467ec8bab3SRichard Henderson     if (ofs == 0) {
7477ec8bab3SRichard Henderson         tcg_gen_andi_i32(ret, arg, (1u << len) - 1);
7487ec8bab3SRichard Henderson         return;
7497ec8bab3SRichard Henderson     }
7507ec8bab3SRichard Henderson 
7517ec8bab3SRichard Henderson     if (TCG_TARGET_HAS_extract_i32
7527ec8bab3SRichard Henderson         && TCG_TARGET_extract_i32_valid(ofs, len)) {
7537ec8bab3SRichard Henderson         tcg_gen_op4ii_i32(INDEX_op_extract_i32, ret, arg, ofs, len);
7547ec8bab3SRichard Henderson         return;
7557ec8bab3SRichard Henderson     }
7567ec8bab3SRichard Henderson 
7577ec8bab3SRichard Henderson     /* Assume that zero-extension, if available, is cheaper than a shift.  */
7587ec8bab3SRichard Henderson     switch (ofs + len) {
7597ec8bab3SRichard Henderson     case 16:
7607ec8bab3SRichard Henderson         if (TCG_TARGET_HAS_ext16u_i32) {
7617ec8bab3SRichard Henderson             tcg_gen_ext16u_i32(ret, arg);
7627ec8bab3SRichard Henderson             tcg_gen_shri_i32(ret, ret, ofs);
7637ec8bab3SRichard Henderson             return;
7647ec8bab3SRichard Henderson         }
7657ec8bab3SRichard Henderson         break;
7667ec8bab3SRichard Henderson     case 8:
7677ec8bab3SRichard Henderson         if (TCG_TARGET_HAS_ext8u_i32) {
7687ec8bab3SRichard Henderson             tcg_gen_ext8u_i32(ret, arg);
7697ec8bab3SRichard Henderson             tcg_gen_shri_i32(ret, ret, ofs);
7707ec8bab3SRichard Henderson             return;
7717ec8bab3SRichard Henderson         }
7727ec8bab3SRichard Henderson         break;
7737ec8bab3SRichard Henderson     }
7747ec8bab3SRichard Henderson 
7757ec8bab3SRichard Henderson     /* ??? Ideally we'd know what values are available for immediate AND.
7767ec8bab3SRichard Henderson        Assume that 8 bits are available, plus the special case of 16,
7777ec8bab3SRichard Henderson        so that we get ext8u, ext16u.  */
7787ec8bab3SRichard Henderson     switch (len) {
7797ec8bab3SRichard Henderson     case 1 ... 8: case 16:
7807ec8bab3SRichard Henderson         tcg_gen_shri_i32(ret, arg, ofs);
7817ec8bab3SRichard Henderson         tcg_gen_andi_i32(ret, ret, (1u << len) - 1);
7827ec8bab3SRichard Henderson         break;
7837ec8bab3SRichard Henderson     default:
7847ec8bab3SRichard Henderson         tcg_gen_shli_i32(ret, arg, 32 - len - ofs);
7857ec8bab3SRichard Henderson         tcg_gen_shri_i32(ret, ret, 32 - len);
7867ec8bab3SRichard Henderson         break;
7877ec8bab3SRichard Henderson     }
7887ec8bab3SRichard Henderson }
7897ec8bab3SRichard Henderson 
7907ec8bab3SRichard Henderson void tcg_gen_sextract_i32(TCGv_i32 ret, TCGv_i32 arg,
7917ec8bab3SRichard Henderson                           unsigned int ofs, unsigned int len)
7927ec8bab3SRichard Henderson {
7937ec8bab3SRichard Henderson     tcg_debug_assert(ofs < 32);
7947ec8bab3SRichard Henderson     tcg_debug_assert(len > 0);
7957ec8bab3SRichard Henderson     tcg_debug_assert(len <= 32);
7967ec8bab3SRichard Henderson     tcg_debug_assert(ofs + len <= 32);
7977ec8bab3SRichard Henderson 
7987ec8bab3SRichard Henderson     /* Canonicalize certain special cases, even if extract is supported.  */
7997ec8bab3SRichard Henderson     if (ofs + len == 32) {
8007ec8bab3SRichard Henderson         tcg_gen_sari_i32(ret, arg, 32 - len);
8017ec8bab3SRichard Henderson         return;
8027ec8bab3SRichard Henderson     }
8037ec8bab3SRichard Henderson     if (ofs == 0) {
8047ec8bab3SRichard Henderson         switch (len) {
8057ec8bab3SRichard Henderson         case 16:
8067ec8bab3SRichard Henderson             tcg_gen_ext16s_i32(ret, arg);
8077ec8bab3SRichard Henderson             return;
8087ec8bab3SRichard Henderson         case 8:
8097ec8bab3SRichard Henderson             tcg_gen_ext8s_i32(ret, arg);
8107ec8bab3SRichard Henderson             return;
8117ec8bab3SRichard Henderson         }
8127ec8bab3SRichard Henderson     }
8137ec8bab3SRichard Henderson 
8147ec8bab3SRichard Henderson     if (TCG_TARGET_HAS_sextract_i32
8157ec8bab3SRichard Henderson         && TCG_TARGET_extract_i32_valid(ofs, len)) {
8167ec8bab3SRichard Henderson         tcg_gen_op4ii_i32(INDEX_op_sextract_i32, ret, arg, ofs, len);
8177ec8bab3SRichard Henderson         return;
8187ec8bab3SRichard Henderson     }
8197ec8bab3SRichard Henderson 
8207ec8bab3SRichard Henderson     /* Assume that sign-extension, if available, is cheaper than a shift.  */
8217ec8bab3SRichard Henderson     switch (ofs + len) {
8227ec8bab3SRichard Henderson     case 16:
8237ec8bab3SRichard Henderson         if (TCG_TARGET_HAS_ext16s_i32) {
8247ec8bab3SRichard Henderson             tcg_gen_ext16s_i32(ret, arg);
8257ec8bab3SRichard Henderson             tcg_gen_sari_i32(ret, ret, ofs);
8267ec8bab3SRichard Henderson             return;
8277ec8bab3SRichard Henderson         }
8287ec8bab3SRichard Henderson         break;
8297ec8bab3SRichard Henderson     case 8:
8307ec8bab3SRichard Henderson         if (TCG_TARGET_HAS_ext8s_i32) {
8317ec8bab3SRichard Henderson             tcg_gen_ext8s_i32(ret, arg);
8327ec8bab3SRichard Henderson             tcg_gen_sari_i32(ret, ret, ofs);
8337ec8bab3SRichard Henderson             return;
8347ec8bab3SRichard Henderson         }
8357ec8bab3SRichard Henderson         break;
8367ec8bab3SRichard Henderson     }
8377ec8bab3SRichard Henderson     switch (len) {
8387ec8bab3SRichard Henderson     case 16:
8397ec8bab3SRichard Henderson         if (TCG_TARGET_HAS_ext16s_i32) {
8407ec8bab3SRichard Henderson             tcg_gen_shri_i32(ret, arg, ofs);
8417ec8bab3SRichard Henderson             tcg_gen_ext16s_i32(ret, ret);
8427ec8bab3SRichard Henderson             return;
8437ec8bab3SRichard Henderson         }
8447ec8bab3SRichard Henderson         break;
8457ec8bab3SRichard Henderson     case 8:
8467ec8bab3SRichard Henderson         if (TCG_TARGET_HAS_ext8s_i32) {
8477ec8bab3SRichard Henderson             tcg_gen_shri_i32(ret, arg, ofs);
8487ec8bab3SRichard Henderson             tcg_gen_ext8s_i32(ret, ret);
8497ec8bab3SRichard Henderson             return;
8507ec8bab3SRichard Henderson         }
8517ec8bab3SRichard Henderson         break;
8527ec8bab3SRichard Henderson     }
8537ec8bab3SRichard Henderson 
8547ec8bab3SRichard Henderson     tcg_gen_shli_i32(ret, arg, 32 - len - ofs);
8557ec8bab3SRichard Henderson     tcg_gen_sari_i32(ret, ret, 32 - len);
8567ec8bab3SRichard Henderson }
8577ec8bab3SRichard Henderson 
858951c6300SRichard Henderson void tcg_gen_movcond_i32(TCGCond cond, TCGv_i32 ret, TCGv_i32 c1,
859951c6300SRichard Henderson                          TCGv_i32 c2, TCGv_i32 v1, TCGv_i32 v2)
860951c6300SRichard Henderson {
86137ed3bf1SRichard Henderson     if (cond == TCG_COND_ALWAYS) {
86237ed3bf1SRichard Henderson         tcg_gen_mov_i32(ret, v1);
86337ed3bf1SRichard Henderson     } else if (cond == TCG_COND_NEVER) {
86437ed3bf1SRichard Henderson         tcg_gen_mov_i32(ret, v2);
86537ed3bf1SRichard Henderson     } else if (TCG_TARGET_HAS_movcond_i32) {
866951c6300SRichard Henderson         tcg_gen_op6i_i32(INDEX_op_movcond_i32, ret, c1, c2, v1, v2, cond);
867951c6300SRichard Henderson     } else {
868951c6300SRichard Henderson         TCGv_i32 t0 = tcg_temp_new_i32();
869951c6300SRichard Henderson         TCGv_i32 t1 = tcg_temp_new_i32();
870951c6300SRichard Henderson         tcg_gen_setcond_i32(cond, t0, c1, c2);
871951c6300SRichard Henderson         tcg_gen_neg_i32(t0, t0);
872951c6300SRichard Henderson         tcg_gen_and_i32(t1, v1, t0);
873951c6300SRichard Henderson         tcg_gen_andc_i32(ret, v2, t0);
874951c6300SRichard Henderson         tcg_gen_or_i32(ret, ret, t1);
875951c6300SRichard Henderson         tcg_temp_free_i32(t0);
876951c6300SRichard Henderson         tcg_temp_free_i32(t1);
877951c6300SRichard Henderson     }
878951c6300SRichard Henderson }
879951c6300SRichard Henderson 
880951c6300SRichard Henderson void tcg_gen_add2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 al,
881951c6300SRichard Henderson                       TCGv_i32 ah, TCGv_i32 bl, TCGv_i32 bh)
882951c6300SRichard Henderson {
883951c6300SRichard Henderson     if (TCG_TARGET_HAS_add2_i32) {
884951c6300SRichard Henderson         tcg_gen_op6_i32(INDEX_op_add2_i32, rl, rh, al, ah, bl, bh);
885951c6300SRichard Henderson     } else {
886951c6300SRichard Henderson         TCGv_i64 t0 = tcg_temp_new_i64();
887951c6300SRichard Henderson         TCGv_i64 t1 = tcg_temp_new_i64();
888951c6300SRichard Henderson         tcg_gen_concat_i32_i64(t0, al, ah);
889951c6300SRichard Henderson         tcg_gen_concat_i32_i64(t1, bl, bh);
890951c6300SRichard Henderson         tcg_gen_add_i64(t0, t0, t1);
891951c6300SRichard Henderson         tcg_gen_extr_i64_i32(rl, rh, t0);
892951c6300SRichard Henderson         tcg_temp_free_i64(t0);
893951c6300SRichard Henderson         tcg_temp_free_i64(t1);
894951c6300SRichard Henderson     }
895951c6300SRichard Henderson }
896951c6300SRichard Henderson 
897951c6300SRichard Henderson void tcg_gen_sub2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 al,
898951c6300SRichard Henderson                       TCGv_i32 ah, TCGv_i32 bl, TCGv_i32 bh)
899951c6300SRichard Henderson {
900951c6300SRichard Henderson     if (TCG_TARGET_HAS_sub2_i32) {
901951c6300SRichard Henderson         tcg_gen_op6_i32(INDEX_op_sub2_i32, rl, rh, al, ah, bl, bh);
902951c6300SRichard Henderson     } else {
903951c6300SRichard Henderson         TCGv_i64 t0 = tcg_temp_new_i64();
904951c6300SRichard Henderson         TCGv_i64 t1 = tcg_temp_new_i64();
905951c6300SRichard Henderson         tcg_gen_concat_i32_i64(t0, al, ah);
906951c6300SRichard Henderson         tcg_gen_concat_i32_i64(t1, bl, bh);
907951c6300SRichard Henderson         tcg_gen_sub_i64(t0, t0, t1);
908951c6300SRichard Henderson         tcg_gen_extr_i64_i32(rl, rh, t0);
909951c6300SRichard Henderson         tcg_temp_free_i64(t0);
910951c6300SRichard Henderson         tcg_temp_free_i64(t1);
911951c6300SRichard Henderson     }
912951c6300SRichard Henderson }
913951c6300SRichard Henderson 
914951c6300SRichard Henderson void tcg_gen_mulu2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 arg1, TCGv_i32 arg2)
915951c6300SRichard Henderson {
916951c6300SRichard Henderson     if (TCG_TARGET_HAS_mulu2_i32) {
917951c6300SRichard Henderson         tcg_gen_op4_i32(INDEX_op_mulu2_i32, rl, rh, arg1, arg2);
918951c6300SRichard Henderson     } else if (TCG_TARGET_HAS_muluh_i32) {
919951c6300SRichard Henderson         TCGv_i32 t = tcg_temp_new_i32();
920951c6300SRichard Henderson         tcg_gen_op3_i32(INDEX_op_mul_i32, t, arg1, arg2);
921951c6300SRichard Henderson         tcg_gen_op3_i32(INDEX_op_muluh_i32, rh, arg1, arg2);
922951c6300SRichard Henderson         tcg_gen_mov_i32(rl, t);
923951c6300SRichard Henderson         tcg_temp_free_i32(t);
924951c6300SRichard Henderson     } else {
925951c6300SRichard Henderson         TCGv_i64 t0 = tcg_temp_new_i64();
926951c6300SRichard Henderson         TCGv_i64 t1 = tcg_temp_new_i64();
927951c6300SRichard Henderson         tcg_gen_extu_i32_i64(t0, arg1);
928951c6300SRichard Henderson         tcg_gen_extu_i32_i64(t1, arg2);
929951c6300SRichard Henderson         tcg_gen_mul_i64(t0, t0, t1);
930951c6300SRichard Henderson         tcg_gen_extr_i64_i32(rl, rh, t0);
931951c6300SRichard Henderson         tcg_temp_free_i64(t0);
932951c6300SRichard Henderson         tcg_temp_free_i64(t1);
933951c6300SRichard Henderson     }
934951c6300SRichard Henderson }
935951c6300SRichard Henderson 
936951c6300SRichard Henderson void tcg_gen_muls2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 arg1, TCGv_i32 arg2)
937951c6300SRichard Henderson {
938951c6300SRichard Henderson     if (TCG_TARGET_HAS_muls2_i32) {
939951c6300SRichard Henderson         tcg_gen_op4_i32(INDEX_op_muls2_i32, rl, rh, arg1, arg2);
940951c6300SRichard Henderson     } else if (TCG_TARGET_HAS_mulsh_i32) {
941951c6300SRichard Henderson         TCGv_i32 t = tcg_temp_new_i32();
942951c6300SRichard Henderson         tcg_gen_op3_i32(INDEX_op_mul_i32, t, arg1, arg2);
943951c6300SRichard Henderson         tcg_gen_op3_i32(INDEX_op_mulsh_i32, rh, arg1, arg2);
944951c6300SRichard Henderson         tcg_gen_mov_i32(rl, t);
945951c6300SRichard Henderson         tcg_temp_free_i32(t);
946951c6300SRichard Henderson     } else if (TCG_TARGET_REG_BITS == 32) {
947951c6300SRichard Henderson         TCGv_i32 t0 = tcg_temp_new_i32();
948951c6300SRichard Henderson         TCGv_i32 t1 = tcg_temp_new_i32();
949951c6300SRichard Henderson         TCGv_i32 t2 = tcg_temp_new_i32();
950951c6300SRichard Henderson         TCGv_i32 t3 = tcg_temp_new_i32();
951951c6300SRichard Henderson         tcg_gen_mulu2_i32(t0, t1, arg1, arg2);
952951c6300SRichard Henderson         /* Adjust for negative inputs.  */
953951c6300SRichard Henderson         tcg_gen_sari_i32(t2, arg1, 31);
954951c6300SRichard Henderson         tcg_gen_sari_i32(t3, arg2, 31);
955951c6300SRichard Henderson         tcg_gen_and_i32(t2, t2, arg2);
956951c6300SRichard Henderson         tcg_gen_and_i32(t3, t3, arg1);
957951c6300SRichard Henderson         tcg_gen_sub_i32(rh, t1, t2);
958951c6300SRichard Henderson         tcg_gen_sub_i32(rh, rh, t3);
959951c6300SRichard Henderson         tcg_gen_mov_i32(rl, t0);
960951c6300SRichard Henderson         tcg_temp_free_i32(t0);
961951c6300SRichard Henderson         tcg_temp_free_i32(t1);
962951c6300SRichard Henderson         tcg_temp_free_i32(t2);
963951c6300SRichard Henderson         tcg_temp_free_i32(t3);
964951c6300SRichard Henderson     } else {
965951c6300SRichard Henderson         TCGv_i64 t0 = tcg_temp_new_i64();
966951c6300SRichard Henderson         TCGv_i64 t1 = tcg_temp_new_i64();
967951c6300SRichard Henderson         tcg_gen_ext_i32_i64(t0, arg1);
968951c6300SRichard Henderson         tcg_gen_ext_i32_i64(t1, arg2);
969951c6300SRichard Henderson         tcg_gen_mul_i64(t0, t0, t1);
970951c6300SRichard Henderson         tcg_gen_extr_i64_i32(rl, rh, t0);
971951c6300SRichard Henderson         tcg_temp_free_i64(t0);
972951c6300SRichard Henderson         tcg_temp_free_i64(t1);
973951c6300SRichard Henderson     }
974951c6300SRichard Henderson }
975951c6300SRichard Henderson 
9765087abfbSRichard Henderson void tcg_gen_mulsu2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 arg1, TCGv_i32 arg2)
9775087abfbSRichard Henderson {
9785087abfbSRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
9795087abfbSRichard Henderson         TCGv_i32 t0 = tcg_temp_new_i32();
9805087abfbSRichard Henderson         TCGv_i32 t1 = tcg_temp_new_i32();
9815087abfbSRichard Henderson         TCGv_i32 t2 = tcg_temp_new_i32();
9825087abfbSRichard Henderson         tcg_gen_mulu2_i32(t0, t1, arg1, arg2);
9835087abfbSRichard Henderson         /* Adjust for negative input for the signed arg1.  */
9845087abfbSRichard Henderson         tcg_gen_sari_i32(t2, arg1, 31);
9855087abfbSRichard Henderson         tcg_gen_and_i32(t2, t2, arg2);
9865087abfbSRichard Henderson         tcg_gen_sub_i32(rh, t1, t2);
9875087abfbSRichard Henderson         tcg_gen_mov_i32(rl, t0);
9885087abfbSRichard Henderson         tcg_temp_free_i32(t0);
9895087abfbSRichard Henderson         tcg_temp_free_i32(t1);
9905087abfbSRichard Henderson         tcg_temp_free_i32(t2);
9915087abfbSRichard Henderson     } else {
9925087abfbSRichard Henderson         TCGv_i64 t0 = tcg_temp_new_i64();
9935087abfbSRichard Henderson         TCGv_i64 t1 = tcg_temp_new_i64();
9945087abfbSRichard Henderson         tcg_gen_ext_i32_i64(t0, arg1);
9955087abfbSRichard Henderson         tcg_gen_extu_i32_i64(t1, arg2);
9965087abfbSRichard Henderson         tcg_gen_mul_i64(t0, t0, t1);
9975087abfbSRichard Henderson         tcg_gen_extr_i64_i32(rl, rh, t0);
9985087abfbSRichard Henderson         tcg_temp_free_i64(t0);
9995087abfbSRichard Henderson         tcg_temp_free_i64(t1);
10005087abfbSRichard Henderson     }
10015087abfbSRichard Henderson }
10025087abfbSRichard Henderson 
1003951c6300SRichard Henderson void tcg_gen_ext8s_i32(TCGv_i32 ret, TCGv_i32 arg)
1004951c6300SRichard Henderson {
1005951c6300SRichard Henderson     if (TCG_TARGET_HAS_ext8s_i32) {
1006951c6300SRichard Henderson         tcg_gen_op2_i32(INDEX_op_ext8s_i32, ret, arg);
1007951c6300SRichard Henderson     } else {
1008951c6300SRichard Henderson         tcg_gen_shli_i32(ret, arg, 24);
1009951c6300SRichard Henderson         tcg_gen_sari_i32(ret, ret, 24);
1010951c6300SRichard Henderson     }
1011951c6300SRichard Henderson }
1012951c6300SRichard Henderson 
1013951c6300SRichard Henderson void tcg_gen_ext16s_i32(TCGv_i32 ret, TCGv_i32 arg)
1014951c6300SRichard Henderson {
1015951c6300SRichard Henderson     if (TCG_TARGET_HAS_ext16s_i32) {
1016951c6300SRichard Henderson         tcg_gen_op2_i32(INDEX_op_ext16s_i32, ret, arg);
1017951c6300SRichard Henderson     } else {
1018951c6300SRichard Henderson         tcg_gen_shli_i32(ret, arg, 16);
1019951c6300SRichard Henderson         tcg_gen_sari_i32(ret, ret, 16);
1020951c6300SRichard Henderson     }
1021951c6300SRichard Henderson }
1022951c6300SRichard Henderson 
1023951c6300SRichard Henderson void tcg_gen_ext8u_i32(TCGv_i32 ret, TCGv_i32 arg)
1024951c6300SRichard Henderson {
1025951c6300SRichard Henderson     if (TCG_TARGET_HAS_ext8u_i32) {
1026951c6300SRichard Henderson         tcg_gen_op2_i32(INDEX_op_ext8u_i32, ret, arg);
1027951c6300SRichard Henderson     } else {
1028951c6300SRichard Henderson         tcg_gen_andi_i32(ret, arg, 0xffu);
1029951c6300SRichard Henderson     }
1030951c6300SRichard Henderson }
1031951c6300SRichard Henderson 
1032951c6300SRichard Henderson void tcg_gen_ext16u_i32(TCGv_i32 ret, TCGv_i32 arg)
1033951c6300SRichard Henderson {
1034951c6300SRichard Henderson     if (TCG_TARGET_HAS_ext16u_i32) {
1035951c6300SRichard Henderson         tcg_gen_op2_i32(INDEX_op_ext16u_i32, ret, arg);
1036951c6300SRichard Henderson     } else {
1037951c6300SRichard Henderson         tcg_gen_andi_i32(ret, arg, 0xffffu);
1038951c6300SRichard Henderson     }
1039951c6300SRichard Henderson }
1040951c6300SRichard Henderson 
1041951c6300SRichard Henderson /* Note: we assume the two high bytes are set to zero */
1042951c6300SRichard Henderson void tcg_gen_bswap16_i32(TCGv_i32 ret, TCGv_i32 arg)
1043951c6300SRichard Henderson {
1044951c6300SRichard Henderson     if (TCG_TARGET_HAS_bswap16_i32) {
1045951c6300SRichard Henderson         tcg_gen_op2_i32(INDEX_op_bswap16_i32, ret, arg);
1046951c6300SRichard Henderson     } else {
1047951c6300SRichard Henderson         TCGv_i32 t0 = tcg_temp_new_i32();
1048951c6300SRichard Henderson 
1049951c6300SRichard Henderson         tcg_gen_ext8u_i32(t0, arg);
1050951c6300SRichard Henderson         tcg_gen_shli_i32(t0, t0, 8);
1051951c6300SRichard Henderson         tcg_gen_shri_i32(ret, arg, 8);
1052951c6300SRichard Henderson         tcg_gen_or_i32(ret, ret, t0);
1053951c6300SRichard Henderson         tcg_temp_free_i32(t0);
1054951c6300SRichard Henderson     }
1055951c6300SRichard Henderson }
1056951c6300SRichard Henderson 
1057951c6300SRichard Henderson void tcg_gen_bswap32_i32(TCGv_i32 ret, TCGv_i32 arg)
1058951c6300SRichard Henderson {
1059951c6300SRichard Henderson     if (TCG_TARGET_HAS_bswap32_i32) {
1060951c6300SRichard Henderson         tcg_gen_op2_i32(INDEX_op_bswap32_i32, ret, arg);
1061951c6300SRichard Henderson     } else {
1062951c6300SRichard Henderson         TCGv_i32 t0, t1;
1063951c6300SRichard Henderson         t0 = tcg_temp_new_i32();
1064951c6300SRichard Henderson         t1 = tcg_temp_new_i32();
1065951c6300SRichard Henderson 
1066951c6300SRichard Henderson         tcg_gen_shli_i32(t0, arg, 24);
1067951c6300SRichard Henderson 
1068951c6300SRichard Henderson         tcg_gen_andi_i32(t1, arg, 0x0000ff00);
1069951c6300SRichard Henderson         tcg_gen_shli_i32(t1, t1, 8);
1070951c6300SRichard Henderson         tcg_gen_or_i32(t0, t0, t1);
1071951c6300SRichard Henderson 
1072951c6300SRichard Henderson         tcg_gen_shri_i32(t1, arg, 8);
1073951c6300SRichard Henderson         tcg_gen_andi_i32(t1, t1, 0x0000ff00);
1074951c6300SRichard Henderson         tcg_gen_or_i32(t0, t0, t1);
1075951c6300SRichard Henderson 
1076951c6300SRichard Henderson         tcg_gen_shri_i32(t1, arg, 24);
1077951c6300SRichard Henderson         tcg_gen_or_i32(ret, t0, t1);
1078951c6300SRichard Henderson         tcg_temp_free_i32(t0);
1079951c6300SRichard Henderson         tcg_temp_free_i32(t1);
1080951c6300SRichard Henderson     }
1081951c6300SRichard Henderson }
1082951c6300SRichard Henderson 
1083951c6300SRichard Henderson /* 64-bit ops */
1084951c6300SRichard Henderson 
1085951c6300SRichard Henderson #if TCG_TARGET_REG_BITS == 32
1086951c6300SRichard Henderson /* These are all inline for TCG_TARGET_REG_BITS == 64.  */
1087951c6300SRichard Henderson 
1088951c6300SRichard Henderson void tcg_gen_discard_i64(TCGv_i64 arg)
1089951c6300SRichard Henderson {
1090951c6300SRichard Henderson     tcg_gen_discard_i32(TCGV_LOW(arg));
1091951c6300SRichard Henderson     tcg_gen_discard_i32(TCGV_HIGH(arg));
1092951c6300SRichard Henderson }
1093951c6300SRichard Henderson 
1094951c6300SRichard Henderson void tcg_gen_mov_i64(TCGv_i64 ret, TCGv_i64 arg)
1095951c6300SRichard Henderson {
1096951c6300SRichard Henderson     tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg));
1097951c6300SRichard Henderson     tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg));
1098951c6300SRichard Henderson }
1099951c6300SRichard Henderson 
1100951c6300SRichard Henderson void tcg_gen_movi_i64(TCGv_i64 ret, int64_t arg)
1101951c6300SRichard Henderson {
1102951c6300SRichard Henderson     tcg_gen_movi_i32(TCGV_LOW(ret), arg);
1103951c6300SRichard Henderson     tcg_gen_movi_i32(TCGV_HIGH(ret), arg >> 32);
1104951c6300SRichard Henderson }
1105951c6300SRichard Henderson 
1106951c6300SRichard Henderson void tcg_gen_ld8u_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset)
1107951c6300SRichard Henderson {
1108951c6300SRichard Henderson     tcg_gen_ld8u_i32(TCGV_LOW(ret), arg2, offset);
1109951c6300SRichard Henderson     tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
1110951c6300SRichard Henderson }
1111951c6300SRichard Henderson 
1112951c6300SRichard Henderson void tcg_gen_ld8s_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset)
1113951c6300SRichard Henderson {
1114951c6300SRichard Henderson     tcg_gen_ld8s_i32(TCGV_LOW(ret), arg2, offset);
11153ff91d7eSJoseph Myers     tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31);
1116951c6300SRichard Henderson }
1117951c6300SRichard Henderson 
1118951c6300SRichard Henderson void tcg_gen_ld16u_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset)
1119951c6300SRichard Henderson {
1120951c6300SRichard Henderson     tcg_gen_ld16u_i32(TCGV_LOW(ret), arg2, offset);
1121951c6300SRichard Henderson     tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
1122951c6300SRichard Henderson }
1123951c6300SRichard Henderson 
1124951c6300SRichard Henderson void tcg_gen_ld16s_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset)
1125951c6300SRichard Henderson {
1126951c6300SRichard Henderson     tcg_gen_ld16s_i32(TCGV_LOW(ret), arg2, offset);
1127951c6300SRichard Henderson     tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31);
1128951c6300SRichard Henderson }
1129951c6300SRichard Henderson 
1130951c6300SRichard Henderson void tcg_gen_ld32u_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset)
1131951c6300SRichard Henderson {
1132951c6300SRichard Henderson     tcg_gen_ld_i32(TCGV_LOW(ret), arg2, offset);
1133951c6300SRichard Henderson     tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
1134951c6300SRichard Henderson }
1135951c6300SRichard Henderson 
1136951c6300SRichard Henderson void tcg_gen_ld32s_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset)
1137951c6300SRichard Henderson {
1138951c6300SRichard Henderson     tcg_gen_ld_i32(TCGV_LOW(ret), arg2, offset);
1139951c6300SRichard Henderson     tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31);
1140951c6300SRichard Henderson }
1141951c6300SRichard Henderson 
1142951c6300SRichard Henderson void tcg_gen_ld_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset)
1143951c6300SRichard Henderson {
1144951c6300SRichard Henderson     /* Since arg2 and ret have different types,
1145951c6300SRichard Henderson        they cannot be the same temporary */
1146cf811fffSPeter Maydell #ifdef HOST_WORDS_BIGENDIAN
1147951c6300SRichard Henderson     tcg_gen_ld_i32(TCGV_HIGH(ret), arg2, offset);
1148951c6300SRichard Henderson     tcg_gen_ld_i32(TCGV_LOW(ret), arg2, offset + 4);
1149951c6300SRichard Henderson #else
1150951c6300SRichard Henderson     tcg_gen_ld_i32(TCGV_LOW(ret), arg2, offset);
1151951c6300SRichard Henderson     tcg_gen_ld_i32(TCGV_HIGH(ret), arg2, offset + 4);
1152951c6300SRichard Henderson #endif
1153951c6300SRichard Henderson }
1154951c6300SRichard Henderson 
1155951c6300SRichard Henderson void tcg_gen_st_i64(TCGv_i64 arg1, TCGv_ptr arg2, tcg_target_long offset)
1156951c6300SRichard Henderson {
1157cf811fffSPeter Maydell #ifdef HOST_WORDS_BIGENDIAN
1158951c6300SRichard Henderson     tcg_gen_st_i32(TCGV_HIGH(arg1), arg2, offset);
1159951c6300SRichard Henderson     tcg_gen_st_i32(TCGV_LOW(arg1), arg2, offset + 4);
1160951c6300SRichard Henderson #else
1161951c6300SRichard Henderson     tcg_gen_st_i32(TCGV_LOW(arg1), arg2, offset);
1162951c6300SRichard Henderson     tcg_gen_st_i32(TCGV_HIGH(arg1), arg2, offset + 4);
1163951c6300SRichard Henderson #endif
1164951c6300SRichard Henderson }
1165951c6300SRichard Henderson 
1166951c6300SRichard Henderson void tcg_gen_and_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
1167951c6300SRichard Henderson {
1168951c6300SRichard Henderson     tcg_gen_and_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2));
1169951c6300SRichard Henderson     tcg_gen_and_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2));
1170951c6300SRichard Henderson }
1171951c6300SRichard Henderson 
1172951c6300SRichard Henderson void tcg_gen_or_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
1173951c6300SRichard Henderson {
1174951c6300SRichard Henderson     tcg_gen_or_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2));
1175951c6300SRichard Henderson     tcg_gen_or_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2));
1176951c6300SRichard Henderson }
1177951c6300SRichard Henderson 
1178951c6300SRichard Henderson void tcg_gen_xor_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
1179951c6300SRichard Henderson {
1180951c6300SRichard Henderson     tcg_gen_xor_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2));
1181951c6300SRichard Henderson     tcg_gen_xor_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2));
1182951c6300SRichard Henderson }
1183951c6300SRichard Henderson 
1184951c6300SRichard Henderson void tcg_gen_shl_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
1185951c6300SRichard Henderson {
1186951c6300SRichard Henderson     gen_helper_shl_i64(ret, arg1, arg2);
1187951c6300SRichard Henderson }
1188951c6300SRichard Henderson 
1189951c6300SRichard Henderson void tcg_gen_shr_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
1190951c6300SRichard Henderson {
1191951c6300SRichard Henderson     gen_helper_shr_i64(ret, arg1, arg2);
1192951c6300SRichard Henderson }
1193951c6300SRichard Henderson 
1194951c6300SRichard Henderson void tcg_gen_sar_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
1195951c6300SRichard Henderson {
1196951c6300SRichard Henderson     gen_helper_sar_i64(ret, arg1, arg2);
1197951c6300SRichard Henderson }
1198951c6300SRichard Henderson 
1199951c6300SRichard Henderson void tcg_gen_mul_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
1200951c6300SRichard Henderson {
1201951c6300SRichard Henderson     TCGv_i64 t0;
1202951c6300SRichard Henderson     TCGv_i32 t1;
1203951c6300SRichard Henderson 
1204951c6300SRichard Henderson     t0 = tcg_temp_new_i64();
1205951c6300SRichard Henderson     t1 = tcg_temp_new_i32();
1206951c6300SRichard Henderson 
1207951c6300SRichard Henderson     tcg_gen_mulu2_i32(TCGV_LOW(t0), TCGV_HIGH(t0),
1208951c6300SRichard Henderson                       TCGV_LOW(arg1), TCGV_LOW(arg2));
1209951c6300SRichard Henderson 
1210951c6300SRichard Henderson     tcg_gen_mul_i32(t1, TCGV_LOW(arg1), TCGV_HIGH(arg2));
1211951c6300SRichard Henderson     tcg_gen_add_i32(TCGV_HIGH(t0), TCGV_HIGH(t0), t1);
1212951c6300SRichard Henderson     tcg_gen_mul_i32(t1, TCGV_HIGH(arg1), TCGV_LOW(arg2));
1213951c6300SRichard Henderson     tcg_gen_add_i32(TCGV_HIGH(t0), TCGV_HIGH(t0), t1);
1214951c6300SRichard Henderson 
1215951c6300SRichard Henderson     tcg_gen_mov_i64(ret, t0);
1216951c6300SRichard Henderson     tcg_temp_free_i64(t0);
1217951c6300SRichard Henderson     tcg_temp_free_i32(t1);
1218951c6300SRichard Henderson }
1219951c6300SRichard Henderson #endif /* TCG_TARGET_REG_SIZE == 32 */
1220951c6300SRichard Henderson 
1221951c6300SRichard Henderson void tcg_gen_addi_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
1222951c6300SRichard Henderson {
1223951c6300SRichard Henderson     /* some cases can be optimized here */
1224951c6300SRichard Henderson     if (arg2 == 0) {
1225951c6300SRichard Henderson         tcg_gen_mov_i64(ret, arg1);
1226951c6300SRichard Henderson     } else {
1227951c6300SRichard Henderson         TCGv_i64 t0 = tcg_const_i64(arg2);
1228951c6300SRichard Henderson         tcg_gen_add_i64(ret, arg1, t0);
1229951c6300SRichard Henderson         tcg_temp_free_i64(t0);
1230951c6300SRichard Henderson     }
1231951c6300SRichard Henderson }
1232951c6300SRichard Henderson 
1233951c6300SRichard Henderson void tcg_gen_subfi_i64(TCGv_i64 ret, int64_t arg1, TCGv_i64 arg2)
1234951c6300SRichard Henderson {
1235951c6300SRichard Henderson     if (arg1 == 0 && TCG_TARGET_HAS_neg_i64) {
1236951c6300SRichard Henderson         /* Don't recurse with tcg_gen_neg_i64.  */
1237951c6300SRichard Henderson         tcg_gen_op2_i64(INDEX_op_neg_i64, ret, arg2);
1238951c6300SRichard Henderson     } else {
1239951c6300SRichard Henderson         TCGv_i64 t0 = tcg_const_i64(arg1);
1240951c6300SRichard Henderson         tcg_gen_sub_i64(ret, t0, arg2);
1241951c6300SRichard Henderson         tcg_temp_free_i64(t0);
1242951c6300SRichard Henderson     }
1243951c6300SRichard Henderson }
1244951c6300SRichard Henderson 
1245951c6300SRichard Henderson void tcg_gen_subi_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
1246951c6300SRichard Henderson {
1247951c6300SRichard Henderson     /* some cases can be optimized here */
1248951c6300SRichard Henderson     if (arg2 == 0) {
1249951c6300SRichard Henderson         tcg_gen_mov_i64(ret, arg1);
1250951c6300SRichard Henderson     } else {
1251951c6300SRichard Henderson         TCGv_i64 t0 = tcg_const_i64(arg2);
1252951c6300SRichard Henderson         tcg_gen_sub_i64(ret, arg1, t0);
1253951c6300SRichard Henderson         tcg_temp_free_i64(t0);
1254951c6300SRichard Henderson     }
1255951c6300SRichard Henderson }
1256951c6300SRichard Henderson 
1257951c6300SRichard Henderson void tcg_gen_andi_i64(TCGv_i64 ret, TCGv_i64 arg1, uint64_t arg2)
1258951c6300SRichard Henderson {
12593a13c3f3SRichard Henderson     TCGv_i64 t0;
12603a13c3f3SRichard Henderson 
12613a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
1262951c6300SRichard Henderson         tcg_gen_andi_i32(TCGV_LOW(ret), TCGV_LOW(arg1), arg2);
1263951c6300SRichard Henderson         tcg_gen_andi_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), arg2 >> 32);
12643a13c3f3SRichard Henderson         return;
12653a13c3f3SRichard Henderson     }
12663a13c3f3SRichard Henderson 
1267951c6300SRichard Henderson     /* Some cases can be optimized here.  */
1268951c6300SRichard Henderson     switch (arg2) {
1269951c6300SRichard Henderson     case 0:
1270951c6300SRichard Henderson         tcg_gen_movi_i64(ret, 0);
1271951c6300SRichard Henderson         return;
1272951c6300SRichard Henderson     case 0xffffffffffffffffull:
1273951c6300SRichard Henderson         tcg_gen_mov_i64(ret, arg1);
1274951c6300SRichard Henderson         return;
1275951c6300SRichard Henderson     case 0xffull:
1276951c6300SRichard Henderson         /* Don't recurse with tcg_gen_ext8u_i64.  */
1277951c6300SRichard Henderson         if (TCG_TARGET_HAS_ext8u_i64) {
1278951c6300SRichard Henderson             tcg_gen_op2_i64(INDEX_op_ext8u_i64, ret, arg1);
1279951c6300SRichard Henderson             return;
1280951c6300SRichard Henderson         }
1281951c6300SRichard Henderson         break;
1282951c6300SRichard Henderson     case 0xffffu:
1283951c6300SRichard Henderson         if (TCG_TARGET_HAS_ext16u_i64) {
1284951c6300SRichard Henderson             tcg_gen_op2_i64(INDEX_op_ext16u_i64, ret, arg1);
1285951c6300SRichard Henderson             return;
1286951c6300SRichard Henderson         }
1287951c6300SRichard Henderson         break;
1288951c6300SRichard Henderson     case 0xffffffffull:
1289951c6300SRichard Henderson         if (TCG_TARGET_HAS_ext32u_i64) {
1290951c6300SRichard Henderson             tcg_gen_op2_i64(INDEX_op_ext32u_i64, ret, arg1);
1291951c6300SRichard Henderson             return;
1292951c6300SRichard Henderson         }
1293951c6300SRichard Henderson         break;
1294951c6300SRichard Henderson     }
1295951c6300SRichard Henderson     t0 = tcg_const_i64(arg2);
1296951c6300SRichard Henderson     tcg_gen_and_i64(ret, arg1, t0);
1297951c6300SRichard Henderson     tcg_temp_free_i64(t0);
1298951c6300SRichard Henderson }
1299951c6300SRichard Henderson 
1300951c6300SRichard Henderson void tcg_gen_ori_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
1301951c6300SRichard Henderson {
13023a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
1303951c6300SRichard Henderson         tcg_gen_ori_i32(TCGV_LOW(ret), TCGV_LOW(arg1), arg2);
1304951c6300SRichard Henderson         tcg_gen_ori_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), arg2 >> 32);
13053a13c3f3SRichard Henderson         return;
13063a13c3f3SRichard Henderson     }
1307951c6300SRichard Henderson     /* Some cases can be optimized here.  */
1308951c6300SRichard Henderson     if (arg2 == -1) {
1309951c6300SRichard Henderson         tcg_gen_movi_i64(ret, -1);
1310951c6300SRichard Henderson     } else if (arg2 == 0) {
1311951c6300SRichard Henderson         tcg_gen_mov_i64(ret, arg1);
1312951c6300SRichard Henderson     } else {
1313951c6300SRichard Henderson         TCGv_i64 t0 = tcg_const_i64(arg2);
1314951c6300SRichard Henderson         tcg_gen_or_i64(ret, arg1, t0);
1315951c6300SRichard Henderson         tcg_temp_free_i64(t0);
1316951c6300SRichard Henderson     }
1317951c6300SRichard Henderson }
1318951c6300SRichard Henderson 
1319951c6300SRichard Henderson void tcg_gen_xori_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
1320951c6300SRichard Henderson {
13213a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
1322951c6300SRichard Henderson         tcg_gen_xori_i32(TCGV_LOW(ret), TCGV_LOW(arg1), arg2);
1323951c6300SRichard Henderson         tcg_gen_xori_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), arg2 >> 32);
13243a13c3f3SRichard Henderson         return;
13253a13c3f3SRichard Henderson     }
1326951c6300SRichard Henderson     /* Some cases can be optimized here.  */
1327951c6300SRichard Henderson     if (arg2 == 0) {
1328951c6300SRichard Henderson         tcg_gen_mov_i64(ret, arg1);
1329951c6300SRichard Henderson     } else if (arg2 == -1 && TCG_TARGET_HAS_not_i64) {
1330951c6300SRichard Henderson         /* Don't recurse with tcg_gen_not_i64.  */
1331951c6300SRichard Henderson         tcg_gen_op2_i64(INDEX_op_not_i64, ret, arg1);
1332951c6300SRichard Henderson     } else {
1333951c6300SRichard Henderson         TCGv_i64 t0 = tcg_const_i64(arg2);
1334951c6300SRichard Henderson         tcg_gen_xor_i64(ret, arg1, t0);
1335951c6300SRichard Henderson         tcg_temp_free_i64(t0);
1336951c6300SRichard Henderson     }
1337951c6300SRichard Henderson }
1338951c6300SRichard Henderson 
1339951c6300SRichard Henderson static inline void tcg_gen_shifti_i64(TCGv_i64 ret, TCGv_i64 arg1,
1340951c6300SRichard Henderson                                       unsigned c, bool right, bool arith)
1341951c6300SRichard Henderson {
1342951c6300SRichard Henderson     tcg_debug_assert(c < 64);
1343951c6300SRichard Henderson     if (c == 0) {
1344951c6300SRichard Henderson         tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg1));
1345951c6300SRichard Henderson         tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1));
1346951c6300SRichard Henderson     } else if (c >= 32) {
1347951c6300SRichard Henderson         c -= 32;
1348951c6300SRichard Henderson         if (right) {
1349951c6300SRichard Henderson             if (arith) {
1350951c6300SRichard Henderson                 tcg_gen_sari_i32(TCGV_LOW(ret), TCGV_HIGH(arg1), c);
1351951c6300SRichard Henderson                 tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), 31);
1352951c6300SRichard Henderson             } else {
1353951c6300SRichard Henderson                 tcg_gen_shri_i32(TCGV_LOW(ret), TCGV_HIGH(arg1), c);
1354951c6300SRichard Henderson                 tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
1355951c6300SRichard Henderson             }
1356951c6300SRichard Henderson         } else {
1357951c6300SRichard Henderson             tcg_gen_shli_i32(TCGV_HIGH(ret), TCGV_LOW(arg1), c);
1358951c6300SRichard Henderson             tcg_gen_movi_i32(TCGV_LOW(ret), 0);
1359951c6300SRichard Henderson         }
1360951c6300SRichard Henderson     } else {
1361951c6300SRichard Henderson         TCGv_i32 t0, t1;
1362951c6300SRichard Henderson 
1363951c6300SRichard Henderson         t0 = tcg_temp_new_i32();
1364951c6300SRichard Henderson         t1 = tcg_temp_new_i32();
1365951c6300SRichard Henderson         if (right) {
1366951c6300SRichard Henderson             tcg_gen_shli_i32(t0, TCGV_HIGH(arg1), 32 - c);
1367951c6300SRichard Henderson             if (arith) {
1368951c6300SRichard Henderson                 tcg_gen_sari_i32(t1, TCGV_HIGH(arg1), c);
1369951c6300SRichard Henderson             } else {
1370951c6300SRichard Henderson                 tcg_gen_shri_i32(t1, TCGV_HIGH(arg1), c);
1371951c6300SRichard Henderson             }
1372951c6300SRichard Henderson             tcg_gen_shri_i32(TCGV_LOW(ret), TCGV_LOW(arg1), c);
1373951c6300SRichard Henderson             tcg_gen_or_i32(TCGV_LOW(ret), TCGV_LOW(ret), t0);
1374951c6300SRichard Henderson             tcg_gen_mov_i32(TCGV_HIGH(ret), t1);
1375951c6300SRichard Henderson         } else {
1376951c6300SRichard Henderson             tcg_gen_shri_i32(t0, TCGV_LOW(arg1), 32 - c);
1377951c6300SRichard Henderson             /* Note: ret can be the same as arg1, so we use t1 */
1378951c6300SRichard Henderson             tcg_gen_shli_i32(t1, TCGV_LOW(arg1), c);
1379951c6300SRichard Henderson             tcg_gen_shli_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), c);
1380951c6300SRichard Henderson             tcg_gen_or_i32(TCGV_HIGH(ret), TCGV_HIGH(ret), t0);
1381951c6300SRichard Henderson             tcg_gen_mov_i32(TCGV_LOW(ret), t1);
1382951c6300SRichard Henderson         }
1383951c6300SRichard Henderson         tcg_temp_free_i32(t0);
1384951c6300SRichard Henderson         tcg_temp_free_i32(t1);
1385951c6300SRichard Henderson     }
1386951c6300SRichard Henderson }
1387951c6300SRichard Henderson 
1388951c6300SRichard Henderson void tcg_gen_shli_i64(TCGv_i64 ret, TCGv_i64 arg1, unsigned arg2)
1389951c6300SRichard Henderson {
1390951c6300SRichard Henderson     tcg_debug_assert(arg2 < 64);
13913a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
13923a13c3f3SRichard Henderson         tcg_gen_shifti_i64(ret, arg1, arg2, 0, 0);
13933a13c3f3SRichard Henderson     } else if (arg2 == 0) {
1394951c6300SRichard Henderson         tcg_gen_mov_i64(ret, arg1);
1395951c6300SRichard Henderson     } else {
1396951c6300SRichard Henderson         TCGv_i64 t0 = tcg_const_i64(arg2);
1397951c6300SRichard Henderson         tcg_gen_shl_i64(ret, arg1, t0);
1398951c6300SRichard Henderson         tcg_temp_free_i64(t0);
1399951c6300SRichard Henderson     }
1400951c6300SRichard Henderson }
1401951c6300SRichard Henderson 
1402951c6300SRichard Henderson void tcg_gen_shri_i64(TCGv_i64 ret, TCGv_i64 arg1, unsigned arg2)
1403951c6300SRichard Henderson {
1404951c6300SRichard Henderson     tcg_debug_assert(arg2 < 64);
14053a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
14063a13c3f3SRichard Henderson         tcg_gen_shifti_i64(ret, arg1, arg2, 1, 0);
14073a13c3f3SRichard Henderson     } else if (arg2 == 0) {
1408951c6300SRichard Henderson         tcg_gen_mov_i64(ret, arg1);
1409951c6300SRichard Henderson     } else {
1410951c6300SRichard Henderson         TCGv_i64 t0 = tcg_const_i64(arg2);
1411951c6300SRichard Henderson         tcg_gen_shr_i64(ret, arg1, t0);
1412951c6300SRichard Henderson         tcg_temp_free_i64(t0);
1413951c6300SRichard Henderson     }
1414951c6300SRichard Henderson }
1415951c6300SRichard Henderson 
1416951c6300SRichard Henderson void tcg_gen_sari_i64(TCGv_i64 ret, TCGv_i64 arg1, unsigned arg2)
1417951c6300SRichard Henderson {
1418951c6300SRichard Henderson     tcg_debug_assert(arg2 < 64);
14193a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
14203a13c3f3SRichard Henderson         tcg_gen_shifti_i64(ret, arg1, arg2, 1, 1);
14213a13c3f3SRichard Henderson     } else if (arg2 == 0) {
1422951c6300SRichard Henderson         tcg_gen_mov_i64(ret, arg1);
1423951c6300SRichard Henderson     } else {
1424951c6300SRichard Henderson         TCGv_i64 t0 = tcg_const_i64(arg2);
1425951c6300SRichard Henderson         tcg_gen_sar_i64(ret, arg1, t0);
1426951c6300SRichard Henderson         tcg_temp_free_i64(t0);
1427951c6300SRichard Henderson     }
1428951c6300SRichard Henderson }
1429951c6300SRichard Henderson 
143042a268c2SRichard Henderson void tcg_gen_brcond_i64(TCGCond cond, TCGv_i64 arg1, TCGv_i64 arg2, TCGLabel *l)
1431951c6300SRichard Henderson {
1432951c6300SRichard Henderson     if (cond == TCG_COND_ALWAYS) {
143342a268c2SRichard Henderson         tcg_gen_br(l);
1434951c6300SRichard Henderson     } else if (cond != TCG_COND_NEVER) {
14353a13c3f3SRichard Henderson         if (TCG_TARGET_REG_BITS == 32) {
1436951c6300SRichard Henderson             tcg_gen_op6ii_i32(INDEX_op_brcond2_i32, TCGV_LOW(arg1),
1437951c6300SRichard Henderson                               TCGV_HIGH(arg1), TCGV_LOW(arg2),
143842a268c2SRichard Henderson                               TCGV_HIGH(arg2), cond, label_arg(l));
14393a13c3f3SRichard Henderson         } else {
144042a268c2SRichard Henderson             tcg_gen_op4ii_i64(INDEX_op_brcond_i64, arg1, arg2, cond,
144142a268c2SRichard Henderson                               label_arg(l));
14423a13c3f3SRichard Henderson         }
1443951c6300SRichard Henderson     }
1444951c6300SRichard Henderson }
1445951c6300SRichard Henderson 
144642a268c2SRichard Henderson void tcg_gen_brcondi_i64(TCGCond cond, TCGv_i64 arg1, int64_t arg2, TCGLabel *l)
1447951c6300SRichard Henderson {
1448951c6300SRichard Henderson     if (cond == TCG_COND_ALWAYS) {
144942a268c2SRichard Henderson         tcg_gen_br(l);
1450951c6300SRichard Henderson     } else if (cond != TCG_COND_NEVER) {
1451951c6300SRichard Henderson         TCGv_i64 t0 = tcg_const_i64(arg2);
145242a268c2SRichard Henderson         tcg_gen_brcond_i64(cond, arg1, t0, l);
1453951c6300SRichard Henderson         tcg_temp_free_i64(t0);
1454951c6300SRichard Henderson     }
1455951c6300SRichard Henderson }
1456951c6300SRichard Henderson 
1457951c6300SRichard Henderson void tcg_gen_setcond_i64(TCGCond cond, TCGv_i64 ret,
1458951c6300SRichard Henderson                          TCGv_i64 arg1, TCGv_i64 arg2)
1459951c6300SRichard Henderson {
1460951c6300SRichard Henderson     if (cond == TCG_COND_ALWAYS) {
1461951c6300SRichard Henderson         tcg_gen_movi_i64(ret, 1);
1462951c6300SRichard Henderson     } else if (cond == TCG_COND_NEVER) {
1463951c6300SRichard Henderson         tcg_gen_movi_i64(ret, 0);
1464951c6300SRichard Henderson     } else {
14653a13c3f3SRichard Henderson         if (TCG_TARGET_REG_BITS == 32) {
1466951c6300SRichard Henderson             tcg_gen_op6i_i32(INDEX_op_setcond2_i32, TCGV_LOW(ret),
1467951c6300SRichard Henderson                              TCGV_LOW(arg1), TCGV_HIGH(arg1),
1468951c6300SRichard Henderson                              TCGV_LOW(arg2), TCGV_HIGH(arg2), cond);
1469951c6300SRichard Henderson             tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
14703a13c3f3SRichard Henderson         } else {
1471951c6300SRichard Henderson             tcg_gen_op4i_i64(INDEX_op_setcond_i64, ret, arg1, arg2, cond);
14723a13c3f3SRichard Henderson         }
1473951c6300SRichard Henderson     }
1474951c6300SRichard Henderson }
1475951c6300SRichard Henderson 
1476951c6300SRichard Henderson void tcg_gen_setcondi_i64(TCGCond cond, TCGv_i64 ret,
1477951c6300SRichard Henderson                           TCGv_i64 arg1, int64_t arg2)
1478951c6300SRichard Henderson {
1479951c6300SRichard Henderson     TCGv_i64 t0 = tcg_const_i64(arg2);
1480951c6300SRichard Henderson     tcg_gen_setcond_i64(cond, ret, arg1, t0);
1481951c6300SRichard Henderson     tcg_temp_free_i64(t0);
1482951c6300SRichard Henderson }
1483951c6300SRichard Henderson 
1484951c6300SRichard Henderson void tcg_gen_muli_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
1485951c6300SRichard Henderson {
1486951c6300SRichard Henderson     TCGv_i64 t0 = tcg_const_i64(arg2);
1487951c6300SRichard Henderson     tcg_gen_mul_i64(ret, arg1, t0);
1488951c6300SRichard Henderson     tcg_temp_free_i64(t0);
1489951c6300SRichard Henderson }
1490951c6300SRichard Henderson 
1491951c6300SRichard Henderson void tcg_gen_div_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
1492951c6300SRichard Henderson {
1493951c6300SRichard Henderson     if (TCG_TARGET_HAS_div_i64) {
1494951c6300SRichard Henderson         tcg_gen_op3_i64(INDEX_op_div_i64, ret, arg1, arg2);
1495951c6300SRichard Henderson     } else if (TCG_TARGET_HAS_div2_i64) {
1496951c6300SRichard Henderson         TCGv_i64 t0 = tcg_temp_new_i64();
1497951c6300SRichard Henderson         tcg_gen_sari_i64(t0, arg1, 63);
1498951c6300SRichard Henderson         tcg_gen_op5_i64(INDEX_op_div2_i64, ret, t0, arg1, t0, arg2);
1499951c6300SRichard Henderson         tcg_temp_free_i64(t0);
1500951c6300SRichard Henderson     } else {
1501951c6300SRichard Henderson         gen_helper_div_i64(ret, arg1, arg2);
1502951c6300SRichard Henderson     }
1503951c6300SRichard Henderson }
1504951c6300SRichard Henderson 
1505951c6300SRichard Henderson void tcg_gen_rem_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
1506951c6300SRichard Henderson {
1507951c6300SRichard Henderson     if (TCG_TARGET_HAS_rem_i64) {
1508951c6300SRichard Henderson         tcg_gen_op3_i64(INDEX_op_rem_i64, ret, arg1, arg2);
1509951c6300SRichard Henderson     } else if (TCG_TARGET_HAS_div_i64) {
1510951c6300SRichard Henderson         TCGv_i64 t0 = tcg_temp_new_i64();
1511951c6300SRichard Henderson         tcg_gen_op3_i64(INDEX_op_div_i64, t0, arg1, arg2);
1512951c6300SRichard Henderson         tcg_gen_mul_i64(t0, t0, arg2);
1513951c6300SRichard Henderson         tcg_gen_sub_i64(ret, arg1, t0);
1514951c6300SRichard Henderson         tcg_temp_free_i64(t0);
1515951c6300SRichard Henderson     } else if (TCG_TARGET_HAS_div2_i64) {
1516951c6300SRichard Henderson         TCGv_i64 t0 = tcg_temp_new_i64();
1517951c6300SRichard Henderson         tcg_gen_sari_i64(t0, arg1, 63);
1518951c6300SRichard Henderson         tcg_gen_op5_i64(INDEX_op_div2_i64, t0, ret, arg1, t0, arg2);
1519951c6300SRichard Henderson         tcg_temp_free_i64(t0);
1520951c6300SRichard Henderson     } else {
1521951c6300SRichard Henderson         gen_helper_rem_i64(ret, arg1, arg2);
1522951c6300SRichard Henderson     }
1523951c6300SRichard Henderson }
1524951c6300SRichard Henderson 
1525951c6300SRichard Henderson void tcg_gen_divu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
1526951c6300SRichard Henderson {
1527951c6300SRichard Henderson     if (TCG_TARGET_HAS_div_i64) {
1528951c6300SRichard Henderson         tcg_gen_op3_i64(INDEX_op_divu_i64, ret, arg1, arg2);
1529951c6300SRichard Henderson     } else if (TCG_TARGET_HAS_div2_i64) {
1530951c6300SRichard Henderson         TCGv_i64 t0 = tcg_temp_new_i64();
1531951c6300SRichard Henderson         tcg_gen_movi_i64(t0, 0);
1532951c6300SRichard Henderson         tcg_gen_op5_i64(INDEX_op_divu2_i64, ret, t0, arg1, t0, arg2);
1533951c6300SRichard Henderson         tcg_temp_free_i64(t0);
1534951c6300SRichard Henderson     } else {
1535951c6300SRichard Henderson         gen_helper_divu_i64(ret, arg1, arg2);
1536951c6300SRichard Henderson     }
1537951c6300SRichard Henderson }
1538951c6300SRichard Henderson 
1539951c6300SRichard Henderson void tcg_gen_remu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
1540951c6300SRichard Henderson {
1541951c6300SRichard Henderson     if (TCG_TARGET_HAS_rem_i64) {
1542951c6300SRichard Henderson         tcg_gen_op3_i64(INDEX_op_remu_i64, ret, arg1, arg2);
1543951c6300SRichard Henderson     } else if (TCG_TARGET_HAS_div_i64) {
1544951c6300SRichard Henderson         TCGv_i64 t0 = tcg_temp_new_i64();
1545951c6300SRichard Henderson         tcg_gen_op3_i64(INDEX_op_divu_i64, t0, arg1, arg2);
1546951c6300SRichard Henderson         tcg_gen_mul_i64(t0, t0, arg2);
1547951c6300SRichard Henderson         tcg_gen_sub_i64(ret, arg1, t0);
1548951c6300SRichard Henderson         tcg_temp_free_i64(t0);
1549951c6300SRichard Henderson     } else if (TCG_TARGET_HAS_div2_i64) {
1550951c6300SRichard Henderson         TCGv_i64 t0 = tcg_temp_new_i64();
1551951c6300SRichard Henderson         tcg_gen_movi_i64(t0, 0);
1552951c6300SRichard Henderson         tcg_gen_op5_i64(INDEX_op_divu2_i64, t0, ret, arg1, t0, arg2);
1553951c6300SRichard Henderson         tcg_temp_free_i64(t0);
1554951c6300SRichard Henderson     } else {
1555951c6300SRichard Henderson         gen_helper_remu_i64(ret, arg1, arg2);
1556951c6300SRichard Henderson     }
1557951c6300SRichard Henderson }
1558951c6300SRichard Henderson 
1559951c6300SRichard Henderson void tcg_gen_ext8s_i64(TCGv_i64 ret, TCGv_i64 arg)
1560951c6300SRichard Henderson {
15613a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
1562951c6300SRichard Henderson         tcg_gen_ext8s_i32(TCGV_LOW(ret), TCGV_LOW(arg));
1563951c6300SRichard Henderson         tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31);
15643a13c3f3SRichard Henderson     } else if (TCG_TARGET_HAS_ext8s_i64) {
1565951c6300SRichard Henderson         tcg_gen_op2_i64(INDEX_op_ext8s_i64, ret, arg);
1566951c6300SRichard Henderson     } else {
1567951c6300SRichard Henderson         tcg_gen_shli_i64(ret, arg, 56);
1568951c6300SRichard Henderson         tcg_gen_sari_i64(ret, ret, 56);
1569951c6300SRichard Henderson     }
1570951c6300SRichard Henderson }
1571951c6300SRichard Henderson 
1572951c6300SRichard Henderson void tcg_gen_ext16s_i64(TCGv_i64 ret, TCGv_i64 arg)
1573951c6300SRichard Henderson {
15743a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
1575951c6300SRichard Henderson         tcg_gen_ext16s_i32(TCGV_LOW(ret), TCGV_LOW(arg));
1576951c6300SRichard Henderson         tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31);
15773a13c3f3SRichard Henderson     } else if (TCG_TARGET_HAS_ext16s_i64) {
1578951c6300SRichard Henderson         tcg_gen_op2_i64(INDEX_op_ext16s_i64, ret, arg);
1579951c6300SRichard Henderson     } else {
1580951c6300SRichard Henderson         tcg_gen_shli_i64(ret, arg, 48);
1581951c6300SRichard Henderson         tcg_gen_sari_i64(ret, ret, 48);
1582951c6300SRichard Henderson     }
1583951c6300SRichard Henderson }
1584951c6300SRichard Henderson 
1585951c6300SRichard Henderson void tcg_gen_ext32s_i64(TCGv_i64 ret, TCGv_i64 arg)
1586951c6300SRichard Henderson {
15873a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
1588951c6300SRichard Henderson         tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg));
1589951c6300SRichard Henderson         tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31);
15903a13c3f3SRichard Henderson     } else if (TCG_TARGET_HAS_ext32s_i64) {
1591951c6300SRichard Henderson         tcg_gen_op2_i64(INDEX_op_ext32s_i64, ret, arg);
1592951c6300SRichard Henderson     } else {
1593951c6300SRichard Henderson         tcg_gen_shli_i64(ret, arg, 32);
1594951c6300SRichard Henderson         tcg_gen_sari_i64(ret, ret, 32);
1595951c6300SRichard Henderson     }
1596951c6300SRichard Henderson }
1597951c6300SRichard Henderson 
1598951c6300SRichard Henderson void tcg_gen_ext8u_i64(TCGv_i64 ret, TCGv_i64 arg)
1599951c6300SRichard Henderson {
16003a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
1601951c6300SRichard Henderson         tcg_gen_ext8u_i32(TCGV_LOW(ret), TCGV_LOW(arg));
1602951c6300SRichard Henderson         tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
16033a13c3f3SRichard Henderson     } else if (TCG_TARGET_HAS_ext8u_i64) {
1604951c6300SRichard Henderson         tcg_gen_op2_i64(INDEX_op_ext8u_i64, ret, arg);
1605951c6300SRichard Henderson     } else {
1606951c6300SRichard Henderson         tcg_gen_andi_i64(ret, arg, 0xffu);
1607951c6300SRichard Henderson     }
1608951c6300SRichard Henderson }
1609951c6300SRichard Henderson 
1610951c6300SRichard Henderson void tcg_gen_ext16u_i64(TCGv_i64 ret, TCGv_i64 arg)
1611951c6300SRichard Henderson {
16123a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
1613951c6300SRichard Henderson         tcg_gen_ext16u_i32(TCGV_LOW(ret), TCGV_LOW(arg));
1614951c6300SRichard Henderson         tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
16153a13c3f3SRichard Henderson     } else if (TCG_TARGET_HAS_ext16u_i64) {
1616951c6300SRichard Henderson         tcg_gen_op2_i64(INDEX_op_ext16u_i64, ret, arg);
1617951c6300SRichard Henderson     } else {
1618951c6300SRichard Henderson         tcg_gen_andi_i64(ret, arg, 0xffffu);
1619951c6300SRichard Henderson     }
1620951c6300SRichard Henderson }
1621951c6300SRichard Henderson 
1622951c6300SRichard Henderson void tcg_gen_ext32u_i64(TCGv_i64 ret, TCGv_i64 arg)
1623951c6300SRichard Henderson {
16243a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
1625951c6300SRichard Henderson         tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg));
1626951c6300SRichard Henderson         tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
16273a13c3f3SRichard Henderson     } else if (TCG_TARGET_HAS_ext32u_i64) {
1628951c6300SRichard Henderson         tcg_gen_op2_i64(INDEX_op_ext32u_i64, ret, arg);
1629951c6300SRichard Henderson     } else {
1630951c6300SRichard Henderson         tcg_gen_andi_i64(ret, arg, 0xffffffffu);
1631951c6300SRichard Henderson     }
1632951c6300SRichard Henderson }
1633951c6300SRichard Henderson 
1634951c6300SRichard Henderson /* Note: we assume the six high bytes are set to zero */
1635951c6300SRichard Henderson void tcg_gen_bswap16_i64(TCGv_i64 ret, TCGv_i64 arg)
1636951c6300SRichard Henderson {
16373a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
1638951c6300SRichard Henderson         tcg_gen_bswap16_i32(TCGV_LOW(ret), TCGV_LOW(arg));
1639951c6300SRichard Henderson         tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
16403a13c3f3SRichard Henderson     } else if (TCG_TARGET_HAS_bswap16_i64) {
1641951c6300SRichard Henderson         tcg_gen_op2_i64(INDEX_op_bswap16_i64, ret, arg);
1642951c6300SRichard Henderson     } else {
1643951c6300SRichard Henderson         TCGv_i64 t0 = tcg_temp_new_i64();
1644951c6300SRichard Henderson 
1645951c6300SRichard Henderson         tcg_gen_ext8u_i64(t0, arg);
1646951c6300SRichard Henderson         tcg_gen_shli_i64(t0, t0, 8);
1647951c6300SRichard Henderson         tcg_gen_shri_i64(ret, arg, 8);
1648951c6300SRichard Henderson         tcg_gen_or_i64(ret, ret, t0);
1649951c6300SRichard Henderson         tcg_temp_free_i64(t0);
1650951c6300SRichard Henderson     }
1651951c6300SRichard Henderson }
1652951c6300SRichard Henderson 
1653951c6300SRichard Henderson /* Note: we assume the four high bytes are set to zero */
1654951c6300SRichard Henderson void tcg_gen_bswap32_i64(TCGv_i64 ret, TCGv_i64 arg)
1655951c6300SRichard Henderson {
16563a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
1657951c6300SRichard Henderson         tcg_gen_bswap32_i32(TCGV_LOW(ret), TCGV_LOW(arg));
1658951c6300SRichard Henderson         tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
16593a13c3f3SRichard Henderson     } else if (TCG_TARGET_HAS_bswap32_i64) {
1660951c6300SRichard Henderson         tcg_gen_op2_i64(INDEX_op_bswap32_i64, ret, arg);
1661951c6300SRichard Henderson     } else {
1662951c6300SRichard Henderson         TCGv_i64 t0, t1;
1663951c6300SRichard Henderson         t0 = tcg_temp_new_i64();
1664951c6300SRichard Henderson         t1 = tcg_temp_new_i64();
1665951c6300SRichard Henderson 
1666951c6300SRichard Henderson         tcg_gen_shli_i64(t0, arg, 24);
1667951c6300SRichard Henderson         tcg_gen_ext32u_i64(t0, t0);
1668951c6300SRichard Henderson 
1669951c6300SRichard Henderson         tcg_gen_andi_i64(t1, arg, 0x0000ff00);
1670951c6300SRichard Henderson         tcg_gen_shli_i64(t1, t1, 8);
1671951c6300SRichard Henderson         tcg_gen_or_i64(t0, t0, t1);
1672951c6300SRichard Henderson 
1673951c6300SRichard Henderson         tcg_gen_shri_i64(t1, arg, 8);
1674951c6300SRichard Henderson         tcg_gen_andi_i64(t1, t1, 0x0000ff00);
1675951c6300SRichard Henderson         tcg_gen_or_i64(t0, t0, t1);
1676951c6300SRichard Henderson 
1677951c6300SRichard Henderson         tcg_gen_shri_i64(t1, arg, 24);
1678951c6300SRichard Henderson         tcg_gen_or_i64(ret, t0, t1);
1679951c6300SRichard Henderson         tcg_temp_free_i64(t0);
1680951c6300SRichard Henderson         tcg_temp_free_i64(t1);
1681951c6300SRichard Henderson     }
1682951c6300SRichard Henderson }
1683951c6300SRichard Henderson 
1684951c6300SRichard Henderson void tcg_gen_bswap64_i64(TCGv_i64 ret, TCGv_i64 arg)
1685951c6300SRichard Henderson {
16863a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
1687951c6300SRichard Henderson         TCGv_i32 t0, t1;
1688951c6300SRichard Henderson         t0 = tcg_temp_new_i32();
1689951c6300SRichard Henderson         t1 = tcg_temp_new_i32();
1690951c6300SRichard Henderson 
1691951c6300SRichard Henderson         tcg_gen_bswap32_i32(t0, TCGV_LOW(arg));
1692951c6300SRichard Henderson         tcg_gen_bswap32_i32(t1, TCGV_HIGH(arg));
1693951c6300SRichard Henderson         tcg_gen_mov_i32(TCGV_LOW(ret), t1);
1694951c6300SRichard Henderson         tcg_gen_mov_i32(TCGV_HIGH(ret), t0);
1695951c6300SRichard Henderson         tcg_temp_free_i32(t0);
1696951c6300SRichard Henderson         tcg_temp_free_i32(t1);
16973a13c3f3SRichard Henderson     } else if (TCG_TARGET_HAS_bswap64_i64) {
1698951c6300SRichard Henderson         tcg_gen_op2_i64(INDEX_op_bswap64_i64, ret, arg);
1699951c6300SRichard Henderson     } else {
1700951c6300SRichard Henderson         TCGv_i64 t0 = tcg_temp_new_i64();
1701951c6300SRichard Henderson         TCGv_i64 t1 = tcg_temp_new_i64();
1702951c6300SRichard Henderson 
1703951c6300SRichard Henderson         tcg_gen_shli_i64(t0, arg, 56);
1704951c6300SRichard Henderson 
1705951c6300SRichard Henderson         tcg_gen_andi_i64(t1, arg, 0x0000ff00);
1706951c6300SRichard Henderson         tcg_gen_shli_i64(t1, t1, 40);
1707951c6300SRichard Henderson         tcg_gen_or_i64(t0, t0, t1);
1708951c6300SRichard Henderson 
1709951c6300SRichard Henderson         tcg_gen_andi_i64(t1, arg, 0x00ff0000);
1710951c6300SRichard Henderson         tcg_gen_shli_i64(t1, t1, 24);
1711951c6300SRichard Henderson         tcg_gen_or_i64(t0, t0, t1);
1712951c6300SRichard Henderson 
1713951c6300SRichard Henderson         tcg_gen_andi_i64(t1, arg, 0xff000000);
1714951c6300SRichard Henderson         tcg_gen_shli_i64(t1, t1, 8);
1715951c6300SRichard Henderson         tcg_gen_or_i64(t0, t0, t1);
1716951c6300SRichard Henderson 
1717951c6300SRichard Henderson         tcg_gen_shri_i64(t1, arg, 8);
1718951c6300SRichard Henderson         tcg_gen_andi_i64(t1, t1, 0xff000000);
1719951c6300SRichard Henderson         tcg_gen_or_i64(t0, t0, t1);
1720951c6300SRichard Henderson 
1721951c6300SRichard Henderson         tcg_gen_shri_i64(t1, arg, 24);
1722951c6300SRichard Henderson         tcg_gen_andi_i64(t1, t1, 0x00ff0000);
1723951c6300SRichard Henderson         tcg_gen_or_i64(t0, t0, t1);
1724951c6300SRichard Henderson 
1725951c6300SRichard Henderson         tcg_gen_shri_i64(t1, arg, 40);
1726951c6300SRichard Henderson         tcg_gen_andi_i64(t1, t1, 0x0000ff00);
1727951c6300SRichard Henderson         tcg_gen_or_i64(t0, t0, t1);
1728951c6300SRichard Henderson 
1729951c6300SRichard Henderson         tcg_gen_shri_i64(t1, arg, 56);
1730951c6300SRichard Henderson         tcg_gen_or_i64(ret, t0, t1);
1731951c6300SRichard Henderson         tcg_temp_free_i64(t0);
1732951c6300SRichard Henderson         tcg_temp_free_i64(t1);
1733951c6300SRichard Henderson     }
1734951c6300SRichard Henderson }
1735951c6300SRichard Henderson 
1736951c6300SRichard Henderson void tcg_gen_not_i64(TCGv_i64 ret, TCGv_i64 arg)
1737951c6300SRichard Henderson {
17383a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
17393a13c3f3SRichard Henderson         tcg_gen_not_i32(TCGV_LOW(ret), TCGV_LOW(arg));
17403a13c3f3SRichard Henderson         tcg_gen_not_i32(TCGV_HIGH(ret), TCGV_HIGH(arg));
17413a13c3f3SRichard Henderson     } else if (TCG_TARGET_HAS_not_i64) {
1742951c6300SRichard Henderson         tcg_gen_op2_i64(INDEX_op_not_i64, ret, arg);
1743951c6300SRichard Henderson     } else {
1744951c6300SRichard Henderson         tcg_gen_xori_i64(ret, arg, -1);
1745951c6300SRichard Henderson     }
1746951c6300SRichard Henderson }
1747951c6300SRichard Henderson 
1748951c6300SRichard Henderson void tcg_gen_andc_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
1749951c6300SRichard Henderson {
17503a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
17513a13c3f3SRichard Henderson         tcg_gen_andc_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2));
17523a13c3f3SRichard Henderson         tcg_gen_andc_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2));
17533a13c3f3SRichard Henderson     } else if (TCG_TARGET_HAS_andc_i64) {
1754951c6300SRichard Henderson         tcg_gen_op3_i64(INDEX_op_andc_i64, ret, arg1, arg2);
1755951c6300SRichard Henderson     } else {
1756951c6300SRichard Henderson         TCGv_i64 t0 = tcg_temp_new_i64();
1757951c6300SRichard Henderson         tcg_gen_not_i64(t0, arg2);
1758951c6300SRichard Henderson         tcg_gen_and_i64(ret, arg1, t0);
1759951c6300SRichard Henderson         tcg_temp_free_i64(t0);
1760951c6300SRichard Henderson     }
1761951c6300SRichard Henderson }
1762951c6300SRichard Henderson 
1763951c6300SRichard Henderson void tcg_gen_eqv_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
1764951c6300SRichard Henderson {
17653a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
17663a13c3f3SRichard Henderson         tcg_gen_eqv_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2));
17673a13c3f3SRichard Henderson         tcg_gen_eqv_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2));
17683a13c3f3SRichard Henderson     } else if (TCG_TARGET_HAS_eqv_i64) {
1769951c6300SRichard Henderson         tcg_gen_op3_i64(INDEX_op_eqv_i64, ret, arg1, arg2);
1770951c6300SRichard Henderson     } else {
1771951c6300SRichard Henderson         tcg_gen_xor_i64(ret, arg1, arg2);
1772951c6300SRichard Henderson         tcg_gen_not_i64(ret, ret);
1773951c6300SRichard Henderson     }
1774951c6300SRichard Henderson }
1775951c6300SRichard Henderson 
1776951c6300SRichard Henderson void tcg_gen_nand_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
1777951c6300SRichard Henderson {
17783a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
17793a13c3f3SRichard Henderson         tcg_gen_nand_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2));
17803a13c3f3SRichard Henderson         tcg_gen_nand_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2));
17813a13c3f3SRichard Henderson     } else if (TCG_TARGET_HAS_nand_i64) {
1782951c6300SRichard Henderson         tcg_gen_op3_i64(INDEX_op_nand_i64, ret, arg1, arg2);
1783951c6300SRichard Henderson     } else {
1784951c6300SRichard Henderson         tcg_gen_and_i64(ret, arg1, arg2);
1785951c6300SRichard Henderson         tcg_gen_not_i64(ret, ret);
1786951c6300SRichard Henderson     }
1787951c6300SRichard Henderson }
1788951c6300SRichard Henderson 
1789951c6300SRichard Henderson void tcg_gen_nor_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
1790951c6300SRichard Henderson {
17913a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
17923a13c3f3SRichard Henderson         tcg_gen_nor_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2));
17933a13c3f3SRichard Henderson         tcg_gen_nor_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2));
17943a13c3f3SRichard Henderson     } else if (TCG_TARGET_HAS_nor_i64) {
1795951c6300SRichard Henderson         tcg_gen_op3_i64(INDEX_op_nor_i64, ret, arg1, arg2);
1796951c6300SRichard Henderson     } else {
1797951c6300SRichard Henderson         tcg_gen_or_i64(ret, arg1, arg2);
1798951c6300SRichard Henderson         tcg_gen_not_i64(ret, ret);
1799951c6300SRichard Henderson     }
1800951c6300SRichard Henderson }
1801951c6300SRichard Henderson 
1802951c6300SRichard Henderson void tcg_gen_orc_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
1803951c6300SRichard Henderson {
18043a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
18053a13c3f3SRichard Henderson         tcg_gen_orc_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2));
18063a13c3f3SRichard Henderson         tcg_gen_orc_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2));
18073a13c3f3SRichard Henderson     } else if (TCG_TARGET_HAS_orc_i64) {
1808951c6300SRichard Henderson         tcg_gen_op3_i64(INDEX_op_orc_i64, ret, arg1, arg2);
1809951c6300SRichard Henderson     } else {
1810951c6300SRichard Henderson         TCGv_i64 t0 = tcg_temp_new_i64();
1811951c6300SRichard Henderson         tcg_gen_not_i64(t0, arg2);
1812951c6300SRichard Henderson         tcg_gen_or_i64(ret, arg1, t0);
1813951c6300SRichard Henderson         tcg_temp_free_i64(t0);
1814951c6300SRichard Henderson     }
1815951c6300SRichard Henderson }
1816951c6300SRichard Henderson 
18170e28d006SRichard Henderson void tcg_gen_clz_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
18180e28d006SRichard Henderson {
18190e28d006SRichard Henderson     if (TCG_TARGET_HAS_clz_i64) {
18200e28d006SRichard Henderson         tcg_gen_op3_i64(INDEX_op_clz_i64, ret, arg1, arg2);
18210e28d006SRichard Henderson     } else {
18220e28d006SRichard Henderson         gen_helper_clz_i64(ret, arg1, arg2);
18230e28d006SRichard Henderson     }
18240e28d006SRichard Henderson }
18250e28d006SRichard Henderson 
18260e28d006SRichard Henderson void tcg_gen_clzi_i64(TCGv_i64 ret, TCGv_i64 arg1, uint64_t arg2)
18270e28d006SRichard Henderson {
18280e28d006SRichard Henderson     if (TCG_TARGET_REG_BITS == 32
18290e28d006SRichard Henderson         && TCG_TARGET_HAS_clz_i32
18300e28d006SRichard Henderson         && arg2 <= 0xffffffffu) {
18310e28d006SRichard Henderson         TCGv_i32 t = tcg_const_i32((uint32_t)arg2 - 32);
18320e28d006SRichard Henderson         tcg_gen_clz_i32(t, TCGV_LOW(arg1), t);
18330e28d006SRichard Henderson         tcg_gen_addi_i32(t, t, 32);
18340e28d006SRichard Henderson         tcg_gen_clz_i32(TCGV_LOW(ret), TCGV_HIGH(arg1), t);
18350e28d006SRichard Henderson         tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
18360e28d006SRichard Henderson         tcg_temp_free_i32(t);
18370e28d006SRichard Henderson     } else {
18380e28d006SRichard Henderson         TCGv_i64 t = tcg_const_i64(arg2);
18390e28d006SRichard Henderson         tcg_gen_clz_i64(ret, arg1, t);
18400e28d006SRichard Henderson         tcg_temp_free_i64(t);
18410e28d006SRichard Henderson     }
18420e28d006SRichard Henderson }
18430e28d006SRichard Henderson 
18440e28d006SRichard Henderson void tcg_gen_ctz_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
18450e28d006SRichard Henderson {
18460e28d006SRichard Henderson     if (TCG_TARGET_HAS_ctz_i64) {
18470e28d006SRichard Henderson         tcg_gen_op3_i64(INDEX_op_ctz_i64, ret, arg1, arg2);
184814e99210SRichard Henderson     } else if (TCG_TARGET_HAS_ctpop_i64 || TCG_TARGET_HAS_clz_i64) {
184914e99210SRichard Henderson         TCGv_i64 z, t = tcg_temp_new_i64();
185014e99210SRichard Henderson 
185114e99210SRichard Henderson         if (TCG_TARGET_HAS_ctpop_i64) {
185214e99210SRichard Henderson             tcg_gen_subi_i64(t, arg1, 1);
185314e99210SRichard Henderson             tcg_gen_andc_i64(t, t, arg1);
185414e99210SRichard Henderson             tcg_gen_ctpop_i64(t, t);
185514e99210SRichard Henderson         } else {
185614e99210SRichard Henderson             /* Since all non-x86 hosts have clz(0) == 64, don't fight it.  */
185714e99210SRichard Henderson             tcg_gen_neg_i64(t, arg1);
185814e99210SRichard Henderson             tcg_gen_and_i64(t, t, arg1);
185914e99210SRichard Henderson             tcg_gen_clzi_i64(t, t, 64);
186014e99210SRichard Henderson             tcg_gen_xori_i64(t, t, 63);
186114e99210SRichard Henderson         }
186214e99210SRichard Henderson         z = tcg_const_i64(0);
186314e99210SRichard Henderson         tcg_gen_movcond_i64(TCG_COND_EQ, ret, arg1, z, arg2, t);
186414e99210SRichard Henderson         tcg_temp_free_i64(t);
186514e99210SRichard Henderson         tcg_temp_free_i64(z);
18660e28d006SRichard Henderson     } else {
18670e28d006SRichard Henderson         gen_helper_ctz_i64(ret, arg1, arg2);
18680e28d006SRichard Henderson     }
18690e28d006SRichard Henderson }
18700e28d006SRichard Henderson 
18710e28d006SRichard Henderson void tcg_gen_ctzi_i64(TCGv_i64 ret, TCGv_i64 arg1, uint64_t arg2)
18720e28d006SRichard Henderson {
18730e28d006SRichard Henderson     if (TCG_TARGET_REG_BITS == 32
18740e28d006SRichard Henderson         && TCG_TARGET_HAS_ctz_i32
18750e28d006SRichard Henderson         && arg2 <= 0xffffffffu) {
18760e28d006SRichard Henderson         TCGv_i32 t32 = tcg_const_i32((uint32_t)arg2 - 32);
18770e28d006SRichard Henderson         tcg_gen_ctz_i32(t32, TCGV_HIGH(arg1), t32);
18780e28d006SRichard Henderson         tcg_gen_addi_i32(t32, t32, 32);
18790e28d006SRichard Henderson         tcg_gen_ctz_i32(TCGV_LOW(ret), TCGV_LOW(arg1), t32);
18800e28d006SRichard Henderson         tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
18810e28d006SRichard Henderson         tcg_temp_free_i32(t32);
188214e99210SRichard Henderson     } else if (!TCG_TARGET_HAS_ctz_i64
188314e99210SRichard Henderson                && TCG_TARGET_HAS_ctpop_i64
188414e99210SRichard Henderson                && arg2 == 64) {
188514e99210SRichard Henderson         /* This equivalence has the advantage of not requiring a fixup.  */
188614e99210SRichard Henderson         TCGv_i64 t = tcg_temp_new_i64();
188714e99210SRichard Henderson         tcg_gen_subi_i64(t, arg1, 1);
188814e99210SRichard Henderson         tcg_gen_andc_i64(t, t, arg1);
188914e99210SRichard Henderson         tcg_gen_ctpop_i64(ret, t);
189014e99210SRichard Henderson         tcg_temp_free_i64(t);
18910e28d006SRichard Henderson     } else {
18920e28d006SRichard Henderson         TCGv_i64 t64 = tcg_const_i64(arg2);
18930e28d006SRichard Henderson         tcg_gen_ctz_i64(ret, arg1, t64);
18940e28d006SRichard Henderson         tcg_temp_free_i64(t64);
18950e28d006SRichard Henderson     }
18960e28d006SRichard Henderson }
18970e28d006SRichard Henderson 
1898086920c2SRichard Henderson void tcg_gen_clrsb_i64(TCGv_i64 ret, TCGv_i64 arg)
1899086920c2SRichard Henderson {
1900086920c2SRichard Henderson     if (TCG_TARGET_HAS_clz_i64 || TCG_TARGET_HAS_clz_i32) {
1901086920c2SRichard Henderson         TCGv_i64 t = tcg_temp_new_i64();
1902086920c2SRichard Henderson         tcg_gen_sari_i64(t, arg, 63);
1903086920c2SRichard Henderson         tcg_gen_xor_i64(t, t, arg);
1904086920c2SRichard Henderson         tcg_gen_clzi_i64(t, t, 64);
1905086920c2SRichard Henderson         tcg_gen_subi_i64(ret, t, 1);
1906086920c2SRichard Henderson         tcg_temp_free_i64(t);
1907086920c2SRichard Henderson     } else {
1908086920c2SRichard Henderson         gen_helper_clrsb_i64(ret, arg);
1909086920c2SRichard Henderson     }
1910086920c2SRichard Henderson }
1911086920c2SRichard Henderson 
1912a768e4e9SRichard Henderson void tcg_gen_ctpop_i64(TCGv_i64 ret, TCGv_i64 arg1)
1913a768e4e9SRichard Henderson {
1914a768e4e9SRichard Henderson     if (TCG_TARGET_HAS_ctpop_i64) {
1915a768e4e9SRichard Henderson         tcg_gen_op2_i64(INDEX_op_ctpop_i64, ret, arg1);
1916a768e4e9SRichard Henderson     } else if (TCG_TARGET_REG_BITS == 32 && TCG_TARGET_HAS_ctpop_i32) {
1917a768e4e9SRichard Henderson         tcg_gen_ctpop_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1));
1918a768e4e9SRichard Henderson         tcg_gen_ctpop_i32(TCGV_LOW(ret), TCGV_LOW(arg1));
1919a768e4e9SRichard Henderson         tcg_gen_add_i32(TCGV_LOW(ret), TCGV_LOW(ret), TCGV_HIGH(ret));
1920a768e4e9SRichard Henderson         tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
1921a768e4e9SRichard Henderson     } else {
1922a768e4e9SRichard Henderson         gen_helper_ctpop_i64(ret, arg1);
1923a768e4e9SRichard Henderson     }
1924a768e4e9SRichard Henderson }
1925a768e4e9SRichard Henderson 
1926951c6300SRichard Henderson void tcg_gen_rotl_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
1927951c6300SRichard Henderson {
1928951c6300SRichard Henderson     if (TCG_TARGET_HAS_rot_i64) {
1929951c6300SRichard Henderson         tcg_gen_op3_i64(INDEX_op_rotl_i64, ret, arg1, arg2);
1930951c6300SRichard Henderson     } else {
1931951c6300SRichard Henderson         TCGv_i64 t0, t1;
1932951c6300SRichard Henderson         t0 = tcg_temp_new_i64();
1933951c6300SRichard Henderson         t1 = tcg_temp_new_i64();
1934951c6300SRichard Henderson         tcg_gen_shl_i64(t0, arg1, arg2);
1935951c6300SRichard Henderson         tcg_gen_subfi_i64(t1, 64, arg2);
1936951c6300SRichard Henderson         tcg_gen_shr_i64(t1, arg1, t1);
1937951c6300SRichard Henderson         tcg_gen_or_i64(ret, t0, t1);
1938951c6300SRichard Henderson         tcg_temp_free_i64(t0);
1939951c6300SRichard Henderson         tcg_temp_free_i64(t1);
1940951c6300SRichard Henderson     }
1941951c6300SRichard Henderson }
1942951c6300SRichard Henderson 
1943951c6300SRichard Henderson void tcg_gen_rotli_i64(TCGv_i64 ret, TCGv_i64 arg1, unsigned arg2)
1944951c6300SRichard Henderson {
1945951c6300SRichard Henderson     tcg_debug_assert(arg2 < 64);
1946951c6300SRichard Henderson     /* some cases can be optimized here */
1947951c6300SRichard Henderson     if (arg2 == 0) {
1948951c6300SRichard Henderson         tcg_gen_mov_i64(ret, arg1);
1949951c6300SRichard Henderson     } else if (TCG_TARGET_HAS_rot_i64) {
1950951c6300SRichard Henderson         TCGv_i64 t0 = tcg_const_i64(arg2);
1951951c6300SRichard Henderson         tcg_gen_rotl_i64(ret, arg1, t0);
1952951c6300SRichard Henderson         tcg_temp_free_i64(t0);
1953951c6300SRichard Henderson     } else {
1954951c6300SRichard Henderson         TCGv_i64 t0, t1;
1955951c6300SRichard Henderson         t0 = tcg_temp_new_i64();
1956951c6300SRichard Henderson         t1 = tcg_temp_new_i64();
1957951c6300SRichard Henderson         tcg_gen_shli_i64(t0, arg1, arg2);
1958951c6300SRichard Henderson         tcg_gen_shri_i64(t1, arg1, 64 - arg2);
1959951c6300SRichard Henderson         tcg_gen_or_i64(ret, t0, t1);
1960951c6300SRichard Henderson         tcg_temp_free_i64(t0);
1961951c6300SRichard Henderson         tcg_temp_free_i64(t1);
1962951c6300SRichard Henderson     }
1963951c6300SRichard Henderson }
1964951c6300SRichard Henderson 
1965951c6300SRichard Henderson void tcg_gen_rotr_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
1966951c6300SRichard Henderson {
1967951c6300SRichard Henderson     if (TCG_TARGET_HAS_rot_i64) {
1968951c6300SRichard Henderson         tcg_gen_op3_i64(INDEX_op_rotr_i64, ret, arg1, arg2);
1969951c6300SRichard Henderson     } else {
1970951c6300SRichard Henderson         TCGv_i64 t0, t1;
1971951c6300SRichard Henderson         t0 = tcg_temp_new_i64();
1972951c6300SRichard Henderson         t1 = tcg_temp_new_i64();
1973951c6300SRichard Henderson         tcg_gen_shr_i64(t0, arg1, arg2);
1974951c6300SRichard Henderson         tcg_gen_subfi_i64(t1, 64, arg2);
1975951c6300SRichard Henderson         tcg_gen_shl_i64(t1, arg1, t1);
1976951c6300SRichard Henderson         tcg_gen_or_i64(ret, t0, t1);
1977951c6300SRichard Henderson         tcg_temp_free_i64(t0);
1978951c6300SRichard Henderson         tcg_temp_free_i64(t1);
1979951c6300SRichard Henderson     }
1980951c6300SRichard Henderson }
1981951c6300SRichard Henderson 
1982951c6300SRichard Henderson void tcg_gen_rotri_i64(TCGv_i64 ret, TCGv_i64 arg1, unsigned arg2)
1983951c6300SRichard Henderson {
1984951c6300SRichard Henderson     tcg_debug_assert(arg2 < 64);
1985951c6300SRichard Henderson     /* some cases can be optimized here */
1986951c6300SRichard Henderson     if (arg2 == 0) {
1987951c6300SRichard Henderson         tcg_gen_mov_i64(ret, arg1);
1988951c6300SRichard Henderson     } else {
1989951c6300SRichard Henderson         tcg_gen_rotli_i64(ret, arg1, 64 - arg2);
1990951c6300SRichard Henderson     }
1991951c6300SRichard Henderson }
1992951c6300SRichard Henderson 
1993951c6300SRichard Henderson void tcg_gen_deposit_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2,
1994951c6300SRichard Henderson                          unsigned int ofs, unsigned int len)
1995951c6300SRichard Henderson {
1996951c6300SRichard Henderson     uint64_t mask;
1997951c6300SRichard Henderson     TCGv_i64 t1;
1998951c6300SRichard Henderson 
1999951c6300SRichard Henderson     tcg_debug_assert(ofs < 64);
20000d0d309dSRichard Henderson     tcg_debug_assert(len > 0);
2001951c6300SRichard Henderson     tcg_debug_assert(len <= 64);
2002951c6300SRichard Henderson     tcg_debug_assert(ofs + len <= 64);
2003951c6300SRichard Henderson 
20040d0d309dSRichard Henderson     if (len == 64) {
2005951c6300SRichard Henderson         tcg_gen_mov_i64(ret, arg2);
2006951c6300SRichard Henderson         return;
2007951c6300SRichard Henderson     }
2008951c6300SRichard Henderson     if (TCG_TARGET_HAS_deposit_i64 && TCG_TARGET_deposit_i64_valid(ofs, len)) {
2009951c6300SRichard Henderson         tcg_gen_op5ii_i64(INDEX_op_deposit_i64, ret, arg1, arg2, ofs, len);
2010951c6300SRichard Henderson         return;
2011951c6300SRichard Henderson     }
2012951c6300SRichard Henderson 
20133a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
2014951c6300SRichard Henderson         if (ofs >= 32) {
2015951c6300SRichard Henderson             tcg_gen_deposit_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1),
2016951c6300SRichard Henderson                                 TCGV_LOW(arg2), ofs - 32, len);
2017951c6300SRichard Henderson             tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg1));
2018951c6300SRichard Henderson             return;
2019951c6300SRichard Henderson         }
2020951c6300SRichard Henderson         if (ofs + len <= 32) {
2021951c6300SRichard Henderson             tcg_gen_deposit_i32(TCGV_LOW(ret), TCGV_LOW(arg1),
2022951c6300SRichard Henderson                                 TCGV_LOW(arg2), ofs, len);
2023951c6300SRichard Henderson             tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1));
2024951c6300SRichard Henderson             return;
2025951c6300SRichard Henderson         }
20263a13c3f3SRichard Henderson     }
2027951c6300SRichard Henderson 
2028951c6300SRichard Henderson     mask = (1ull << len) - 1;
2029951c6300SRichard Henderson     t1 = tcg_temp_new_i64();
2030951c6300SRichard Henderson 
2031951c6300SRichard Henderson     if (ofs + len < 64) {
2032951c6300SRichard Henderson         tcg_gen_andi_i64(t1, arg2, mask);
2033951c6300SRichard Henderson         tcg_gen_shli_i64(t1, t1, ofs);
2034951c6300SRichard Henderson     } else {
2035951c6300SRichard Henderson         tcg_gen_shli_i64(t1, arg2, ofs);
2036951c6300SRichard Henderson     }
2037951c6300SRichard Henderson     tcg_gen_andi_i64(ret, arg1, ~(mask << ofs));
2038951c6300SRichard Henderson     tcg_gen_or_i64(ret, ret, t1);
2039951c6300SRichard Henderson 
2040951c6300SRichard Henderson     tcg_temp_free_i64(t1);
2041951c6300SRichard Henderson }
2042951c6300SRichard Henderson 
204307cc68d5SRichard Henderson void tcg_gen_deposit_z_i64(TCGv_i64 ret, TCGv_i64 arg,
204407cc68d5SRichard Henderson                            unsigned int ofs, unsigned int len)
204507cc68d5SRichard Henderson {
204607cc68d5SRichard Henderson     tcg_debug_assert(ofs < 64);
204707cc68d5SRichard Henderson     tcg_debug_assert(len > 0);
204807cc68d5SRichard Henderson     tcg_debug_assert(len <= 64);
204907cc68d5SRichard Henderson     tcg_debug_assert(ofs + len <= 64);
205007cc68d5SRichard Henderson 
205107cc68d5SRichard Henderson     if (ofs + len == 64) {
205207cc68d5SRichard Henderson         tcg_gen_shli_i64(ret, arg, ofs);
205307cc68d5SRichard Henderson     } else if (ofs == 0) {
205407cc68d5SRichard Henderson         tcg_gen_andi_i64(ret, arg, (1ull << len) - 1);
205507cc68d5SRichard Henderson     } else if (TCG_TARGET_HAS_deposit_i64
205607cc68d5SRichard Henderson                && TCG_TARGET_deposit_i64_valid(ofs, len)) {
205707cc68d5SRichard Henderson         TCGv_i64 zero = tcg_const_i64(0);
205807cc68d5SRichard Henderson         tcg_gen_op5ii_i64(INDEX_op_deposit_i64, ret, zero, arg, ofs, len);
205907cc68d5SRichard Henderson         tcg_temp_free_i64(zero);
206007cc68d5SRichard Henderson     } else {
206107cc68d5SRichard Henderson         if (TCG_TARGET_REG_BITS == 32) {
206207cc68d5SRichard Henderson             if (ofs >= 32) {
206307cc68d5SRichard Henderson                 tcg_gen_deposit_z_i32(TCGV_HIGH(ret), TCGV_LOW(arg),
206407cc68d5SRichard Henderson                                       ofs - 32, len);
206507cc68d5SRichard Henderson                 tcg_gen_movi_i32(TCGV_LOW(ret), 0);
206607cc68d5SRichard Henderson                 return;
206707cc68d5SRichard Henderson             }
206807cc68d5SRichard Henderson             if (ofs + len <= 32) {
206907cc68d5SRichard Henderson                 tcg_gen_deposit_z_i32(TCGV_LOW(ret), TCGV_LOW(arg), ofs, len);
207007cc68d5SRichard Henderson                 tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
207107cc68d5SRichard Henderson                 return;
207207cc68d5SRichard Henderson             }
207307cc68d5SRichard Henderson         }
207407cc68d5SRichard Henderson         /* To help two-operand hosts we prefer to zero-extend first,
207507cc68d5SRichard Henderson            which allows ARG to stay live.  */
207607cc68d5SRichard Henderson         switch (len) {
207707cc68d5SRichard Henderson         case 32:
207807cc68d5SRichard Henderson             if (TCG_TARGET_HAS_ext32u_i64) {
207907cc68d5SRichard Henderson                 tcg_gen_ext32u_i64(ret, arg);
208007cc68d5SRichard Henderson                 tcg_gen_shli_i64(ret, ret, ofs);
208107cc68d5SRichard Henderson                 return;
208207cc68d5SRichard Henderson             }
208307cc68d5SRichard Henderson             break;
208407cc68d5SRichard Henderson         case 16:
208507cc68d5SRichard Henderson             if (TCG_TARGET_HAS_ext16u_i64) {
208607cc68d5SRichard Henderson                 tcg_gen_ext16u_i64(ret, arg);
208707cc68d5SRichard Henderson                 tcg_gen_shli_i64(ret, ret, ofs);
208807cc68d5SRichard Henderson                 return;
208907cc68d5SRichard Henderson             }
209007cc68d5SRichard Henderson             break;
209107cc68d5SRichard Henderson         case 8:
209207cc68d5SRichard Henderson             if (TCG_TARGET_HAS_ext8u_i64) {
209307cc68d5SRichard Henderson                 tcg_gen_ext8u_i64(ret, arg);
209407cc68d5SRichard Henderson                 tcg_gen_shli_i64(ret, ret, ofs);
209507cc68d5SRichard Henderson                 return;
209607cc68d5SRichard Henderson             }
209707cc68d5SRichard Henderson             break;
209807cc68d5SRichard Henderson         }
209907cc68d5SRichard Henderson         /* Otherwise prefer zero-extension over AND for code size.  */
210007cc68d5SRichard Henderson         switch (ofs + len) {
210107cc68d5SRichard Henderson         case 32:
210207cc68d5SRichard Henderson             if (TCG_TARGET_HAS_ext32u_i64) {
210307cc68d5SRichard Henderson                 tcg_gen_shli_i64(ret, arg, ofs);
210407cc68d5SRichard Henderson                 tcg_gen_ext32u_i64(ret, ret);
210507cc68d5SRichard Henderson                 return;
210607cc68d5SRichard Henderson             }
210707cc68d5SRichard Henderson             break;
210807cc68d5SRichard Henderson         case 16:
210907cc68d5SRichard Henderson             if (TCG_TARGET_HAS_ext16u_i64) {
211007cc68d5SRichard Henderson                 tcg_gen_shli_i64(ret, arg, ofs);
211107cc68d5SRichard Henderson                 tcg_gen_ext16u_i64(ret, ret);
211207cc68d5SRichard Henderson                 return;
211307cc68d5SRichard Henderson             }
211407cc68d5SRichard Henderson             break;
211507cc68d5SRichard Henderson         case 8:
211607cc68d5SRichard Henderson             if (TCG_TARGET_HAS_ext8u_i64) {
211707cc68d5SRichard Henderson                 tcg_gen_shli_i64(ret, arg, ofs);
211807cc68d5SRichard Henderson                 tcg_gen_ext8u_i64(ret, ret);
211907cc68d5SRichard Henderson                 return;
212007cc68d5SRichard Henderson             }
212107cc68d5SRichard Henderson             break;
212207cc68d5SRichard Henderson         }
212307cc68d5SRichard Henderson         tcg_gen_andi_i64(ret, arg, (1ull << len) - 1);
212407cc68d5SRichard Henderson         tcg_gen_shli_i64(ret, ret, ofs);
212507cc68d5SRichard Henderson     }
212607cc68d5SRichard Henderson }
212707cc68d5SRichard Henderson 
21287ec8bab3SRichard Henderson void tcg_gen_extract_i64(TCGv_i64 ret, TCGv_i64 arg,
21297ec8bab3SRichard Henderson                          unsigned int ofs, unsigned int len)
21307ec8bab3SRichard Henderson {
21317ec8bab3SRichard Henderson     tcg_debug_assert(ofs < 64);
21327ec8bab3SRichard Henderson     tcg_debug_assert(len > 0);
21337ec8bab3SRichard Henderson     tcg_debug_assert(len <= 64);
21347ec8bab3SRichard Henderson     tcg_debug_assert(ofs + len <= 64);
21357ec8bab3SRichard Henderson 
21367ec8bab3SRichard Henderson     /* Canonicalize certain special cases, even if extract is supported.  */
21377ec8bab3SRichard Henderson     if (ofs + len == 64) {
21387ec8bab3SRichard Henderson         tcg_gen_shri_i64(ret, arg, 64 - len);
21397ec8bab3SRichard Henderson         return;
21407ec8bab3SRichard Henderson     }
21417ec8bab3SRichard Henderson     if (ofs == 0) {
21427ec8bab3SRichard Henderson         tcg_gen_andi_i64(ret, arg, (1ull << len) - 1);
21437ec8bab3SRichard Henderson         return;
21447ec8bab3SRichard Henderson     }
21457ec8bab3SRichard Henderson 
21467ec8bab3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
21477ec8bab3SRichard Henderson         /* Look for a 32-bit extract within one of the two words.  */
21487ec8bab3SRichard Henderson         if (ofs >= 32) {
21497ec8bab3SRichard Henderson             tcg_gen_extract_i32(TCGV_LOW(ret), TCGV_HIGH(arg), ofs - 32, len);
21507ec8bab3SRichard Henderson             tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
21517ec8bab3SRichard Henderson             return;
21527ec8bab3SRichard Henderson         }
21537ec8bab3SRichard Henderson         if (ofs + len <= 32) {
21547ec8bab3SRichard Henderson             tcg_gen_extract_i32(TCGV_LOW(ret), TCGV_LOW(arg), ofs, len);
21557ec8bab3SRichard Henderson             tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
21567ec8bab3SRichard Henderson             return;
21577ec8bab3SRichard Henderson         }
21587ec8bab3SRichard Henderson         /* The field is split across two words.  One double-word
21597ec8bab3SRichard Henderson            shift is better than two double-word shifts.  */
21607ec8bab3SRichard Henderson         goto do_shift_and;
21617ec8bab3SRichard Henderson     }
21627ec8bab3SRichard Henderson 
21637ec8bab3SRichard Henderson     if (TCG_TARGET_HAS_extract_i64
21647ec8bab3SRichard Henderson         && TCG_TARGET_extract_i64_valid(ofs, len)) {
21657ec8bab3SRichard Henderson         tcg_gen_op4ii_i64(INDEX_op_extract_i64, ret, arg, ofs, len);
21667ec8bab3SRichard Henderson         return;
21677ec8bab3SRichard Henderson     }
21687ec8bab3SRichard Henderson 
21697ec8bab3SRichard Henderson     /* Assume that zero-extension, if available, is cheaper than a shift.  */
21707ec8bab3SRichard Henderson     switch (ofs + len) {
21717ec8bab3SRichard Henderson     case 32:
21727ec8bab3SRichard Henderson         if (TCG_TARGET_HAS_ext32u_i64) {
21737ec8bab3SRichard Henderson             tcg_gen_ext32u_i64(ret, arg);
21747ec8bab3SRichard Henderson             tcg_gen_shri_i64(ret, ret, ofs);
21757ec8bab3SRichard Henderson             return;
21767ec8bab3SRichard Henderson         }
21777ec8bab3SRichard Henderson         break;
21787ec8bab3SRichard Henderson     case 16:
21797ec8bab3SRichard Henderson         if (TCG_TARGET_HAS_ext16u_i64) {
21807ec8bab3SRichard Henderson             tcg_gen_ext16u_i64(ret, arg);
21817ec8bab3SRichard Henderson             tcg_gen_shri_i64(ret, ret, ofs);
21827ec8bab3SRichard Henderson             return;
21837ec8bab3SRichard Henderson         }
21847ec8bab3SRichard Henderson         break;
21857ec8bab3SRichard Henderson     case 8:
21867ec8bab3SRichard Henderson         if (TCG_TARGET_HAS_ext8u_i64) {
21877ec8bab3SRichard Henderson             tcg_gen_ext8u_i64(ret, arg);
21887ec8bab3SRichard Henderson             tcg_gen_shri_i64(ret, ret, ofs);
21897ec8bab3SRichard Henderson             return;
21907ec8bab3SRichard Henderson         }
21917ec8bab3SRichard Henderson         break;
21927ec8bab3SRichard Henderson     }
21937ec8bab3SRichard Henderson 
21947ec8bab3SRichard Henderson     /* ??? Ideally we'd know what values are available for immediate AND.
21957ec8bab3SRichard Henderson        Assume that 8 bits are available, plus the special cases of 16 and 32,
21967ec8bab3SRichard Henderson        so that we get ext8u, ext16u, and ext32u.  */
21977ec8bab3SRichard Henderson     switch (len) {
21987ec8bab3SRichard Henderson     case 1 ... 8: case 16: case 32:
21997ec8bab3SRichard Henderson     do_shift_and:
22007ec8bab3SRichard Henderson         tcg_gen_shri_i64(ret, arg, ofs);
22017ec8bab3SRichard Henderson         tcg_gen_andi_i64(ret, ret, (1ull << len) - 1);
22027ec8bab3SRichard Henderson         break;
22037ec8bab3SRichard Henderson     default:
22047ec8bab3SRichard Henderson         tcg_gen_shli_i64(ret, arg, 64 - len - ofs);
22057ec8bab3SRichard Henderson         tcg_gen_shri_i64(ret, ret, 64 - len);
22067ec8bab3SRichard Henderson         break;
22077ec8bab3SRichard Henderson     }
22087ec8bab3SRichard Henderson }
22097ec8bab3SRichard Henderson 
22107ec8bab3SRichard Henderson void tcg_gen_sextract_i64(TCGv_i64 ret, TCGv_i64 arg,
22117ec8bab3SRichard Henderson                           unsigned int ofs, unsigned int len)
22127ec8bab3SRichard Henderson {
22137ec8bab3SRichard Henderson     tcg_debug_assert(ofs < 64);
22147ec8bab3SRichard Henderson     tcg_debug_assert(len > 0);
22157ec8bab3SRichard Henderson     tcg_debug_assert(len <= 64);
22167ec8bab3SRichard Henderson     tcg_debug_assert(ofs + len <= 64);
22177ec8bab3SRichard Henderson 
22187ec8bab3SRichard Henderson     /* Canonicalize certain special cases, even if sextract is supported.  */
22197ec8bab3SRichard Henderson     if (ofs + len == 64) {
22207ec8bab3SRichard Henderson         tcg_gen_sari_i64(ret, arg, 64 - len);
22217ec8bab3SRichard Henderson         return;
22227ec8bab3SRichard Henderson     }
22237ec8bab3SRichard Henderson     if (ofs == 0) {
22247ec8bab3SRichard Henderson         switch (len) {
22257ec8bab3SRichard Henderson         case 32:
22267ec8bab3SRichard Henderson             tcg_gen_ext32s_i64(ret, arg);
22277ec8bab3SRichard Henderson             return;
22287ec8bab3SRichard Henderson         case 16:
22297ec8bab3SRichard Henderson             tcg_gen_ext16s_i64(ret, arg);
22307ec8bab3SRichard Henderson             return;
22317ec8bab3SRichard Henderson         case 8:
22327ec8bab3SRichard Henderson             tcg_gen_ext8s_i64(ret, arg);
22337ec8bab3SRichard Henderson             return;
22347ec8bab3SRichard Henderson         }
22357ec8bab3SRichard Henderson     }
22367ec8bab3SRichard Henderson 
22377ec8bab3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
22387ec8bab3SRichard Henderson         /* Look for a 32-bit extract within one of the two words.  */
22397ec8bab3SRichard Henderson         if (ofs >= 32) {
22407ec8bab3SRichard Henderson             tcg_gen_sextract_i32(TCGV_LOW(ret), TCGV_HIGH(arg), ofs - 32, len);
22417ec8bab3SRichard Henderson         } else if (ofs + len <= 32) {
22427ec8bab3SRichard Henderson             tcg_gen_sextract_i32(TCGV_LOW(ret), TCGV_LOW(arg), ofs, len);
22437ec8bab3SRichard Henderson         } else if (ofs == 0) {
22447ec8bab3SRichard Henderson             tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg));
22457ec8bab3SRichard Henderson             tcg_gen_sextract_i32(TCGV_HIGH(ret), TCGV_HIGH(arg), 0, len - 32);
22467ec8bab3SRichard Henderson             return;
22477ec8bab3SRichard Henderson         } else if (len > 32) {
22487ec8bab3SRichard Henderson             TCGv_i32 t = tcg_temp_new_i32();
22497ec8bab3SRichard Henderson             /* Extract the bits for the high word normally.  */
22507ec8bab3SRichard Henderson             tcg_gen_sextract_i32(t, TCGV_HIGH(arg), ofs + 32, len - 32);
22517ec8bab3SRichard Henderson             /* Shift the field down for the low part.  */
22527ec8bab3SRichard Henderson             tcg_gen_shri_i64(ret, arg, ofs);
22537ec8bab3SRichard Henderson             /* Overwrite the shift into the high part.  */
22547ec8bab3SRichard Henderson             tcg_gen_mov_i32(TCGV_HIGH(ret), t);
22557ec8bab3SRichard Henderson             tcg_temp_free_i32(t);
22567ec8bab3SRichard Henderson             return;
22577ec8bab3SRichard Henderson         } else {
22587ec8bab3SRichard Henderson             /* Shift the field down for the low part, such that the
22597ec8bab3SRichard Henderson                field sits at the MSB.  */
22607ec8bab3SRichard Henderson             tcg_gen_shri_i64(ret, arg, ofs + len - 32);
22617ec8bab3SRichard Henderson             /* Shift the field down from the MSB, sign extending.  */
22627ec8bab3SRichard Henderson             tcg_gen_sari_i32(TCGV_LOW(ret), TCGV_LOW(ret), 32 - len);
22637ec8bab3SRichard Henderson         }
22647ec8bab3SRichard Henderson         /* Sign-extend the field from 32 bits.  */
22657ec8bab3SRichard Henderson         tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31);
22667ec8bab3SRichard Henderson         return;
22677ec8bab3SRichard Henderson     }
22687ec8bab3SRichard Henderson 
22697ec8bab3SRichard Henderson     if (TCG_TARGET_HAS_sextract_i64
22707ec8bab3SRichard Henderson         && TCG_TARGET_extract_i64_valid(ofs, len)) {
22717ec8bab3SRichard Henderson         tcg_gen_op4ii_i64(INDEX_op_sextract_i64, ret, arg, ofs, len);
22727ec8bab3SRichard Henderson         return;
22737ec8bab3SRichard Henderson     }
22747ec8bab3SRichard Henderson 
22757ec8bab3SRichard Henderson     /* Assume that sign-extension, if available, is cheaper than a shift.  */
22767ec8bab3SRichard Henderson     switch (ofs + len) {
22777ec8bab3SRichard Henderson     case 32:
22787ec8bab3SRichard Henderson         if (TCG_TARGET_HAS_ext32s_i64) {
22797ec8bab3SRichard Henderson             tcg_gen_ext32s_i64(ret, arg);
22807ec8bab3SRichard Henderson             tcg_gen_sari_i64(ret, ret, ofs);
22817ec8bab3SRichard Henderson             return;
22827ec8bab3SRichard Henderson         }
22837ec8bab3SRichard Henderson         break;
22847ec8bab3SRichard Henderson     case 16:
22857ec8bab3SRichard Henderson         if (TCG_TARGET_HAS_ext16s_i64) {
22867ec8bab3SRichard Henderson             tcg_gen_ext16s_i64(ret, arg);
22877ec8bab3SRichard Henderson             tcg_gen_sari_i64(ret, ret, ofs);
22887ec8bab3SRichard Henderson             return;
22897ec8bab3SRichard Henderson         }
22907ec8bab3SRichard Henderson         break;
22917ec8bab3SRichard Henderson     case 8:
22927ec8bab3SRichard Henderson         if (TCG_TARGET_HAS_ext8s_i64) {
22937ec8bab3SRichard Henderson             tcg_gen_ext8s_i64(ret, arg);
22947ec8bab3SRichard Henderson             tcg_gen_sari_i64(ret, ret, ofs);
22957ec8bab3SRichard Henderson             return;
22967ec8bab3SRichard Henderson         }
22977ec8bab3SRichard Henderson         break;
22987ec8bab3SRichard Henderson     }
22997ec8bab3SRichard Henderson     switch (len) {
23007ec8bab3SRichard Henderson     case 32:
23017ec8bab3SRichard Henderson         if (TCG_TARGET_HAS_ext32s_i64) {
23027ec8bab3SRichard Henderson             tcg_gen_shri_i64(ret, arg, ofs);
23037ec8bab3SRichard Henderson             tcg_gen_ext32s_i64(ret, ret);
23047ec8bab3SRichard Henderson             return;
23057ec8bab3SRichard Henderson         }
23067ec8bab3SRichard Henderson         break;
23077ec8bab3SRichard Henderson     case 16:
23087ec8bab3SRichard Henderson         if (TCG_TARGET_HAS_ext16s_i64) {
23097ec8bab3SRichard Henderson             tcg_gen_shri_i64(ret, arg, ofs);
23107ec8bab3SRichard Henderson             tcg_gen_ext16s_i64(ret, ret);
23117ec8bab3SRichard Henderson             return;
23127ec8bab3SRichard Henderson         }
23137ec8bab3SRichard Henderson         break;
23147ec8bab3SRichard Henderson     case 8:
23157ec8bab3SRichard Henderson         if (TCG_TARGET_HAS_ext8s_i64) {
23167ec8bab3SRichard Henderson             tcg_gen_shri_i64(ret, arg, ofs);
23177ec8bab3SRichard Henderson             tcg_gen_ext8s_i64(ret, ret);
23187ec8bab3SRichard Henderson             return;
23197ec8bab3SRichard Henderson         }
23207ec8bab3SRichard Henderson         break;
23217ec8bab3SRichard Henderson     }
23227ec8bab3SRichard Henderson     tcg_gen_shli_i64(ret, arg, 64 - len - ofs);
23237ec8bab3SRichard Henderson     tcg_gen_sari_i64(ret, ret, 64 - len);
23247ec8bab3SRichard Henderson }
23257ec8bab3SRichard Henderson 
2326951c6300SRichard Henderson void tcg_gen_movcond_i64(TCGCond cond, TCGv_i64 ret, TCGv_i64 c1,
2327951c6300SRichard Henderson                          TCGv_i64 c2, TCGv_i64 v1, TCGv_i64 v2)
2328951c6300SRichard Henderson {
232937ed3bf1SRichard Henderson     if (cond == TCG_COND_ALWAYS) {
233037ed3bf1SRichard Henderson         tcg_gen_mov_i64(ret, v1);
233137ed3bf1SRichard Henderson     } else if (cond == TCG_COND_NEVER) {
233237ed3bf1SRichard Henderson         tcg_gen_mov_i64(ret, v2);
233337ed3bf1SRichard Henderson     } else if (TCG_TARGET_REG_BITS == 32) {
2334951c6300SRichard Henderson         TCGv_i32 t0 = tcg_temp_new_i32();
2335951c6300SRichard Henderson         TCGv_i32 t1 = tcg_temp_new_i32();
2336951c6300SRichard Henderson         tcg_gen_op6i_i32(INDEX_op_setcond2_i32, t0,
2337951c6300SRichard Henderson                          TCGV_LOW(c1), TCGV_HIGH(c1),
2338951c6300SRichard Henderson                          TCGV_LOW(c2), TCGV_HIGH(c2), cond);
2339951c6300SRichard Henderson 
2340951c6300SRichard Henderson         if (TCG_TARGET_HAS_movcond_i32) {
2341951c6300SRichard Henderson             tcg_gen_movi_i32(t1, 0);
2342951c6300SRichard Henderson             tcg_gen_movcond_i32(TCG_COND_NE, TCGV_LOW(ret), t0, t1,
2343951c6300SRichard Henderson                                 TCGV_LOW(v1), TCGV_LOW(v2));
2344951c6300SRichard Henderson             tcg_gen_movcond_i32(TCG_COND_NE, TCGV_HIGH(ret), t0, t1,
2345951c6300SRichard Henderson                                 TCGV_HIGH(v1), TCGV_HIGH(v2));
2346951c6300SRichard Henderson         } else {
2347951c6300SRichard Henderson             tcg_gen_neg_i32(t0, t0);
2348951c6300SRichard Henderson 
2349951c6300SRichard Henderson             tcg_gen_and_i32(t1, TCGV_LOW(v1), t0);
2350951c6300SRichard Henderson             tcg_gen_andc_i32(TCGV_LOW(ret), TCGV_LOW(v2), t0);
2351951c6300SRichard Henderson             tcg_gen_or_i32(TCGV_LOW(ret), TCGV_LOW(ret), t1);
2352951c6300SRichard Henderson 
2353951c6300SRichard Henderson             tcg_gen_and_i32(t1, TCGV_HIGH(v1), t0);
2354951c6300SRichard Henderson             tcg_gen_andc_i32(TCGV_HIGH(ret), TCGV_HIGH(v2), t0);
2355951c6300SRichard Henderson             tcg_gen_or_i32(TCGV_HIGH(ret), TCGV_HIGH(ret), t1);
2356951c6300SRichard Henderson         }
2357951c6300SRichard Henderson         tcg_temp_free_i32(t0);
2358951c6300SRichard Henderson         tcg_temp_free_i32(t1);
23593a13c3f3SRichard Henderson     } else if (TCG_TARGET_HAS_movcond_i64) {
2360951c6300SRichard Henderson         tcg_gen_op6i_i64(INDEX_op_movcond_i64, ret, c1, c2, v1, v2, cond);
2361951c6300SRichard Henderson     } else {
2362951c6300SRichard Henderson         TCGv_i64 t0 = tcg_temp_new_i64();
2363951c6300SRichard Henderson         TCGv_i64 t1 = tcg_temp_new_i64();
2364951c6300SRichard Henderson         tcg_gen_setcond_i64(cond, t0, c1, c2);
2365951c6300SRichard Henderson         tcg_gen_neg_i64(t0, t0);
2366951c6300SRichard Henderson         tcg_gen_and_i64(t1, v1, t0);
2367951c6300SRichard Henderson         tcg_gen_andc_i64(ret, v2, t0);
2368951c6300SRichard Henderson         tcg_gen_or_i64(ret, ret, t1);
2369951c6300SRichard Henderson         tcg_temp_free_i64(t0);
2370951c6300SRichard Henderson         tcg_temp_free_i64(t1);
2371951c6300SRichard Henderson     }
2372951c6300SRichard Henderson }
2373951c6300SRichard Henderson 
2374951c6300SRichard Henderson void tcg_gen_add2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 al,
2375951c6300SRichard Henderson                       TCGv_i64 ah, TCGv_i64 bl, TCGv_i64 bh)
2376951c6300SRichard Henderson {
2377951c6300SRichard Henderson     if (TCG_TARGET_HAS_add2_i64) {
2378951c6300SRichard Henderson         tcg_gen_op6_i64(INDEX_op_add2_i64, rl, rh, al, ah, bl, bh);
2379951c6300SRichard Henderson     } else {
2380951c6300SRichard Henderson         TCGv_i64 t0 = tcg_temp_new_i64();
2381951c6300SRichard Henderson         TCGv_i64 t1 = tcg_temp_new_i64();
2382951c6300SRichard Henderson         tcg_gen_add_i64(t0, al, bl);
2383951c6300SRichard Henderson         tcg_gen_setcond_i64(TCG_COND_LTU, t1, t0, al);
2384951c6300SRichard Henderson         tcg_gen_add_i64(rh, ah, bh);
2385951c6300SRichard Henderson         tcg_gen_add_i64(rh, rh, t1);
2386951c6300SRichard Henderson         tcg_gen_mov_i64(rl, t0);
2387951c6300SRichard Henderson         tcg_temp_free_i64(t0);
2388951c6300SRichard Henderson         tcg_temp_free_i64(t1);
2389951c6300SRichard Henderson     }
2390951c6300SRichard Henderson }
2391951c6300SRichard Henderson 
2392951c6300SRichard Henderson void tcg_gen_sub2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 al,
2393951c6300SRichard Henderson                       TCGv_i64 ah, TCGv_i64 bl, TCGv_i64 bh)
2394951c6300SRichard Henderson {
2395951c6300SRichard Henderson     if (TCG_TARGET_HAS_sub2_i64) {
2396951c6300SRichard Henderson         tcg_gen_op6_i64(INDEX_op_sub2_i64, rl, rh, al, ah, bl, bh);
2397951c6300SRichard Henderson     } else {
2398951c6300SRichard Henderson         TCGv_i64 t0 = tcg_temp_new_i64();
2399951c6300SRichard Henderson         TCGv_i64 t1 = tcg_temp_new_i64();
2400951c6300SRichard Henderson         tcg_gen_sub_i64(t0, al, bl);
2401951c6300SRichard Henderson         tcg_gen_setcond_i64(TCG_COND_LTU, t1, al, bl);
2402951c6300SRichard Henderson         tcg_gen_sub_i64(rh, ah, bh);
2403951c6300SRichard Henderson         tcg_gen_sub_i64(rh, rh, t1);
2404951c6300SRichard Henderson         tcg_gen_mov_i64(rl, t0);
2405951c6300SRichard Henderson         tcg_temp_free_i64(t0);
2406951c6300SRichard Henderson         tcg_temp_free_i64(t1);
2407951c6300SRichard Henderson     }
2408951c6300SRichard Henderson }
2409951c6300SRichard Henderson 
2410951c6300SRichard Henderson void tcg_gen_mulu2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 arg1, TCGv_i64 arg2)
2411951c6300SRichard Henderson {
2412951c6300SRichard Henderson     if (TCG_TARGET_HAS_mulu2_i64) {
2413951c6300SRichard Henderson         tcg_gen_op4_i64(INDEX_op_mulu2_i64, rl, rh, arg1, arg2);
2414951c6300SRichard Henderson     } else if (TCG_TARGET_HAS_muluh_i64) {
2415951c6300SRichard Henderson         TCGv_i64 t = tcg_temp_new_i64();
2416951c6300SRichard Henderson         tcg_gen_op3_i64(INDEX_op_mul_i64, t, arg1, arg2);
2417951c6300SRichard Henderson         tcg_gen_op3_i64(INDEX_op_muluh_i64, rh, arg1, arg2);
2418951c6300SRichard Henderson         tcg_gen_mov_i64(rl, t);
2419951c6300SRichard Henderson         tcg_temp_free_i64(t);
2420951c6300SRichard Henderson     } else {
2421951c6300SRichard Henderson         TCGv_i64 t0 = tcg_temp_new_i64();
2422951c6300SRichard Henderson         tcg_gen_mul_i64(t0, arg1, arg2);
2423951c6300SRichard Henderson         gen_helper_muluh_i64(rh, arg1, arg2);
2424951c6300SRichard Henderson         tcg_gen_mov_i64(rl, t0);
2425951c6300SRichard Henderson         tcg_temp_free_i64(t0);
2426951c6300SRichard Henderson     }
2427951c6300SRichard Henderson }
2428951c6300SRichard Henderson 
2429951c6300SRichard Henderson void tcg_gen_muls2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 arg1, TCGv_i64 arg2)
2430951c6300SRichard Henderson {
2431951c6300SRichard Henderson     if (TCG_TARGET_HAS_muls2_i64) {
2432951c6300SRichard Henderson         tcg_gen_op4_i64(INDEX_op_muls2_i64, rl, rh, arg1, arg2);
2433951c6300SRichard Henderson     } else if (TCG_TARGET_HAS_mulsh_i64) {
2434951c6300SRichard Henderson         TCGv_i64 t = tcg_temp_new_i64();
2435951c6300SRichard Henderson         tcg_gen_op3_i64(INDEX_op_mul_i64, t, arg1, arg2);
2436951c6300SRichard Henderson         tcg_gen_op3_i64(INDEX_op_mulsh_i64, rh, arg1, arg2);
2437951c6300SRichard Henderson         tcg_gen_mov_i64(rl, t);
2438951c6300SRichard Henderson         tcg_temp_free_i64(t);
2439951c6300SRichard Henderson     } else if (TCG_TARGET_HAS_mulu2_i64 || TCG_TARGET_HAS_muluh_i64) {
2440951c6300SRichard Henderson         TCGv_i64 t0 = tcg_temp_new_i64();
2441951c6300SRichard Henderson         TCGv_i64 t1 = tcg_temp_new_i64();
2442951c6300SRichard Henderson         TCGv_i64 t2 = tcg_temp_new_i64();
2443951c6300SRichard Henderson         TCGv_i64 t3 = tcg_temp_new_i64();
2444951c6300SRichard Henderson         tcg_gen_mulu2_i64(t0, t1, arg1, arg2);
2445951c6300SRichard Henderson         /* Adjust for negative inputs.  */
2446951c6300SRichard Henderson         tcg_gen_sari_i64(t2, arg1, 63);
2447951c6300SRichard Henderson         tcg_gen_sari_i64(t3, arg2, 63);
2448951c6300SRichard Henderson         tcg_gen_and_i64(t2, t2, arg2);
2449951c6300SRichard Henderson         tcg_gen_and_i64(t3, t3, arg1);
2450951c6300SRichard Henderson         tcg_gen_sub_i64(rh, t1, t2);
2451951c6300SRichard Henderson         tcg_gen_sub_i64(rh, rh, t3);
2452951c6300SRichard Henderson         tcg_gen_mov_i64(rl, t0);
2453951c6300SRichard Henderson         tcg_temp_free_i64(t0);
2454951c6300SRichard Henderson         tcg_temp_free_i64(t1);
2455951c6300SRichard Henderson         tcg_temp_free_i64(t2);
2456951c6300SRichard Henderson         tcg_temp_free_i64(t3);
2457951c6300SRichard Henderson     } else {
2458951c6300SRichard Henderson         TCGv_i64 t0 = tcg_temp_new_i64();
2459951c6300SRichard Henderson         tcg_gen_mul_i64(t0, arg1, arg2);
2460951c6300SRichard Henderson         gen_helper_mulsh_i64(rh, arg1, arg2);
2461951c6300SRichard Henderson         tcg_gen_mov_i64(rl, t0);
2462951c6300SRichard Henderson         tcg_temp_free_i64(t0);
2463951c6300SRichard Henderson     }
2464951c6300SRichard Henderson }
2465951c6300SRichard Henderson 
24665087abfbSRichard Henderson void tcg_gen_mulsu2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 arg1, TCGv_i64 arg2)
24675087abfbSRichard Henderson {
24685087abfbSRichard Henderson     TCGv_i64 t0 = tcg_temp_new_i64();
24695087abfbSRichard Henderson     TCGv_i64 t1 = tcg_temp_new_i64();
24705087abfbSRichard Henderson     TCGv_i64 t2 = tcg_temp_new_i64();
24715087abfbSRichard Henderson     tcg_gen_mulu2_i64(t0, t1, arg1, arg2);
24725087abfbSRichard Henderson     /* Adjust for negative input for the signed arg1.  */
24735087abfbSRichard Henderson     tcg_gen_sari_i64(t2, arg1, 63);
24745087abfbSRichard Henderson     tcg_gen_and_i64(t2, t2, arg2);
24755087abfbSRichard Henderson     tcg_gen_sub_i64(rh, t1, t2);
24765087abfbSRichard Henderson     tcg_gen_mov_i64(rl, t0);
24775087abfbSRichard Henderson     tcg_temp_free_i64(t0);
24785087abfbSRichard Henderson     tcg_temp_free_i64(t1);
24795087abfbSRichard Henderson     tcg_temp_free_i64(t2);
24805087abfbSRichard Henderson }
24815087abfbSRichard Henderson 
2482951c6300SRichard Henderson /* Size changing operations.  */
2483951c6300SRichard Henderson 
2484609ad705SRichard Henderson void tcg_gen_extrl_i64_i32(TCGv_i32 ret, TCGv_i64 arg)
2485951c6300SRichard Henderson {
24863a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
2487951c6300SRichard Henderson         tcg_gen_mov_i32(ret, TCGV_LOW(arg));
2488609ad705SRichard Henderson     } else if (TCG_TARGET_HAS_extrl_i64_i32) {
2489609ad705SRichard Henderson         tcg_gen_op2(&tcg_ctx, INDEX_op_extrl_i64_i32,
2490609ad705SRichard Henderson                     GET_TCGV_I32(ret), GET_TCGV_I64(arg));
2491951c6300SRichard Henderson     } else {
2492951c6300SRichard Henderson         tcg_gen_mov_i32(ret, MAKE_TCGV_I32(GET_TCGV_I64(arg)));
2493609ad705SRichard Henderson     }
2494609ad705SRichard Henderson }
2495609ad705SRichard Henderson 
2496609ad705SRichard Henderson void tcg_gen_extrh_i64_i32(TCGv_i32 ret, TCGv_i64 arg)
2497609ad705SRichard Henderson {
2498609ad705SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
2499609ad705SRichard Henderson         tcg_gen_mov_i32(ret, TCGV_HIGH(arg));
2500609ad705SRichard Henderson     } else if (TCG_TARGET_HAS_extrh_i64_i32) {
2501609ad705SRichard Henderson         tcg_gen_op2(&tcg_ctx, INDEX_op_extrh_i64_i32,
2502609ad705SRichard Henderson                     GET_TCGV_I32(ret), GET_TCGV_I64(arg));
2503951c6300SRichard Henderson     } else {
2504951c6300SRichard Henderson         TCGv_i64 t = tcg_temp_new_i64();
2505609ad705SRichard Henderson         tcg_gen_shri_i64(t, arg, 32);
2506951c6300SRichard Henderson         tcg_gen_mov_i32(ret, MAKE_TCGV_I32(GET_TCGV_I64(t)));
2507951c6300SRichard Henderson         tcg_temp_free_i64(t);
2508951c6300SRichard Henderson     }
2509951c6300SRichard Henderson }
2510951c6300SRichard Henderson 
2511951c6300SRichard Henderson void tcg_gen_extu_i32_i64(TCGv_i64 ret, TCGv_i32 arg)
2512951c6300SRichard Henderson {
25133a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
2514951c6300SRichard Henderson         tcg_gen_mov_i32(TCGV_LOW(ret), arg);
2515951c6300SRichard Henderson         tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
25163a13c3f3SRichard Henderson     } else {
25174f2331e5SAurelien Jarno         tcg_gen_op2(&tcg_ctx, INDEX_op_extu_i32_i64,
25184f2331e5SAurelien Jarno                     GET_TCGV_I64(ret), GET_TCGV_I32(arg));
25193a13c3f3SRichard Henderson     }
2520951c6300SRichard Henderson }
2521951c6300SRichard Henderson 
2522951c6300SRichard Henderson void tcg_gen_ext_i32_i64(TCGv_i64 ret, TCGv_i32 arg)
2523951c6300SRichard Henderson {
25243a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
2525951c6300SRichard Henderson         tcg_gen_mov_i32(TCGV_LOW(ret), arg);
2526951c6300SRichard Henderson         tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31);
25273a13c3f3SRichard Henderson     } else {
25284f2331e5SAurelien Jarno         tcg_gen_op2(&tcg_ctx, INDEX_op_ext_i32_i64,
25294f2331e5SAurelien Jarno                     GET_TCGV_I64(ret), GET_TCGV_I32(arg));
25303a13c3f3SRichard Henderson     }
2531951c6300SRichard Henderson }
2532951c6300SRichard Henderson 
2533951c6300SRichard Henderson void tcg_gen_concat_i32_i64(TCGv_i64 dest, TCGv_i32 low, TCGv_i32 high)
2534951c6300SRichard Henderson {
25353a13c3f3SRichard Henderson     TCGv_i64 tmp;
25363a13c3f3SRichard Henderson 
25373a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
2538951c6300SRichard Henderson         tcg_gen_mov_i32(TCGV_LOW(dest), low);
2539951c6300SRichard Henderson         tcg_gen_mov_i32(TCGV_HIGH(dest), high);
25403a13c3f3SRichard Henderson         return;
25413a13c3f3SRichard Henderson     }
25423a13c3f3SRichard Henderson 
25433a13c3f3SRichard Henderson     tmp = tcg_temp_new_i64();
2544951c6300SRichard Henderson     /* These extensions are only needed for type correctness.
2545951c6300SRichard Henderson        We may be able to do better given target specific information.  */
2546951c6300SRichard Henderson     tcg_gen_extu_i32_i64(tmp, high);
2547951c6300SRichard Henderson     tcg_gen_extu_i32_i64(dest, low);
2548951c6300SRichard Henderson     /* If deposit is available, use it.  Otherwise use the extra
2549951c6300SRichard Henderson        knowledge that we have of the zero-extensions above.  */
2550951c6300SRichard Henderson     if (TCG_TARGET_HAS_deposit_i64 && TCG_TARGET_deposit_i64_valid(32, 32)) {
2551951c6300SRichard Henderson         tcg_gen_deposit_i64(dest, dest, tmp, 32, 32);
2552951c6300SRichard Henderson     } else {
2553951c6300SRichard Henderson         tcg_gen_shli_i64(tmp, tmp, 32);
2554951c6300SRichard Henderson         tcg_gen_or_i64(dest, dest, tmp);
2555951c6300SRichard Henderson     }
2556951c6300SRichard Henderson     tcg_temp_free_i64(tmp);
2557951c6300SRichard Henderson }
2558951c6300SRichard Henderson 
2559951c6300SRichard Henderson void tcg_gen_extr_i64_i32(TCGv_i32 lo, TCGv_i32 hi, TCGv_i64 arg)
2560951c6300SRichard Henderson {
25613a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
2562951c6300SRichard Henderson         tcg_gen_mov_i32(lo, TCGV_LOW(arg));
2563951c6300SRichard Henderson         tcg_gen_mov_i32(hi, TCGV_HIGH(arg));
25643a13c3f3SRichard Henderson     } else {
2565609ad705SRichard Henderson         tcg_gen_extrl_i64_i32(lo, arg);
2566609ad705SRichard Henderson         tcg_gen_extrh_i64_i32(hi, arg);
25673a13c3f3SRichard Henderson     }
2568951c6300SRichard Henderson }
2569951c6300SRichard Henderson 
2570951c6300SRichard Henderson void tcg_gen_extr32_i64(TCGv_i64 lo, TCGv_i64 hi, TCGv_i64 arg)
2571951c6300SRichard Henderson {
2572951c6300SRichard Henderson     tcg_gen_ext32u_i64(lo, arg);
2573951c6300SRichard Henderson     tcg_gen_shri_i64(hi, arg, 32);
2574951c6300SRichard Henderson }
2575951c6300SRichard Henderson 
2576951c6300SRichard Henderson /* QEMU specific operations.  */
2577951c6300SRichard Henderson 
2578951c6300SRichard Henderson void tcg_gen_goto_tb(unsigned idx)
2579951c6300SRichard Henderson {
2580951c6300SRichard Henderson     /* We only support two chained exits.  */
2581951c6300SRichard Henderson     tcg_debug_assert(idx <= 1);
2582951c6300SRichard Henderson #ifdef CONFIG_DEBUG_TCG
2583951c6300SRichard Henderson     /* Verify that we havn't seen this numbered exit before.  */
2584951c6300SRichard Henderson     tcg_debug_assert((tcg_ctx.goto_tb_issue_mask & (1 << idx)) == 0);
2585951c6300SRichard Henderson     tcg_ctx.goto_tb_issue_mask |= 1 << idx;
2586951c6300SRichard Henderson #endif
2587951c6300SRichard Henderson     tcg_gen_op1i(INDEX_op_goto_tb, idx);
2588951c6300SRichard Henderson }
2589951c6300SRichard Henderson 
2590951c6300SRichard Henderson static inline TCGMemOp tcg_canonicalize_memop(TCGMemOp op, bool is64, bool st)
2591951c6300SRichard Henderson {
25921f00b27fSSergey Sorokin     /* Trigger the asserts within as early as possible.  */
25931f00b27fSSergey Sorokin     (void)get_alignment_bits(op);
25941f00b27fSSergey Sorokin 
2595951c6300SRichard Henderson     switch (op & MO_SIZE) {
2596951c6300SRichard Henderson     case MO_8:
2597951c6300SRichard Henderson         op &= ~MO_BSWAP;
2598951c6300SRichard Henderson         break;
2599951c6300SRichard Henderson     case MO_16:
2600951c6300SRichard Henderson         break;
2601951c6300SRichard Henderson     case MO_32:
2602951c6300SRichard Henderson         if (!is64) {
2603951c6300SRichard Henderson             op &= ~MO_SIGN;
2604951c6300SRichard Henderson         }
2605951c6300SRichard Henderson         break;
2606951c6300SRichard Henderson     case MO_64:
2607951c6300SRichard Henderson         if (!is64) {
2608951c6300SRichard Henderson             tcg_abort();
2609951c6300SRichard Henderson         }
2610951c6300SRichard Henderson         break;
2611951c6300SRichard Henderson     }
2612951c6300SRichard Henderson     if (st) {
2613951c6300SRichard Henderson         op &= ~MO_SIGN;
2614951c6300SRichard Henderson     }
2615951c6300SRichard Henderson     return op;
2616951c6300SRichard Henderson }
2617951c6300SRichard Henderson 
2618c45cb8bbSRichard Henderson static void gen_ldst_i32(TCGOpcode opc, TCGv_i32 val, TCGv addr,
2619c45cb8bbSRichard Henderson                          TCGMemOp memop, TCGArg idx)
2620951c6300SRichard Henderson {
262159227d5dSRichard Henderson     TCGMemOpIdx oi = make_memop_idx(memop, idx);
2622951c6300SRichard Henderson #if TARGET_LONG_BITS == 32
262359227d5dSRichard Henderson     tcg_gen_op3i_i32(opc, val, addr, oi);
2624951c6300SRichard Henderson #else
2625c45cb8bbSRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
262659227d5dSRichard Henderson         tcg_gen_op4i_i32(opc, val, TCGV_LOW(addr), TCGV_HIGH(addr), oi);
2627c45cb8bbSRichard Henderson     } else {
262859227d5dSRichard Henderson         tcg_gen_op3(&tcg_ctx, opc, GET_TCGV_I32(val), GET_TCGV_I64(addr), oi);
2629c45cb8bbSRichard Henderson     }
2630951c6300SRichard Henderson #endif
2631c45cb8bbSRichard Henderson }
2632c45cb8bbSRichard Henderson 
2633c45cb8bbSRichard Henderson static void gen_ldst_i64(TCGOpcode opc, TCGv_i64 val, TCGv addr,
2634c45cb8bbSRichard Henderson                          TCGMemOp memop, TCGArg idx)
2635c45cb8bbSRichard Henderson {
263659227d5dSRichard Henderson     TCGMemOpIdx oi = make_memop_idx(memop, idx);
2637c45cb8bbSRichard Henderson #if TARGET_LONG_BITS == 32
2638c45cb8bbSRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
263959227d5dSRichard Henderson         tcg_gen_op4i_i32(opc, TCGV_LOW(val), TCGV_HIGH(val), addr, oi);
2640c45cb8bbSRichard Henderson     } else {
264159227d5dSRichard Henderson         tcg_gen_op3(&tcg_ctx, opc, GET_TCGV_I64(val), GET_TCGV_I32(addr), oi);
2642c45cb8bbSRichard Henderson     }
2643c45cb8bbSRichard Henderson #else
2644c45cb8bbSRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
264559227d5dSRichard Henderson         tcg_gen_op5i_i32(opc, TCGV_LOW(val), TCGV_HIGH(val),
264659227d5dSRichard Henderson                          TCGV_LOW(addr), TCGV_HIGH(addr), oi);
2647c45cb8bbSRichard Henderson     } else {
264859227d5dSRichard Henderson         tcg_gen_op3i_i64(opc, val, addr, oi);
2649c45cb8bbSRichard Henderson     }
2650c45cb8bbSRichard Henderson #endif
2651c45cb8bbSRichard Henderson }
2652951c6300SRichard Henderson 
2653951c6300SRichard Henderson void tcg_gen_qemu_ld_i32(TCGv_i32 val, TCGv addr, TCGArg idx, TCGMemOp memop)
2654951c6300SRichard Henderson {
2655951c6300SRichard Henderson     memop = tcg_canonicalize_memop(memop, 0, 0);
2656dcdaadb6SLluís Vilanova     trace_guest_mem_before_tcg(tcg_ctx.cpu, tcg_ctx.tcg_env,
2657dcdaadb6SLluís Vilanova                                addr, trace_mem_get_info(memop, 0));
2658c45cb8bbSRichard Henderson     gen_ldst_i32(INDEX_op_qemu_ld_i32, val, addr, memop, idx);
2659951c6300SRichard Henderson }
2660951c6300SRichard Henderson 
2661951c6300SRichard Henderson void tcg_gen_qemu_st_i32(TCGv_i32 val, TCGv addr, TCGArg idx, TCGMemOp memop)
2662951c6300SRichard Henderson {
2663951c6300SRichard Henderson     memop = tcg_canonicalize_memop(memop, 0, 1);
2664dcdaadb6SLluís Vilanova     trace_guest_mem_before_tcg(tcg_ctx.cpu, tcg_ctx.tcg_env,
2665dcdaadb6SLluís Vilanova                                addr, trace_mem_get_info(memop, 1));
2666c45cb8bbSRichard Henderson     gen_ldst_i32(INDEX_op_qemu_st_i32, val, addr, memop, idx);
2667951c6300SRichard Henderson }
2668951c6300SRichard Henderson 
2669951c6300SRichard Henderson void tcg_gen_qemu_ld_i64(TCGv_i64 val, TCGv addr, TCGArg idx, TCGMemOp memop)
2670951c6300SRichard Henderson {
26713a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && (memop & MO_SIZE) < MO_64) {
2672951c6300SRichard Henderson         tcg_gen_qemu_ld_i32(TCGV_LOW(val), addr, idx, memop);
2673951c6300SRichard Henderson         if (memop & MO_SIGN) {
2674951c6300SRichard Henderson             tcg_gen_sari_i32(TCGV_HIGH(val), TCGV_LOW(val), 31);
2675951c6300SRichard Henderson         } else {
2676951c6300SRichard Henderson             tcg_gen_movi_i32(TCGV_HIGH(val), 0);
2677951c6300SRichard Henderson         }
2678951c6300SRichard Henderson         return;
2679951c6300SRichard Henderson     }
2680951c6300SRichard Henderson 
2681c45cb8bbSRichard Henderson     memop = tcg_canonicalize_memop(memop, 1, 0);
2682dcdaadb6SLluís Vilanova     trace_guest_mem_before_tcg(tcg_ctx.cpu, tcg_ctx.tcg_env,
2683dcdaadb6SLluís Vilanova                                addr, trace_mem_get_info(memop, 0));
2684c45cb8bbSRichard Henderson     gen_ldst_i64(INDEX_op_qemu_ld_i64, val, addr, memop, idx);
2685951c6300SRichard Henderson }
2686951c6300SRichard Henderson 
2687951c6300SRichard Henderson void tcg_gen_qemu_st_i64(TCGv_i64 val, TCGv addr, TCGArg idx, TCGMemOp memop)
2688951c6300SRichard Henderson {
26893a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && (memop & MO_SIZE) < MO_64) {
2690951c6300SRichard Henderson         tcg_gen_qemu_st_i32(TCGV_LOW(val), addr, idx, memop);
2691951c6300SRichard Henderson         return;
2692951c6300SRichard Henderson     }
2693951c6300SRichard Henderson 
2694c45cb8bbSRichard Henderson     memop = tcg_canonicalize_memop(memop, 1, 1);
2695dcdaadb6SLluís Vilanova     trace_guest_mem_before_tcg(tcg_ctx.cpu, tcg_ctx.tcg_env,
2696dcdaadb6SLluís Vilanova                                addr, trace_mem_get_info(memop, 1));
2697c45cb8bbSRichard Henderson     gen_ldst_i64(INDEX_op_qemu_st_i64, val, addr, memop, idx);
2698951c6300SRichard Henderson }
2699c482cb11SRichard Henderson 
2700c482cb11SRichard Henderson static void tcg_gen_ext_i32(TCGv_i32 ret, TCGv_i32 val, TCGMemOp opc)
2701c482cb11SRichard Henderson {
2702c482cb11SRichard Henderson     switch (opc & MO_SSIZE) {
2703c482cb11SRichard Henderson     case MO_SB:
2704c482cb11SRichard Henderson         tcg_gen_ext8s_i32(ret, val);
2705c482cb11SRichard Henderson         break;
2706c482cb11SRichard Henderson     case MO_UB:
2707c482cb11SRichard Henderson         tcg_gen_ext8u_i32(ret, val);
2708c482cb11SRichard Henderson         break;
2709c482cb11SRichard Henderson     case MO_SW:
2710c482cb11SRichard Henderson         tcg_gen_ext16s_i32(ret, val);
2711c482cb11SRichard Henderson         break;
2712c482cb11SRichard Henderson     case MO_UW:
2713c482cb11SRichard Henderson         tcg_gen_ext16u_i32(ret, val);
2714c482cb11SRichard Henderson         break;
2715c482cb11SRichard Henderson     default:
2716c482cb11SRichard Henderson         tcg_gen_mov_i32(ret, val);
2717c482cb11SRichard Henderson         break;
2718c482cb11SRichard Henderson     }
2719c482cb11SRichard Henderson }
2720c482cb11SRichard Henderson 
2721c482cb11SRichard Henderson static void tcg_gen_ext_i64(TCGv_i64 ret, TCGv_i64 val, TCGMemOp opc)
2722c482cb11SRichard Henderson {
2723c482cb11SRichard Henderson     switch (opc & MO_SSIZE) {
2724c482cb11SRichard Henderson     case MO_SB:
2725c482cb11SRichard Henderson         tcg_gen_ext8s_i64(ret, val);
2726c482cb11SRichard Henderson         break;
2727c482cb11SRichard Henderson     case MO_UB:
2728c482cb11SRichard Henderson         tcg_gen_ext8u_i64(ret, val);
2729c482cb11SRichard Henderson         break;
2730c482cb11SRichard Henderson     case MO_SW:
2731c482cb11SRichard Henderson         tcg_gen_ext16s_i64(ret, val);
2732c482cb11SRichard Henderson         break;
2733c482cb11SRichard Henderson     case MO_UW:
2734c482cb11SRichard Henderson         tcg_gen_ext16u_i64(ret, val);
2735c482cb11SRichard Henderson         break;
2736c482cb11SRichard Henderson     case MO_SL:
2737c482cb11SRichard Henderson         tcg_gen_ext32s_i64(ret, val);
2738c482cb11SRichard Henderson         break;
2739c482cb11SRichard Henderson     case MO_UL:
2740c482cb11SRichard Henderson         tcg_gen_ext32u_i64(ret, val);
2741c482cb11SRichard Henderson         break;
2742c482cb11SRichard Henderson     default:
2743c482cb11SRichard Henderson         tcg_gen_mov_i64(ret, val);
2744c482cb11SRichard Henderson         break;
2745c482cb11SRichard Henderson     }
2746c482cb11SRichard Henderson }
2747c482cb11SRichard Henderson 
2748c482cb11SRichard Henderson #ifdef CONFIG_SOFTMMU
2749c482cb11SRichard Henderson typedef void (*gen_atomic_cx_i32)(TCGv_i32, TCGv_env, TCGv,
2750c482cb11SRichard Henderson                                   TCGv_i32, TCGv_i32, TCGv_i32);
2751c482cb11SRichard Henderson typedef void (*gen_atomic_cx_i64)(TCGv_i64, TCGv_env, TCGv,
2752c482cb11SRichard Henderson                                   TCGv_i64, TCGv_i64, TCGv_i32);
2753c482cb11SRichard Henderson typedef void (*gen_atomic_op_i32)(TCGv_i32, TCGv_env, TCGv,
2754c482cb11SRichard Henderson                                   TCGv_i32, TCGv_i32);
2755c482cb11SRichard Henderson typedef void (*gen_atomic_op_i64)(TCGv_i64, TCGv_env, TCGv,
2756c482cb11SRichard Henderson                                   TCGv_i64, TCGv_i32);
2757c482cb11SRichard Henderson #else
2758c482cb11SRichard Henderson typedef void (*gen_atomic_cx_i32)(TCGv_i32, TCGv_env, TCGv, TCGv_i32, TCGv_i32);
2759c482cb11SRichard Henderson typedef void (*gen_atomic_cx_i64)(TCGv_i64, TCGv_env, TCGv, TCGv_i64, TCGv_i64);
2760c482cb11SRichard Henderson typedef void (*gen_atomic_op_i32)(TCGv_i32, TCGv_env, TCGv, TCGv_i32);
2761c482cb11SRichard Henderson typedef void (*gen_atomic_op_i64)(TCGv_i64, TCGv_env, TCGv, TCGv_i64);
2762c482cb11SRichard Henderson #endif
2763c482cb11SRichard Henderson 
2764df79b996SRichard Henderson #ifdef CONFIG_ATOMIC64
2765df79b996SRichard Henderson # define WITH_ATOMIC64(X) X,
2766df79b996SRichard Henderson #else
2767df79b996SRichard Henderson # define WITH_ATOMIC64(X)
2768df79b996SRichard Henderson #endif
2769df79b996SRichard Henderson 
2770c482cb11SRichard Henderson static void * const table_cmpxchg[16] = {
2771c482cb11SRichard Henderson     [MO_8] = gen_helper_atomic_cmpxchgb,
2772c482cb11SRichard Henderson     [MO_16 | MO_LE] = gen_helper_atomic_cmpxchgw_le,
2773c482cb11SRichard Henderson     [MO_16 | MO_BE] = gen_helper_atomic_cmpxchgw_be,
2774c482cb11SRichard Henderson     [MO_32 | MO_LE] = gen_helper_atomic_cmpxchgl_le,
2775c482cb11SRichard Henderson     [MO_32 | MO_BE] = gen_helper_atomic_cmpxchgl_be,
2776df79b996SRichard Henderson     WITH_ATOMIC64([MO_64 | MO_LE] = gen_helper_atomic_cmpxchgq_le)
2777df79b996SRichard Henderson     WITH_ATOMIC64([MO_64 | MO_BE] = gen_helper_atomic_cmpxchgq_be)
2778c482cb11SRichard Henderson };
2779c482cb11SRichard Henderson 
2780c482cb11SRichard Henderson void tcg_gen_atomic_cmpxchg_i32(TCGv_i32 retv, TCGv addr, TCGv_i32 cmpv,
2781c482cb11SRichard Henderson                                 TCGv_i32 newv, TCGArg idx, TCGMemOp memop)
2782c482cb11SRichard Henderson {
2783c482cb11SRichard Henderson     memop = tcg_canonicalize_memop(memop, 0, 0);
2784c482cb11SRichard Henderson 
2785c482cb11SRichard Henderson     if (!parallel_cpus) {
2786c482cb11SRichard Henderson         TCGv_i32 t1 = tcg_temp_new_i32();
2787c482cb11SRichard Henderson         TCGv_i32 t2 = tcg_temp_new_i32();
2788c482cb11SRichard Henderson 
2789c482cb11SRichard Henderson         tcg_gen_ext_i32(t2, cmpv, memop & MO_SIZE);
2790c482cb11SRichard Henderson 
2791c482cb11SRichard Henderson         tcg_gen_qemu_ld_i32(t1, addr, idx, memop & ~MO_SIGN);
2792c482cb11SRichard Henderson         tcg_gen_movcond_i32(TCG_COND_EQ, t2, t1, t2, newv, t1);
2793c482cb11SRichard Henderson         tcg_gen_qemu_st_i32(t2, addr, idx, memop);
2794c482cb11SRichard Henderson         tcg_temp_free_i32(t2);
2795c482cb11SRichard Henderson 
2796c482cb11SRichard Henderson         if (memop & MO_SIGN) {
2797c482cb11SRichard Henderson             tcg_gen_ext_i32(retv, t1, memop);
2798c482cb11SRichard Henderson         } else {
2799c482cb11SRichard Henderson             tcg_gen_mov_i32(retv, t1);
2800c482cb11SRichard Henderson         }
2801c482cb11SRichard Henderson         tcg_temp_free_i32(t1);
2802c482cb11SRichard Henderson     } else {
2803c482cb11SRichard Henderson         gen_atomic_cx_i32 gen;
2804c482cb11SRichard Henderson 
2805c482cb11SRichard Henderson         gen = table_cmpxchg[memop & (MO_SIZE | MO_BSWAP)];
2806c482cb11SRichard Henderson         tcg_debug_assert(gen != NULL);
2807c482cb11SRichard Henderson 
2808c482cb11SRichard Henderson #ifdef CONFIG_SOFTMMU
2809c482cb11SRichard Henderson         {
2810c482cb11SRichard Henderson             TCGv_i32 oi = tcg_const_i32(make_memop_idx(memop & ~MO_SIGN, idx));
2811c482cb11SRichard Henderson             gen(retv, tcg_ctx.tcg_env, addr, cmpv, newv, oi);
2812c482cb11SRichard Henderson             tcg_temp_free_i32(oi);
2813c482cb11SRichard Henderson         }
2814c482cb11SRichard Henderson #else
2815c482cb11SRichard Henderson         gen(retv, tcg_ctx.tcg_env, addr, cmpv, newv);
2816c482cb11SRichard Henderson #endif
2817c482cb11SRichard Henderson 
2818c482cb11SRichard Henderson         if (memop & MO_SIGN) {
2819c482cb11SRichard Henderson             tcg_gen_ext_i32(retv, retv, memop);
2820c482cb11SRichard Henderson         }
2821c482cb11SRichard Henderson     }
2822c482cb11SRichard Henderson }
2823c482cb11SRichard Henderson 
2824c482cb11SRichard Henderson void tcg_gen_atomic_cmpxchg_i64(TCGv_i64 retv, TCGv addr, TCGv_i64 cmpv,
2825c482cb11SRichard Henderson                                 TCGv_i64 newv, TCGArg idx, TCGMemOp memop)
2826c482cb11SRichard Henderson {
2827c482cb11SRichard Henderson     memop = tcg_canonicalize_memop(memop, 1, 0);
2828c482cb11SRichard Henderson 
2829c482cb11SRichard Henderson     if (!parallel_cpus) {
2830c482cb11SRichard Henderson         TCGv_i64 t1 = tcg_temp_new_i64();
2831c482cb11SRichard Henderson         TCGv_i64 t2 = tcg_temp_new_i64();
2832c482cb11SRichard Henderson 
2833c482cb11SRichard Henderson         tcg_gen_ext_i64(t2, cmpv, memop & MO_SIZE);
2834c482cb11SRichard Henderson 
2835c482cb11SRichard Henderson         tcg_gen_qemu_ld_i64(t1, addr, idx, memop & ~MO_SIGN);
2836c482cb11SRichard Henderson         tcg_gen_movcond_i64(TCG_COND_EQ, t2, t1, t2, newv, t1);
2837c482cb11SRichard Henderson         tcg_gen_qemu_st_i64(t2, addr, idx, memop);
2838c482cb11SRichard Henderson         tcg_temp_free_i64(t2);
2839c482cb11SRichard Henderson 
2840c482cb11SRichard Henderson         if (memop & MO_SIGN) {
2841c482cb11SRichard Henderson             tcg_gen_ext_i64(retv, t1, memop);
2842c482cb11SRichard Henderson         } else {
2843c482cb11SRichard Henderson             tcg_gen_mov_i64(retv, t1);
2844c482cb11SRichard Henderson         }
2845c482cb11SRichard Henderson         tcg_temp_free_i64(t1);
2846c482cb11SRichard Henderson     } else if ((memop & MO_SIZE) == MO_64) {
2847df79b996SRichard Henderson #ifdef CONFIG_ATOMIC64
2848c482cb11SRichard Henderson         gen_atomic_cx_i64 gen;
2849c482cb11SRichard Henderson 
2850c482cb11SRichard Henderson         gen = table_cmpxchg[memop & (MO_SIZE | MO_BSWAP)];
2851c482cb11SRichard Henderson         tcg_debug_assert(gen != NULL);
2852c482cb11SRichard Henderson 
2853c482cb11SRichard Henderson #ifdef CONFIG_SOFTMMU
2854c482cb11SRichard Henderson         {
2855c482cb11SRichard Henderson             TCGv_i32 oi = tcg_const_i32(make_memop_idx(memop, idx));
2856c482cb11SRichard Henderson             gen(retv, tcg_ctx.tcg_env, addr, cmpv, newv, oi);
2857c482cb11SRichard Henderson             tcg_temp_free_i32(oi);
2858c482cb11SRichard Henderson         }
2859c482cb11SRichard Henderson #else
2860c482cb11SRichard Henderson         gen(retv, tcg_ctx.tcg_env, addr, cmpv, newv);
2861c482cb11SRichard Henderson #endif
2862df79b996SRichard Henderson #else
2863df79b996SRichard Henderson         gen_helper_exit_atomic(tcg_ctx.tcg_env);
2864*79b1af90SRichard Henderson         /* Produce a result, so that we have a well-formed opcode stream
2865*79b1af90SRichard Henderson            with respect to uses of the result in the (dead) code following.  */
2866*79b1af90SRichard Henderson         tcg_gen_movi_i64(retv, 0);
2867df79b996SRichard Henderson #endif /* CONFIG_ATOMIC64 */
2868c482cb11SRichard Henderson     } else {
2869c482cb11SRichard Henderson         TCGv_i32 c32 = tcg_temp_new_i32();
2870c482cb11SRichard Henderson         TCGv_i32 n32 = tcg_temp_new_i32();
2871c482cb11SRichard Henderson         TCGv_i32 r32 = tcg_temp_new_i32();
2872c482cb11SRichard Henderson 
2873c482cb11SRichard Henderson         tcg_gen_extrl_i64_i32(c32, cmpv);
2874c482cb11SRichard Henderson         tcg_gen_extrl_i64_i32(n32, newv);
2875c482cb11SRichard Henderson         tcg_gen_atomic_cmpxchg_i32(r32, addr, c32, n32, idx, memop & ~MO_SIGN);
2876c482cb11SRichard Henderson         tcg_temp_free_i32(c32);
2877c482cb11SRichard Henderson         tcg_temp_free_i32(n32);
2878c482cb11SRichard Henderson 
2879c482cb11SRichard Henderson         tcg_gen_extu_i32_i64(retv, r32);
2880c482cb11SRichard Henderson         tcg_temp_free_i32(r32);
2881c482cb11SRichard Henderson 
2882c482cb11SRichard Henderson         if (memop & MO_SIGN) {
2883c482cb11SRichard Henderson             tcg_gen_ext_i64(retv, retv, memop);
2884c482cb11SRichard Henderson         }
2885c482cb11SRichard Henderson     }
2886c482cb11SRichard Henderson }
2887c482cb11SRichard Henderson 
2888c482cb11SRichard Henderson static void do_nonatomic_op_i32(TCGv_i32 ret, TCGv addr, TCGv_i32 val,
2889c482cb11SRichard Henderson                                 TCGArg idx, TCGMemOp memop, bool new_val,
2890c482cb11SRichard Henderson                                 void (*gen)(TCGv_i32, TCGv_i32, TCGv_i32))
2891c482cb11SRichard Henderson {
2892c482cb11SRichard Henderson     TCGv_i32 t1 = tcg_temp_new_i32();
2893c482cb11SRichard Henderson     TCGv_i32 t2 = tcg_temp_new_i32();
2894c482cb11SRichard Henderson 
2895c482cb11SRichard Henderson     memop = tcg_canonicalize_memop(memop, 0, 0);
2896c482cb11SRichard Henderson 
2897c482cb11SRichard Henderson     tcg_gen_qemu_ld_i32(t1, addr, idx, memop & ~MO_SIGN);
2898c482cb11SRichard Henderson     gen(t2, t1, val);
2899c482cb11SRichard Henderson     tcg_gen_qemu_st_i32(t2, addr, idx, memop);
2900c482cb11SRichard Henderson 
2901c482cb11SRichard Henderson     tcg_gen_ext_i32(ret, (new_val ? t2 : t1), memop);
2902c482cb11SRichard Henderson     tcg_temp_free_i32(t1);
2903c482cb11SRichard Henderson     tcg_temp_free_i32(t2);
2904c482cb11SRichard Henderson }
2905c482cb11SRichard Henderson 
2906c482cb11SRichard Henderson static void do_atomic_op_i32(TCGv_i32 ret, TCGv addr, TCGv_i32 val,
2907c482cb11SRichard Henderson                              TCGArg idx, TCGMemOp memop, void * const table[])
2908c482cb11SRichard Henderson {
2909c482cb11SRichard Henderson     gen_atomic_op_i32 gen;
2910c482cb11SRichard Henderson 
2911c482cb11SRichard Henderson     memop = tcg_canonicalize_memop(memop, 0, 0);
2912c482cb11SRichard Henderson 
2913c482cb11SRichard Henderson     gen = table[memop & (MO_SIZE | MO_BSWAP)];
2914c482cb11SRichard Henderson     tcg_debug_assert(gen != NULL);
2915c482cb11SRichard Henderson 
2916c482cb11SRichard Henderson #ifdef CONFIG_SOFTMMU
2917c482cb11SRichard Henderson     {
2918c482cb11SRichard Henderson         TCGv_i32 oi = tcg_const_i32(make_memop_idx(memop & ~MO_SIGN, idx));
2919c482cb11SRichard Henderson         gen(ret, tcg_ctx.tcg_env, addr, val, oi);
2920c482cb11SRichard Henderson         tcg_temp_free_i32(oi);
2921c482cb11SRichard Henderson     }
2922c482cb11SRichard Henderson #else
2923c482cb11SRichard Henderson     gen(ret, tcg_ctx.tcg_env, addr, val);
2924c482cb11SRichard Henderson #endif
2925c482cb11SRichard Henderson 
2926c482cb11SRichard Henderson     if (memop & MO_SIGN) {
2927c482cb11SRichard Henderson         tcg_gen_ext_i32(ret, ret, memop);
2928c482cb11SRichard Henderson     }
2929c482cb11SRichard Henderson }
2930c482cb11SRichard Henderson 
2931c482cb11SRichard Henderson static void do_nonatomic_op_i64(TCGv_i64 ret, TCGv addr, TCGv_i64 val,
2932c482cb11SRichard Henderson                                 TCGArg idx, TCGMemOp memop, bool new_val,
2933c482cb11SRichard Henderson                                 void (*gen)(TCGv_i64, TCGv_i64, TCGv_i64))
2934c482cb11SRichard Henderson {
2935c482cb11SRichard Henderson     TCGv_i64 t1 = tcg_temp_new_i64();
2936c482cb11SRichard Henderson     TCGv_i64 t2 = tcg_temp_new_i64();
2937c482cb11SRichard Henderson 
2938c482cb11SRichard Henderson     memop = tcg_canonicalize_memop(memop, 1, 0);
2939c482cb11SRichard Henderson 
2940c482cb11SRichard Henderson     tcg_gen_qemu_ld_i64(t1, addr, idx, memop & ~MO_SIGN);
2941c482cb11SRichard Henderson     gen(t2, t1, val);
2942c482cb11SRichard Henderson     tcg_gen_qemu_st_i64(t2, addr, idx, memop);
2943c482cb11SRichard Henderson 
2944c482cb11SRichard Henderson     tcg_gen_ext_i64(ret, (new_val ? t2 : t1), memop);
2945c482cb11SRichard Henderson     tcg_temp_free_i64(t1);
2946c482cb11SRichard Henderson     tcg_temp_free_i64(t2);
2947c482cb11SRichard Henderson }
2948c482cb11SRichard Henderson 
2949c482cb11SRichard Henderson static void do_atomic_op_i64(TCGv_i64 ret, TCGv addr, TCGv_i64 val,
2950c482cb11SRichard Henderson                              TCGArg idx, TCGMemOp memop, void * const table[])
2951c482cb11SRichard Henderson {
2952c482cb11SRichard Henderson     memop = tcg_canonicalize_memop(memop, 1, 0);
2953c482cb11SRichard Henderson 
2954c482cb11SRichard Henderson     if ((memop & MO_SIZE) == MO_64) {
2955df79b996SRichard Henderson #ifdef CONFIG_ATOMIC64
2956c482cb11SRichard Henderson         gen_atomic_op_i64 gen;
2957c482cb11SRichard Henderson 
2958c482cb11SRichard Henderson         gen = table[memop & (MO_SIZE | MO_BSWAP)];
2959c482cb11SRichard Henderson         tcg_debug_assert(gen != NULL);
2960c482cb11SRichard Henderson 
2961c482cb11SRichard Henderson #ifdef CONFIG_SOFTMMU
2962c482cb11SRichard Henderson         {
2963c482cb11SRichard Henderson             TCGv_i32 oi = tcg_const_i32(make_memop_idx(memop & ~MO_SIGN, idx));
2964c482cb11SRichard Henderson             gen(ret, tcg_ctx.tcg_env, addr, val, oi);
2965c482cb11SRichard Henderson             tcg_temp_free_i32(oi);
2966c482cb11SRichard Henderson         }
2967c482cb11SRichard Henderson #else
2968c482cb11SRichard Henderson         gen(ret, tcg_ctx.tcg_env, addr, val);
2969c482cb11SRichard Henderson #endif
2970df79b996SRichard Henderson #else
2971df79b996SRichard Henderson         gen_helper_exit_atomic(tcg_ctx.tcg_env);
2972*79b1af90SRichard Henderson         /* Produce a result, so that we have a well-formed opcode stream
2973*79b1af90SRichard Henderson            with respect to uses of the result in the (dead) code following.  */
2974*79b1af90SRichard Henderson         tcg_gen_movi_i64(ret, 0);
2975df79b996SRichard Henderson #endif /* CONFIG_ATOMIC64 */
2976c482cb11SRichard Henderson     } else {
2977c482cb11SRichard Henderson         TCGv_i32 v32 = tcg_temp_new_i32();
2978c482cb11SRichard Henderson         TCGv_i32 r32 = tcg_temp_new_i32();
2979c482cb11SRichard Henderson 
2980c482cb11SRichard Henderson         tcg_gen_extrl_i64_i32(v32, val);
2981c482cb11SRichard Henderson         do_atomic_op_i32(r32, addr, v32, idx, memop & ~MO_SIGN, table);
2982c482cb11SRichard Henderson         tcg_temp_free_i32(v32);
2983c482cb11SRichard Henderson 
2984c482cb11SRichard Henderson         tcg_gen_extu_i32_i64(ret, r32);
2985c482cb11SRichard Henderson         tcg_temp_free_i32(r32);
2986c482cb11SRichard Henderson 
2987c482cb11SRichard Henderson         if (memop & MO_SIGN) {
2988c482cb11SRichard Henderson             tcg_gen_ext_i64(ret, ret, memop);
2989c482cb11SRichard Henderson         }
2990c482cb11SRichard Henderson     }
2991c482cb11SRichard Henderson }
2992c482cb11SRichard Henderson 
2993c482cb11SRichard Henderson #define GEN_ATOMIC_HELPER(NAME, OP, NEW)                                \
2994c482cb11SRichard Henderson static void * const table_##NAME[16] = {                                \
2995c482cb11SRichard Henderson     [MO_8] = gen_helper_atomic_##NAME##b,                               \
2996c482cb11SRichard Henderson     [MO_16 | MO_LE] = gen_helper_atomic_##NAME##w_le,                   \
2997c482cb11SRichard Henderson     [MO_16 | MO_BE] = gen_helper_atomic_##NAME##w_be,                   \
2998c482cb11SRichard Henderson     [MO_32 | MO_LE] = gen_helper_atomic_##NAME##l_le,                   \
2999c482cb11SRichard Henderson     [MO_32 | MO_BE] = gen_helper_atomic_##NAME##l_be,                   \
3000df79b996SRichard Henderson     WITH_ATOMIC64([MO_64 | MO_LE] = gen_helper_atomic_##NAME##q_le)     \
3001df79b996SRichard Henderson     WITH_ATOMIC64([MO_64 | MO_BE] = gen_helper_atomic_##NAME##q_be)     \
3002c482cb11SRichard Henderson };                                                                      \
3003c482cb11SRichard Henderson void tcg_gen_atomic_##NAME##_i32                                        \
3004c482cb11SRichard Henderson     (TCGv_i32 ret, TCGv addr, TCGv_i32 val, TCGArg idx, TCGMemOp memop) \
3005c482cb11SRichard Henderson {                                                                       \
3006c482cb11SRichard Henderson     if (parallel_cpus) {                                                \
3007c482cb11SRichard Henderson         do_atomic_op_i32(ret, addr, val, idx, memop, table_##NAME);     \
3008c482cb11SRichard Henderson     } else {                                                            \
3009c482cb11SRichard Henderson         do_nonatomic_op_i32(ret, addr, val, idx, memop, NEW,            \
3010c482cb11SRichard Henderson                             tcg_gen_##OP##_i32);                        \
3011c482cb11SRichard Henderson     }                                                                   \
3012c482cb11SRichard Henderson }                                                                       \
3013c482cb11SRichard Henderson void tcg_gen_atomic_##NAME##_i64                                        \
3014c482cb11SRichard Henderson     (TCGv_i64 ret, TCGv addr, TCGv_i64 val, TCGArg idx, TCGMemOp memop) \
3015c482cb11SRichard Henderson {                                                                       \
3016c482cb11SRichard Henderson     if (parallel_cpus) {                                                \
3017c482cb11SRichard Henderson         do_atomic_op_i64(ret, addr, val, idx, memop, table_##NAME);     \
3018c482cb11SRichard Henderson     } else {                                                            \
3019c482cb11SRichard Henderson         do_nonatomic_op_i64(ret, addr, val, idx, memop, NEW,            \
3020c482cb11SRichard Henderson                             tcg_gen_##OP##_i64);                        \
3021c482cb11SRichard Henderson     }                                                                   \
3022c482cb11SRichard Henderson }
3023c482cb11SRichard Henderson 
3024c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_add, add, 0)
3025c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_and, and, 0)
3026c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_or, or, 0)
3027c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_xor, xor, 0)
3028c482cb11SRichard Henderson 
3029c482cb11SRichard Henderson GEN_ATOMIC_HELPER(add_fetch, add, 1)
3030c482cb11SRichard Henderson GEN_ATOMIC_HELPER(and_fetch, and, 1)
3031c482cb11SRichard Henderson GEN_ATOMIC_HELPER(or_fetch, or, 1)
3032c482cb11SRichard Henderson GEN_ATOMIC_HELPER(xor_fetch, xor, 1)
3033c482cb11SRichard Henderson 
3034c482cb11SRichard Henderson static void tcg_gen_mov2_i32(TCGv_i32 r, TCGv_i32 a, TCGv_i32 b)
3035c482cb11SRichard Henderson {
3036c482cb11SRichard Henderson     tcg_gen_mov_i32(r, b);
3037c482cb11SRichard Henderson }
3038c482cb11SRichard Henderson 
3039c482cb11SRichard Henderson static void tcg_gen_mov2_i64(TCGv_i64 r, TCGv_i64 a, TCGv_i64 b)
3040c482cb11SRichard Henderson {
3041c482cb11SRichard Henderson     tcg_gen_mov_i64(r, b);
3042c482cb11SRichard Henderson }
3043c482cb11SRichard Henderson 
3044c482cb11SRichard Henderson GEN_ATOMIC_HELPER(xchg, mov2, 0)
3045c482cb11SRichard Henderson 
3046c482cb11SRichard Henderson #undef GEN_ATOMIC_HELPER
3047