xref: /openbmc/qemu/tcg/tcg-op.c (revision 07cc68d5)
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 
460951c6300SRichard Henderson void tcg_gen_rotl_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
461951c6300SRichard Henderson {
462951c6300SRichard Henderson     if (TCG_TARGET_HAS_rot_i32) {
463951c6300SRichard Henderson         tcg_gen_op3_i32(INDEX_op_rotl_i32, ret, arg1, arg2);
464951c6300SRichard Henderson     } else {
465951c6300SRichard Henderson         TCGv_i32 t0, t1;
466951c6300SRichard Henderson 
467951c6300SRichard Henderson         t0 = tcg_temp_new_i32();
468951c6300SRichard Henderson         t1 = tcg_temp_new_i32();
469951c6300SRichard Henderson         tcg_gen_shl_i32(t0, arg1, arg2);
470951c6300SRichard Henderson         tcg_gen_subfi_i32(t1, 32, arg2);
471951c6300SRichard Henderson         tcg_gen_shr_i32(t1, arg1, t1);
472951c6300SRichard Henderson         tcg_gen_or_i32(ret, t0, t1);
473951c6300SRichard Henderson         tcg_temp_free_i32(t0);
474951c6300SRichard Henderson         tcg_temp_free_i32(t1);
475951c6300SRichard Henderson     }
476951c6300SRichard Henderson }
477951c6300SRichard Henderson 
478951c6300SRichard Henderson void tcg_gen_rotli_i32(TCGv_i32 ret, TCGv_i32 arg1, unsigned arg2)
479951c6300SRichard Henderson {
480951c6300SRichard Henderson     tcg_debug_assert(arg2 < 32);
481951c6300SRichard Henderson     /* some cases can be optimized here */
482951c6300SRichard Henderson     if (arg2 == 0) {
483951c6300SRichard Henderson         tcg_gen_mov_i32(ret, arg1);
484951c6300SRichard Henderson     } else if (TCG_TARGET_HAS_rot_i32) {
485951c6300SRichard Henderson         TCGv_i32 t0 = tcg_const_i32(arg2);
486951c6300SRichard Henderson         tcg_gen_rotl_i32(ret, arg1, t0);
487951c6300SRichard Henderson         tcg_temp_free_i32(t0);
488951c6300SRichard Henderson     } else {
489951c6300SRichard Henderson         TCGv_i32 t0, t1;
490951c6300SRichard Henderson         t0 = tcg_temp_new_i32();
491951c6300SRichard Henderson         t1 = tcg_temp_new_i32();
492951c6300SRichard Henderson         tcg_gen_shli_i32(t0, arg1, arg2);
493951c6300SRichard Henderson         tcg_gen_shri_i32(t1, arg1, 32 - arg2);
494951c6300SRichard Henderson         tcg_gen_or_i32(ret, t0, t1);
495951c6300SRichard Henderson         tcg_temp_free_i32(t0);
496951c6300SRichard Henderson         tcg_temp_free_i32(t1);
497951c6300SRichard Henderson     }
498951c6300SRichard Henderson }
499951c6300SRichard Henderson 
500951c6300SRichard Henderson void tcg_gen_rotr_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
501951c6300SRichard Henderson {
502951c6300SRichard Henderson     if (TCG_TARGET_HAS_rot_i32) {
503951c6300SRichard Henderson         tcg_gen_op3_i32(INDEX_op_rotr_i32, ret, arg1, arg2);
504951c6300SRichard Henderson     } else {
505951c6300SRichard Henderson         TCGv_i32 t0, t1;
506951c6300SRichard Henderson 
507951c6300SRichard Henderson         t0 = tcg_temp_new_i32();
508951c6300SRichard Henderson         t1 = tcg_temp_new_i32();
509951c6300SRichard Henderson         tcg_gen_shr_i32(t0, arg1, arg2);
510951c6300SRichard Henderson         tcg_gen_subfi_i32(t1, 32, arg2);
511951c6300SRichard Henderson         tcg_gen_shl_i32(t1, arg1, t1);
512951c6300SRichard Henderson         tcg_gen_or_i32(ret, t0, t1);
513951c6300SRichard Henderson         tcg_temp_free_i32(t0);
514951c6300SRichard Henderson         tcg_temp_free_i32(t1);
515951c6300SRichard Henderson     }
516951c6300SRichard Henderson }
517951c6300SRichard Henderson 
518951c6300SRichard Henderson void tcg_gen_rotri_i32(TCGv_i32 ret, TCGv_i32 arg1, unsigned arg2)
519951c6300SRichard Henderson {
520951c6300SRichard Henderson     tcg_debug_assert(arg2 < 32);
521951c6300SRichard Henderson     /* some cases can be optimized here */
522951c6300SRichard Henderson     if (arg2 == 0) {
523951c6300SRichard Henderson         tcg_gen_mov_i32(ret, arg1);
524951c6300SRichard Henderson     } else {
525951c6300SRichard Henderson         tcg_gen_rotli_i32(ret, arg1, 32 - arg2);
526951c6300SRichard Henderson     }
527951c6300SRichard Henderson }
528951c6300SRichard Henderson 
529951c6300SRichard Henderson void tcg_gen_deposit_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2,
530951c6300SRichard Henderson                          unsigned int ofs, unsigned int len)
531951c6300SRichard Henderson {
532951c6300SRichard Henderson     uint32_t mask;
533951c6300SRichard Henderson     TCGv_i32 t1;
534951c6300SRichard Henderson 
535951c6300SRichard Henderson     tcg_debug_assert(ofs < 32);
5360d0d309dSRichard Henderson     tcg_debug_assert(len > 0);
537951c6300SRichard Henderson     tcg_debug_assert(len <= 32);
538951c6300SRichard Henderson     tcg_debug_assert(ofs + len <= 32);
539951c6300SRichard Henderson 
5400d0d309dSRichard Henderson     if (len == 32) {
541951c6300SRichard Henderson         tcg_gen_mov_i32(ret, arg2);
542951c6300SRichard Henderson         return;
543951c6300SRichard Henderson     }
544951c6300SRichard Henderson     if (TCG_TARGET_HAS_deposit_i32 && TCG_TARGET_deposit_i32_valid(ofs, len)) {
545951c6300SRichard Henderson         tcg_gen_op5ii_i32(INDEX_op_deposit_i32, ret, arg1, arg2, ofs, len);
546951c6300SRichard Henderson         return;
547951c6300SRichard Henderson     }
548951c6300SRichard Henderson 
549951c6300SRichard Henderson     mask = (1u << len) - 1;
550951c6300SRichard Henderson     t1 = tcg_temp_new_i32();
551951c6300SRichard Henderson 
552951c6300SRichard Henderson     if (ofs + len < 32) {
553951c6300SRichard Henderson         tcg_gen_andi_i32(t1, arg2, mask);
554951c6300SRichard Henderson         tcg_gen_shli_i32(t1, t1, ofs);
555951c6300SRichard Henderson     } else {
556951c6300SRichard Henderson         tcg_gen_shli_i32(t1, arg2, ofs);
557951c6300SRichard Henderson     }
558951c6300SRichard Henderson     tcg_gen_andi_i32(ret, arg1, ~(mask << ofs));
559951c6300SRichard Henderson     tcg_gen_or_i32(ret, ret, t1);
560951c6300SRichard Henderson 
561951c6300SRichard Henderson     tcg_temp_free_i32(t1);
562951c6300SRichard Henderson }
563951c6300SRichard Henderson 
564*07cc68d5SRichard Henderson void tcg_gen_deposit_z_i32(TCGv_i32 ret, TCGv_i32 arg,
565*07cc68d5SRichard Henderson                            unsigned int ofs, unsigned int len)
566*07cc68d5SRichard Henderson {
567*07cc68d5SRichard Henderson     tcg_debug_assert(ofs < 32);
568*07cc68d5SRichard Henderson     tcg_debug_assert(len > 0);
569*07cc68d5SRichard Henderson     tcg_debug_assert(len <= 32);
570*07cc68d5SRichard Henderson     tcg_debug_assert(ofs + len <= 32);
571*07cc68d5SRichard Henderson 
572*07cc68d5SRichard Henderson     if (ofs + len == 32) {
573*07cc68d5SRichard Henderson         tcg_gen_shli_i32(ret, arg, ofs);
574*07cc68d5SRichard Henderson     } else if (ofs == 0) {
575*07cc68d5SRichard Henderson         tcg_gen_andi_i32(ret, arg, (1u << len) - 1);
576*07cc68d5SRichard Henderson     } else if (TCG_TARGET_HAS_deposit_i32
577*07cc68d5SRichard Henderson                && TCG_TARGET_deposit_i32_valid(ofs, len)) {
578*07cc68d5SRichard Henderson         TCGv_i32 zero = tcg_const_i32(0);
579*07cc68d5SRichard Henderson         tcg_gen_op5ii_i32(INDEX_op_deposit_i32, ret, zero, arg, ofs, len);
580*07cc68d5SRichard Henderson         tcg_temp_free_i32(zero);
581*07cc68d5SRichard Henderson     } else {
582*07cc68d5SRichard Henderson         /* To help two-operand hosts we prefer to zero-extend first,
583*07cc68d5SRichard Henderson            which allows ARG to stay live.  */
584*07cc68d5SRichard Henderson         switch (len) {
585*07cc68d5SRichard Henderson         case 16:
586*07cc68d5SRichard Henderson             if (TCG_TARGET_HAS_ext16u_i32) {
587*07cc68d5SRichard Henderson                 tcg_gen_ext16u_i32(ret, arg);
588*07cc68d5SRichard Henderson                 tcg_gen_shli_i32(ret, ret, ofs);
589*07cc68d5SRichard Henderson                 return;
590*07cc68d5SRichard Henderson             }
591*07cc68d5SRichard Henderson             break;
592*07cc68d5SRichard Henderson         case 8:
593*07cc68d5SRichard Henderson             if (TCG_TARGET_HAS_ext8u_i32) {
594*07cc68d5SRichard Henderson                 tcg_gen_ext8u_i32(ret, arg);
595*07cc68d5SRichard Henderson                 tcg_gen_shli_i32(ret, ret, ofs);
596*07cc68d5SRichard Henderson                 return;
597*07cc68d5SRichard Henderson             }
598*07cc68d5SRichard Henderson             break;
599*07cc68d5SRichard Henderson         }
600*07cc68d5SRichard Henderson         /* Otherwise prefer zero-extension over AND for code size.  */
601*07cc68d5SRichard Henderson         switch (ofs + len) {
602*07cc68d5SRichard Henderson         case 16:
603*07cc68d5SRichard Henderson             if (TCG_TARGET_HAS_ext16u_i32) {
604*07cc68d5SRichard Henderson                 tcg_gen_shli_i32(ret, arg, ofs);
605*07cc68d5SRichard Henderson                 tcg_gen_ext16u_i32(ret, ret);
606*07cc68d5SRichard Henderson                 return;
607*07cc68d5SRichard Henderson             }
608*07cc68d5SRichard Henderson             break;
609*07cc68d5SRichard Henderson         case 8:
610*07cc68d5SRichard Henderson             if (TCG_TARGET_HAS_ext8u_i32) {
611*07cc68d5SRichard Henderson                 tcg_gen_shli_i32(ret, arg, ofs);
612*07cc68d5SRichard Henderson                 tcg_gen_ext8u_i32(ret, ret);
613*07cc68d5SRichard Henderson                 return;
614*07cc68d5SRichard Henderson             }
615*07cc68d5SRichard Henderson             break;
616*07cc68d5SRichard Henderson         }
617*07cc68d5SRichard Henderson         tcg_gen_andi_i32(ret, arg, (1u << len) - 1);
618*07cc68d5SRichard Henderson         tcg_gen_shli_i32(ret, ret, ofs);
619*07cc68d5SRichard Henderson     }
620*07cc68d5SRichard Henderson }
621*07cc68d5SRichard Henderson 
6227ec8bab3SRichard Henderson void tcg_gen_extract_i32(TCGv_i32 ret, TCGv_i32 arg,
6237ec8bab3SRichard Henderson                          unsigned int ofs, unsigned int len)
6247ec8bab3SRichard Henderson {
6257ec8bab3SRichard Henderson     tcg_debug_assert(ofs < 32);
6267ec8bab3SRichard Henderson     tcg_debug_assert(len > 0);
6277ec8bab3SRichard Henderson     tcg_debug_assert(len <= 32);
6287ec8bab3SRichard Henderson     tcg_debug_assert(ofs + len <= 32);
6297ec8bab3SRichard Henderson 
6307ec8bab3SRichard Henderson     /* Canonicalize certain special cases, even if extract is supported.  */
6317ec8bab3SRichard Henderson     if (ofs + len == 32) {
6327ec8bab3SRichard Henderson         tcg_gen_shri_i32(ret, arg, 32 - len);
6337ec8bab3SRichard Henderson         return;
6347ec8bab3SRichard Henderson     }
6357ec8bab3SRichard Henderson     if (ofs == 0) {
6367ec8bab3SRichard Henderson         tcg_gen_andi_i32(ret, arg, (1u << len) - 1);
6377ec8bab3SRichard Henderson         return;
6387ec8bab3SRichard Henderson     }
6397ec8bab3SRichard Henderson 
6407ec8bab3SRichard Henderson     if (TCG_TARGET_HAS_extract_i32
6417ec8bab3SRichard Henderson         && TCG_TARGET_extract_i32_valid(ofs, len)) {
6427ec8bab3SRichard Henderson         tcg_gen_op4ii_i32(INDEX_op_extract_i32, ret, arg, ofs, len);
6437ec8bab3SRichard Henderson         return;
6447ec8bab3SRichard Henderson     }
6457ec8bab3SRichard Henderson 
6467ec8bab3SRichard Henderson     /* Assume that zero-extension, if available, is cheaper than a shift.  */
6477ec8bab3SRichard Henderson     switch (ofs + len) {
6487ec8bab3SRichard Henderson     case 16:
6497ec8bab3SRichard Henderson         if (TCG_TARGET_HAS_ext16u_i32) {
6507ec8bab3SRichard Henderson             tcg_gen_ext16u_i32(ret, arg);
6517ec8bab3SRichard Henderson             tcg_gen_shri_i32(ret, ret, ofs);
6527ec8bab3SRichard Henderson             return;
6537ec8bab3SRichard Henderson         }
6547ec8bab3SRichard Henderson         break;
6557ec8bab3SRichard Henderson     case 8:
6567ec8bab3SRichard Henderson         if (TCG_TARGET_HAS_ext8u_i32) {
6577ec8bab3SRichard Henderson             tcg_gen_ext8u_i32(ret, arg);
6587ec8bab3SRichard Henderson             tcg_gen_shri_i32(ret, ret, ofs);
6597ec8bab3SRichard Henderson             return;
6607ec8bab3SRichard Henderson         }
6617ec8bab3SRichard Henderson         break;
6627ec8bab3SRichard Henderson     }
6637ec8bab3SRichard Henderson 
6647ec8bab3SRichard Henderson     /* ??? Ideally we'd know what values are available for immediate AND.
6657ec8bab3SRichard Henderson        Assume that 8 bits are available, plus the special case of 16,
6667ec8bab3SRichard Henderson        so that we get ext8u, ext16u.  */
6677ec8bab3SRichard Henderson     switch (len) {
6687ec8bab3SRichard Henderson     case 1 ... 8: case 16:
6697ec8bab3SRichard Henderson         tcg_gen_shri_i32(ret, arg, ofs);
6707ec8bab3SRichard Henderson         tcg_gen_andi_i32(ret, ret, (1u << len) - 1);
6717ec8bab3SRichard Henderson         break;
6727ec8bab3SRichard Henderson     default:
6737ec8bab3SRichard Henderson         tcg_gen_shli_i32(ret, arg, 32 - len - ofs);
6747ec8bab3SRichard Henderson         tcg_gen_shri_i32(ret, ret, 32 - len);
6757ec8bab3SRichard Henderson         break;
6767ec8bab3SRichard Henderson     }
6777ec8bab3SRichard Henderson }
6787ec8bab3SRichard Henderson 
6797ec8bab3SRichard Henderson void tcg_gen_sextract_i32(TCGv_i32 ret, TCGv_i32 arg,
6807ec8bab3SRichard Henderson                           unsigned int ofs, unsigned int len)
6817ec8bab3SRichard Henderson {
6827ec8bab3SRichard Henderson     tcg_debug_assert(ofs < 32);
6837ec8bab3SRichard Henderson     tcg_debug_assert(len > 0);
6847ec8bab3SRichard Henderson     tcg_debug_assert(len <= 32);
6857ec8bab3SRichard Henderson     tcg_debug_assert(ofs + len <= 32);
6867ec8bab3SRichard Henderson 
6877ec8bab3SRichard Henderson     /* Canonicalize certain special cases, even if extract is supported.  */
6887ec8bab3SRichard Henderson     if (ofs + len == 32) {
6897ec8bab3SRichard Henderson         tcg_gen_sari_i32(ret, arg, 32 - len);
6907ec8bab3SRichard Henderson         return;
6917ec8bab3SRichard Henderson     }
6927ec8bab3SRichard Henderson     if (ofs == 0) {
6937ec8bab3SRichard Henderson         switch (len) {
6947ec8bab3SRichard Henderson         case 16:
6957ec8bab3SRichard Henderson             tcg_gen_ext16s_i32(ret, arg);
6967ec8bab3SRichard Henderson             return;
6977ec8bab3SRichard Henderson         case 8:
6987ec8bab3SRichard Henderson             tcg_gen_ext8s_i32(ret, arg);
6997ec8bab3SRichard Henderson             return;
7007ec8bab3SRichard Henderson         }
7017ec8bab3SRichard Henderson     }
7027ec8bab3SRichard Henderson 
7037ec8bab3SRichard Henderson     if (TCG_TARGET_HAS_sextract_i32
7047ec8bab3SRichard Henderson         && TCG_TARGET_extract_i32_valid(ofs, len)) {
7057ec8bab3SRichard Henderson         tcg_gen_op4ii_i32(INDEX_op_sextract_i32, ret, arg, ofs, len);
7067ec8bab3SRichard Henderson         return;
7077ec8bab3SRichard Henderson     }
7087ec8bab3SRichard Henderson 
7097ec8bab3SRichard Henderson     /* Assume that sign-extension, if available, is cheaper than a shift.  */
7107ec8bab3SRichard Henderson     switch (ofs + len) {
7117ec8bab3SRichard Henderson     case 16:
7127ec8bab3SRichard Henderson         if (TCG_TARGET_HAS_ext16s_i32) {
7137ec8bab3SRichard Henderson             tcg_gen_ext16s_i32(ret, arg);
7147ec8bab3SRichard Henderson             tcg_gen_sari_i32(ret, ret, ofs);
7157ec8bab3SRichard Henderson             return;
7167ec8bab3SRichard Henderson         }
7177ec8bab3SRichard Henderson         break;
7187ec8bab3SRichard Henderson     case 8:
7197ec8bab3SRichard Henderson         if (TCG_TARGET_HAS_ext8s_i32) {
7207ec8bab3SRichard Henderson             tcg_gen_ext8s_i32(ret, arg);
7217ec8bab3SRichard Henderson             tcg_gen_sari_i32(ret, ret, ofs);
7227ec8bab3SRichard Henderson             return;
7237ec8bab3SRichard Henderson         }
7247ec8bab3SRichard Henderson         break;
7257ec8bab3SRichard Henderson     }
7267ec8bab3SRichard Henderson     switch (len) {
7277ec8bab3SRichard Henderson     case 16:
7287ec8bab3SRichard Henderson         if (TCG_TARGET_HAS_ext16s_i32) {
7297ec8bab3SRichard Henderson             tcg_gen_shri_i32(ret, arg, ofs);
7307ec8bab3SRichard Henderson             tcg_gen_ext16s_i32(ret, ret);
7317ec8bab3SRichard Henderson             return;
7327ec8bab3SRichard Henderson         }
7337ec8bab3SRichard Henderson         break;
7347ec8bab3SRichard Henderson     case 8:
7357ec8bab3SRichard Henderson         if (TCG_TARGET_HAS_ext8s_i32) {
7367ec8bab3SRichard Henderson             tcg_gen_shri_i32(ret, arg, ofs);
7377ec8bab3SRichard Henderson             tcg_gen_ext8s_i32(ret, ret);
7387ec8bab3SRichard Henderson             return;
7397ec8bab3SRichard Henderson         }
7407ec8bab3SRichard Henderson         break;
7417ec8bab3SRichard Henderson     }
7427ec8bab3SRichard Henderson 
7437ec8bab3SRichard Henderson     tcg_gen_shli_i32(ret, arg, 32 - len - ofs);
7447ec8bab3SRichard Henderson     tcg_gen_sari_i32(ret, ret, 32 - len);
7457ec8bab3SRichard Henderson }
7467ec8bab3SRichard Henderson 
747951c6300SRichard Henderson void tcg_gen_movcond_i32(TCGCond cond, TCGv_i32 ret, TCGv_i32 c1,
748951c6300SRichard Henderson                          TCGv_i32 c2, TCGv_i32 v1, TCGv_i32 v2)
749951c6300SRichard Henderson {
75037ed3bf1SRichard Henderson     if (cond == TCG_COND_ALWAYS) {
75137ed3bf1SRichard Henderson         tcg_gen_mov_i32(ret, v1);
75237ed3bf1SRichard Henderson     } else if (cond == TCG_COND_NEVER) {
75337ed3bf1SRichard Henderson         tcg_gen_mov_i32(ret, v2);
75437ed3bf1SRichard Henderson     } else if (TCG_TARGET_HAS_movcond_i32) {
755951c6300SRichard Henderson         tcg_gen_op6i_i32(INDEX_op_movcond_i32, ret, c1, c2, v1, v2, cond);
756951c6300SRichard Henderson     } else {
757951c6300SRichard Henderson         TCGv_i32 t0 = tcg_temp_new_i32();
758951c6300SRichard Henderson         TCGv_i32 t1 = tcg_temp_new_i32();
759951c6300SRichard Henderson         tcg_gen_setcond_i32(cond, t0, c1, c2);
760951c6300SRichard Henderson         tcg_gen_neg_i32(t0, t0);
761951c6300SRichard Henderson         tcg_gen_and_i32(t1, v1, t0);
762951c6300SRichard Henderson         tcg_gen_andc_i32(ret, v2, t0);
763951c6300SRichard Henderson         tcg_gen_or_i32(ret, ret, t1);
764951c6300SRichard Henderson         tcg_temp_free_i32(t0);
765951c6300SRichard Henderson         tcg_temp_free_i32(t1);
766951c6300SRichard Henderson     }
767951c6300SRichard Henderson }
768951c6300SRichard Henderson 
769951c6300SRichard Henderson void tcg_gen_add2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 al,
770951c6300SRichard Henderson                       TCGv_i32 ah, TCGv_i32 bl, TCGv_i32 bh)
771951c6300SRichard Henderson {
772951c6300SRichard Henderson     if (TCG_TARGET_HAS_add2_i32) {
773951c6300SRichard Henderson         tcg_gen_op6_i32(INDEX_op_add2_i32, rl, rh, al, ah, bl, bh);
774951c6300SRichard Henderson     } else {
775951c6300SRichard Henderson         TCGv_i64 t0 = tcg_temp_new_i64();
776951c6300SRichard Henderson         TCGv_i64 t1 = tcg_temp_new_i64();
777951c6300SRichard Henderson         tcg_gen_concat_i32_i64(t0, al, ah);
778951c6300SRichard Henderson         tcg_gen_concat_i32_i64(t1, bl, bh);
779951c6300SRichard Henderson         tcg_gen_add_i64(t0, t0, t1);
780951c6300SRichard Henderson         tcg_gen_extr_i64_i32(rl, rh, t0);
781951c6300SRichard Henderson         tcg_temp_free_i64(t0);
782951c6300SRichard Henderson         tcg_temp_free_i64(t1);
783951c6300SRichard Henderson     }
784951c6300SRichard Henderson }
785951c6300SRichard Henderson 
786951c6300SRichard Henderson void tcg_gen_sub2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 al,
787951c6300SRichard Henderson                       TCGv_i32 ah, TCGv_i32 bl, TCGv_i32 bh)
788951c6300SRichard Henderson {
789951c6300SRichard Henderson     if (TCG_TARGET_HAS_sub2_i32) {
790951c6300SRichard Henderson         tcg_gen_op6_i32(INDEX_op_sub2_i32, rl, rh, al, ah, bl, bh);
791951c6300SRichard Henderson     } else {
792951c6300SRichard Henderson         TCGv_i64 t0 = tcg_temp_new_i64();
793951c6300SRichard Henderson         TCGv_i64 t1 = tcg_temp_new_i64();
794951c6300SRichard Henderson         tcg_gen_concat_i32_i64(t0, al, ah);
795951c6300SRichard Henderson         tcg_gen_concat_i32_i64(t1, bl, bh);
796951c6300SRichard Henderson         tcg_gen_sub_i64(t0, t0, t1);
797951c6300SRichard Henderson         tcg_gen_extr_i64_i32(rl, rh, t0);
798951c6300SRichard Henderson         tcg_temp_free_i64(t0);
799951c6300SRichard Henderson         tcg_temp_free_i64(t1);
800951c6300SRichard Henderson     }
801951c6300SRichard Henderson }
802951c6300SRichard Henderson 
803951c6300SRichard Henderson void tcg_gen_mulu2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 arg1, TCGv_i32 arg2)
804951c6300SRichard Henderson {
805951c6300SRichard Henderson     if (TCG_TARGET_HAS_mulu2_i32) {
806951c6300SRichard Henderson         tcg_gen_op4_i32(INDEX_op_mulu2_i32, rl, rh, arg1, arg2);
807951c6300SRichard Henderson     } else if (TCG_TARGET_HAS_muluh_i32) {
808951c6300SRichard Henderson         TCGv_i32 t = tcg_temp_new_i32();
809951c6300SRichard Henderson         tcg_gen_op3_i32(INDEX_op_mul_i32, t, arg1, arg2);
810951c6300SRichard Henderson         tcg_gen_op3_i32(INDEX_op_muluh_i32, rh, arg1, arg2);
811951c6300SRichard Henderson         tcg_gen_mov_i32(rl, t);
812951c6300SRichard Henderson         tcg_temp_free_i32(t);
813951c6300SRichard Henderson     } else {
814951c6300SRichard Henderson         TCGv_i64 t0 = tcg_temp_new_i64();
815951c6300SRichard Henderson         TCGv_i64 t1 = tcg_temp_new_i64();
816951c6300SRichard Henderson         tcg_gen_extu_i32_i64(t0, arg1);
817951c6300SRichard Henderson         tcg_gen_extu_i32_i64(t1, arg2);
818951c6300SRichard Henderson         tcg_gen_mul_i64(t0, t0, t1);
819951c6300SRichard Henderson         tcg_gen_extr_i64_i32(rl, rh, t0);
820951c6300SRichard Henderson         tcg_temp_free_i64(t0);
821951c6300SRichard Henderson         tcg_temp_free_i64(t1);
822951c6300SRichard Henderson     }
823951c6300SRichard Henderson }
824951c6300SRichard Henderson 
825951c6300SRichard Henderson void tcg_gen_muls2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 arg1, TCGv_i32 arg2)
826951c6300SRichard Henderson {
827951c6300SRichard Henderson     if (TCG_TARGET_HAS_muls2_i32) {
828951c6300SRichard Henderson         tcg_gen_op4_i32(INDEX_op_muls2_i32, rl, rh, arg1, arg2);
829951c6300SRichard Henderson     } else if (TCG_TARGET_HAS_mulsh_i32) {
830951c6300SRichard Henderson         TCGv_i32 t = tcg_temp_new_i32();
831951c6300SRichard Henderson         tcg_gen_op3_i32(INDEX_op_mul_i32, t, arg1, arg2);
832951c6300SRichard Henderson         tcg_gen_op3_i32(INDEX_op_mulsh_i32, rh, arg1, arg2);
833951c6300SRichard Henderson         tcg_gen_mov_i32(rl, t);
834951c6300SRichard Henderson         tcg_temp_free_i32(t);
835951c6300SRichard Henderson     } else if (TCG_TARGET_REG_BITS == 32) {
836951c6300SRichard Henderson         TCGv_i32 t0 = tcg_temp_new_i32();
837951c6300SRichard Henderson         TCGv_i32 t1 = tcg_temp_new_i32();
838951c6300SRichard Henderson         TCGv_i32 t2 = tcg_temp_new_i32();
839951c6300SRichard Henderson         TCGv_i32 t3 = tcg_temp_new_i32();
840951c6300SRichard Henderson         tcg_gen_mulu2_i32(t0, t1, arg1, arg2);
841951c6300SRichard Henderson         /* Adjust for negative inputs.  */
842951c6300SRichard Henderson         tcg_gen_sari_i32(t2, arg1, 31);
843951c6300SRichard Henderson         tcg_gen_sari_i32(t3, arg2, 31);
844951c6300SRichard Henderson         tcg_gen_and_i32(t2, t2, arg2);
845951c6300SRichard Henderson         tcg_gen_and_i32(t3, t3, arg1);
846951c6300SRichard Henderson         tcg_gen_sub_i32(rh, t1, t2);
847951c6300SRichard Henderson         tcg_gen_sub_i32(rh, rh, t3);
848951c6300SRichard Henderson         tcg_gen_mov_i32(rl, t0);
849951c6300SRichard Henderson         tcg_temp_free_i32(t0);
850951c6300SRichard Henderson         tcg_temp_free_i32(t1);
851951c6300SRichard Henderson         tcg_temp_free_i32(t2);
852951c6300SRichard Henderson         tcg_temp_free_i32(t3);
853951c6300SRichard Henderson     } else {
854951c6300SRichard Henderson         TCGv_i64 t0 = tcg_temp_new_i64();
855951c6300SRichard Henderson         TCGv_i64 t1 = tcg_temp_new_i64();
856951c6300SRichard Henderson         tcg_gen_ext_i32_i64(t0, arg1);
857951c6300SRichard Henderson         tcg_gen_ext_i32_i64(t1, arg2);
858951c6300SRichard Henderson         tcg_gen_mul_i64(t0, t0, t1);
859951c6300SRichard Henderson         tcg_gen_extr_i64_i32(rl, rh, t0);
860951c6300SRichard Henderson         tcg_temp_free_i64(t0);
861951c6300SRichard Henderson         tcg_temp_free_i64(t1);
862951c6300SRichard Henderson     }
863951c6300SRichard Henderson }
864951c6300SRichard Henderson 
8655087abfbSRichard Henderson void tcg_gen_mulsu2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 arg1, TCGv_i32 arg2)
8665087abfbSRichard Henderson {
8675087abfbSRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
8685087abfbSRichard Henderson         TCGv_i32 t0 = tcg_temp_new_i32();
8695087abfbSRichard Henderson         TCGv_i32 t1 = tcg_temp_new_i32();
8705087abfbSRichard Henderson         TCGv_i32 t2 = tcg_temp_new_i32();
8715087abfbSRichard Henderson         tcg_gen_mulu2_i32(t0, t1, arg1, arg2);
8725087abfbSRichard Henderson         /* Adjust for negative input for the signed arg1.  */
8735087abfbSRichard Henderson         tcg_gen_sari_i32(t2, arg1, 31);
8745087abfbSRichard Henderson         tcg_gen_and_i32(t2, t2, arg2);
8755087abfbSRichard Henderson         tcg_gen_sub_i32(rh, t1, t2);
8765087abfbSRichard Henderson         tcg_gen_mov_i32(rl, t0);
8775087abfbSRichard Henderson         tcg_temp_free_i32(t0);
8785087abfbSRichard Henderson         tcg_temp_free_i32(t1);
8795087abfbSRichard Henderson         tcg_temp_free_i32(t2);
8805087abfbSRichard Henderson     } else {
8815087abfbSRichard Henderson         TCGv_i64 t0 = tcg_temp_new_i64();
8825087abfbSRichard Henderson         TCGv_i64 t1 = tcg_temp_new_i64();
8835087abfbSRichard Henderson         tcg_gen_ext_i32_i64(t0, arg1);
8845087abfbSRichard Henderson         tcg_gen_extu_i32_i64(t1, arg2);
8855087abfbSRichard Henderson         tcg_gen_mul_i64(t0, t0, t1);
8865087abfbSRichard Henderson         tcg_gen_extr_i64_i32(rl, rh, t0);
8875087abfbSRichard Henderson         tcg_temp_free_i64(t0);
8885087abfbSRichard Henderson         tcg_temp_free_i64(t1);
8895087abfbSRichard Henderson     }
8905087abfbSRichard Henderson }
8915087abfbSRichard Henderson 
892951c6300SRichard Henderson void tcg_gen_ext8s_i32(TCGv_i32 ret, TCGv_i32 arg)
893951c6300SRichard Henderson {
894951c6300SRichard Henderson     if (TCG_TARGET_HAS_ext8s_i32) {
895951c6300SRichard Henderson         tcg_gen_op2_i32(INDEX_op_ext8s_i32, ret, arg);
896951c6300SRichard Henderson     } else {
897951c6300SRichard Henderson         tcg_gen_shli_i32(ret, arg, 24);
898951c6300SRichard Henderson         tcg_gen_sari_i32(ret, ret, 24);
899951c6300SRichard Henderson     }
900951c6300SRichard Henderson }
901951c6300SRichard Henderson 
902951c6300SRichard Henderson void tcg_gen_ext16s_i32(TCGv_i32 ret, TCGv_i32 arg)
903951c6300SRichard Henderson {
904951c6300SRichard Henderson     if (TCG_TARGET_HAS_ext16s_i32) {
905951c6300SRichard Henderson         tcg_gen_op2_i32(INDEX_op_ext16s_i32, ret, arg);
906951c6300SRichard Henderson     } else {
907951c6300SRichard Henderson         tcg_gen_shli_i32(ret, arg, 16);
908951c6300SRichard Henderson         tcg_gen_sari_i32(ret, ret, 16);
909951c6300SRichard Henderson     }
910951c6300SRichard Henderson }
911951c6300SRichard Henderson 
912951c6300SRichard Henderson void tcg_gen_ext8u_i32(TCGv_i32 ret, TCGv_i32 arg)
913951c6300SRichard Henderson {
914951c6300SRichard Henderson     if (TCG_TARGET_HAS_ext8u_i32) {
915951c6300SRichard Henderson         tcg_gen_op2_i32(INDEX_op_ext8u_i32, ret, arg);
916951c6300SRichard Henderson     } else {
917951c6300SRichard Henderson         tcg_gen_andi_i32(ret, arg, 0xffu);
918951c6300SRichard Henderson     }
919951c6300SRichard Henderson }
920951c6300SRichard Henderson 
921951c6300SRichard Henderson void tcg_gen_ext16u_i32(TCGv_i32 ret, TCGv_i32 arg)
922951c6300SRichard Henderson {
923951c6300SRichard Henderson     if (TCG_TARGET_HAS_ext16u_i32) {
924951c6300SRichard Henderson         tcg_gen_op2_i32(INDEX_op_ext16u_i32, ret, arg);
925951c6300SRichard Henderson     } else {
926951c6300SRichard Henderson         tcg_gen_andi_i32(ret, arg, 0xffffu);
927951c6300SRichard Henderson     }
928951c6300SRichard Henderson }
929951c6300SRichard Henderson 
930951c6300SRichard Henderson /* Note: we assume the two high bytes are set to zero */
931951c6300SRichard Henderson void tcg_gen_bswap16_i32(TCGv_i32 ret, TCGv_i32 arg)
932951c6300SRichard Henderson {
933951c6300SRichard Henderson     if (TCG_TARGET_HAS_bswap16_i32) {
934951c6300SRichard Henderson         tcg_gen_op2_i32(INDEX_op_bswap16_i32, ret, arg);
935951c6300SRichard Henderson     } else {
936951c6300SRichard Henderson         TCGv_i32 t0 = tcg_temp_new_i32();
937951c6300SRichard Henderson 
938951c6300SRichard Henderson         tcg_gen_ext8u_i32(t0, arg);
939951c6300SRichard Henderson         tcg_gen_shli_i32(t0, t0, 8);
940951c6300SRichard Henderson         tcg_gen_shri_i32(ret, arg, 8);
941951c6300SRichard Henderson         tcg_gen_or_i32(ret, ret, t0);
942951c6300SRichard Henderson         tcg_temp_free_i32(t0);
943951c6300SRichard Henderson     }
944951c6300SRichard Henderson }
945951c6300SRichard Henderson 
946951c6300SRichard Henderson void tcg_gen_bswap32_i32(TCGv_i32 ret, TCGv_i32 arg)
947951c6300SRichard Henderson {
948951c6300SRichard Henderson     if (TCG_TARGET_HAS_bswap32_i32) {
949951c6300SRichard Henderson         tcg_gen_op2_i32(INDEX_op_bswap32_i32, ret, arg);
950951c6300SRichard Henderson     } else {
951951c6300SRichard Henderson         TCGv_i32 t0, t1;
952951c6300SRichard Henderson         t0 = tcg_temp_new_i32();
953951c6300SRichard Henderson         t1 = tcg_temp_new_i32();
954951c6300SRichard Henderson 
955951c6300SRichard Henderson         tcg_gen_shli_i32(t0, arg, 24);
956951c6300SRichard Henderson 
957951c6300SRichard Henderson         tcg_gen_andi_i32(t1, arg, 0x0000ff00);
958951c6300SRichard Henderson         tcg_gen_shli_i32(t1, t1, 8);
959951c6300SRichard Henderson         tcg_gen_or_i32(t0, t0, t1);
960951c6300SRichard Henderson 
961951c6300SRichard Henderson         tcg_gen_shri_i32(t1, arg, 8);
962951c6300SRichard Henderson         tcg_gen_andi_i32(t1, t1, 0x0000ff00);
963951c6300SRichard Henderson         tcg_gen_or_i32(t0, t0, t1);
964951c6300SRichard Henderson 
965951c6300SRichard Henderson         tcg_gen_shri_i32(t1, arg, 24);
966951c6300SRichard Henderson         tcg_gen_or_i32(ret, t0, t1);
967951c6300SRichard Henderson         tcg_temp_free_i32(t0);
968951c6300SRichard Henderson         tcg_temp_free_i32(t1);
969951c6300SRichard Henderson     }
970951c6300SRichard Henderson }
971951c6300SRichard Henderson 
972951c6300SRichard Henderson /* 64-bit ops */
973951c6300SRichard Henderson 
974951c6300SRichard Henderson #if TCG_TARGET_REG_BITS == 32
975951c6300SRichard Henderson /* These are all inline for TCG_TARGET_REG_BITS == 64.  */
976951c6300SRichard Henderson 
977951c6300SRichard Henderson void tcg_gen_discard_i64(TCGv_i64 arg)
978951c6300SRichard Henderson {
979951c6300SRichard Henderson     tcg_gen_discard_i32(TCGV_LOW(arg));
980951c6300SRichard Henderson     tcg_gen_discard_i32(TCGV_HIGH(arg));
981951c6300SRichard Henderson }
982951c6300SRichard Henderson 
983951c6300SRichard Henderson void tcg_gen_mov_i64(TCGv_i64 ret, TCGv_i64 arg)
984951c6300SRichard Henderson {
985951c6300SRichard Henderson     tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg));
986951c6300SRichard Henderson     tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg));
987951c6300SRichard Henderson }
988951c6300SRichard Henderson 
989951c6300SRichard Henderson void tcg_gen_movi_i64(TCGv_i64 ret, int64_t arg)
990951c6300SRichard Henderson {
991951c6300SRichard Henderson     tcg_gen_movi_i32(TCGV_LOW(ret), arg);
992951c6300SRichard Henderson     tcg_gen_movi_i32(TCGV_HIGH(ret), arg >> 32);
993951c6300SRichard Henderson }
994951c6300SRichard Henderson 
995951c6300SRichard Henderson void tcg_gen_ld8u_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset)
996951c6300SRichard Henderson {
997951c6300SRichard Henderson     tcg_gen_ld8u_i32(TCGV_LOW(ret), arg2, offset);
998951c6300SRichard Henderson     tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
999951c6300SRichard Henderson }
1000951c6300SRichard Henderson 
1001951c6300SRichard Henderson void tcg_gen_ld8s_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset)
1002951c6300SRichard Henderson {
1003951c6300SRichard Henderson     tcg_gen_ld8s_i32(TCGV_LOW(ret), arg2, offset);
10043ff91d7eSJoseph Myers     tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31);
1005951c6300SRichard Henderson }
1006951c6300SRichard Henderson 
1007951c6300SRichard Henderson void tcg_gen_ld16u_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset)
1008951c6300SRichard Henderson {
1009951c6300SRichard Henderson     tcg_gen_ld16u_i32(TCGV_LOW(ret), arg2, offset);
1010951c6300SRichard Henderson     tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
1011951c6300SRichard Henderson }
1012951c6300SRichard Henderson 
1013951c6300SRichard Henderson void tcg_gen_ld16s_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset)
1014951c6300SRichard Henderson {
1015951c6300SRichard Henderson     tcg_gen_ld16s_i32(TCGV_LOW(ret), arg2, offset);
1016951c6300SRichard Henderson     tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31);
1017951c6300SRichard Henderson }
1018951c6300SRichard Henderson 
1019951c6300SRichard Henderson void tcg_gen_ld32u_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset)
1020951c6300SRichard Henderson {
1021951c6300SRichard Henderson     tcg_gen_ld_i32(TCGV_LOW(ret), arg2, offset);
1022951c6300SRichard Henderson     tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
1023951c6300SRichard Henderson }
1024951c6300SRichard Henderson 
1025951c6300SRichard Henderson void tcg_gen_ld32s_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset)
1026951c6300SRichard Henderson {
1027951c6300SRichard Henderson     tcg_gen_ld_i32(TCGV_LOW(ret), arg2, offset);
1028951c6300SRichard Henderson     tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31);
1029951c6300SRichard Henderson }
1030951c6300SRichard Henderson 
1031951c6300SRichard Henderson void tcg_gen_ld_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset)
1032951c6300SRichard Henderson {
1033951c6300SRichard Henderson     /* Since arg2 and ret have different types,
1034951c6300SRichard Henderson        they cannot be the same temporary */
1035cf811fffSPeter Maydell #ifdef HOST_WORDS_BIGENDIAN
1036951c6300SRichard Henderson     tcg_gen_ld_i32(TCGV_HIGH(ret), arg2, offset);
1037951c6300SRichard Henderson     tcg_gen_ld_i32(TCGV_LOW(ret), arg2, offset + 4);
1038951c6300SRichard Henderson #else
1039951c6300SRichard Henderson     tcg_gen_ld_i32(TCGV_LOW(ret), arg2, offset);
1040951c6300SRichard Henderson     tcg_gen_ld_i32(TCGV_HIGH(ret), arg2, offset + 4);
1041951c6300SRichard Henderson #endif
1042951c6300SRichard Henderson }
1043951c6300SRichard Henderson 
1044951c6300SRichard Henderson void tcg_gen_st_i64(TCGv_i64 arg1, TCGv_ptr arg2, tcg_target_long offset)
1045951c6300SRichard Henderson {
1046cf811fffSPeter Maydell #ifdef HOST_WORDS_BIGENDIAN
1047951c6300SRichard Henderson     tcg_gen_st_i32(TCGV_HIGH(arg1), arg2, offset);
1048951c6300SRichard Henderson     tcg_gen_st_i32(TCGV_LOW(arg1), arg2, offset + 4);
1049951c6300SRichard Henderson #else
1050951c6300SRichard Henderson     tcg_gen_st_i32(TCGV_LOW(arg1), arg2, offset);
1051951c6300SRichard Henderson     tcg_gen_st_i32(TCGV_HIGH(arg1), arg2, offset + 4);
1052951c6300SRichard Henderson #endif
1053951c6300SRichard Henderson }
1054951c6300SRichard Henderson 
1055951c6300SRichard Henderson void tcg_gen_and_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
1056951c6300SRichard Henderson {
1057951c6300SRichard Henderson     tcg_gen_and_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2));
1058951c6300SRichard Henderson     tcg_gen_and_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2));
1059951c6300SRichard Henderson }
1060951c6300SRichard Henderson 
1061951c6300SRichard Henderson void tcg_gen_or_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
1062951c6300SRichard Henderson {
1063951c6300SRichard Henderson     tcg_gen_or_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2));
1064951c6300SRichard Henderson     tcg_gen_or_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2));
1065951c6300SRichard Henderson }
1066951c6300SRichard Henderson 
1067951c6300SRichard Henderson void tcg_gen_xor_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
1068951c6300SRichard Henderson {
1069951c6300SRichard Henderson     tcg_gen_xor_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2));
1070951c6300SRichard Henderson     tcg_gen_xor_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2));
1071951c6300SRichard Henderson }
1072951c6300SRichard Henderson 
1073951c6300SRichard Henderson void tcg_gen_shl_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
1074951c6300SRichard Henderson {
1075951c6300SRichard Henderson     gen_helper_shl_i64(ret, arg1, arg2);
1076951c6300SRichard Henderson }
1077951c6300SRichard Henderson 
1078951c6300SRichard Henderson void tcg_gen_shr_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
1079951c6300SRichard Henderson {
1080951c6300SRichard Henderson     gen_helper_shr_i64(ret, arg1, arg2);
1081951c6300SRichard Henderson }
1082951c6300SRichard Henderson 
1083951c6300SRichard Henderson void tcg_gen_sar_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
1084951c6300SRichard Henderson {
1085951c6300SRichard Henderson     gen_helper_sar_i64(ret, arg1, arg2);
1086951c6300SRichard Henderson }
1087951c6300SRichard Henderson 
1088951c6300SRichard Henderson void tcg_gen_mul_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
1089951c6300SRichard Henderson {
1090951c6300SRichard Henderson     TCGv_i64 t0;
1091951c6300SRichard Henderson     TCGv_i32 t1;
1092951c6300SRichard Henderson 
1093951c6300SRichard Henderson     t0 = tcg_temp_new_i64();
1094951c6300SRichard Henderson     t1 = tcg_temp_new_i32();
1095951c6300SRichard Henderson 
1096951c6300SRichard Henderson     tcg_gen_mulu2_i32(TCGV_LOW(t0), TCGV_HIGH(t0),
1097951c6300SRichard Henderson                       TCGV_LOW(arg1), TCGV_LOW(arg2));
1098951c6300SRichard Henderson 
1099951c6300SRichard Henderson     tcg_gen_mul_i32(t1, TCGV_LOW(arg1), TCGV_HIGH(arg2));
1100951c6300SRichard Henderson     tcg_gen_add_i32(TCGV_HIGH(t0), TCGV_HIGH(t0), t1);
1101951c6300SRichard Henderson     tcg_gen_mul_i32(t1, TCGV_HIGH(arg1), TCGV_LOW(arg2));
1102951c6300SRichard Henderson     tcg_gen_add_i32(TCGV_HIGH(t0), TCGV_HIGH(t0), t1);
1103951c6300SRichard Henderson 
1104951c6300SRichard Henderson     tcg_gen_mov_i64(ret, t0);
1105951c6300SRichard Henderson     tcg_temp_free_i64(t0);
1106951c6300SRichard Henderson     tcg_temp_free_i32(t1);
1107951c6300SRichard Henderson }
1108951c6300SRichard Henderson #endif /* TCG_TARGET_REG_SIZE == 32 */
1109951c6300SRichard Henderson 
1110951c6300SRichard Henderson void tcg_gen_addi_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
1111951c6300SRichard Henderson {
1112951c6300SRichard Henderson     /* some cases can be optimized here */
1113951c6300SRichard Henderson     if (arg2 == 0) {
1114951c6300SRichard Henderson         tcg_gen_mov_i64(ret, arg1);
1115951c6300SRichard Henderson     } else {
1116951c6300SRichard Henderson         TCGv_i64 t0 = tcg_const_i64(arg2);
1117951c6300SRichard Henderson         tcg_gen_add_i64(ret, arg1, t0);
1118951c6300SRichard Henderson         tcg_temp_free_i64(t0);
1119951c6300SRichard Henderson     }
1120951c6300SRichard Henderson }
1121951c6300SRichard Henderson 
1122951c6300SRichard Henderson void tcg_gen_subfi_i64(TCGv_i64 ret, int64_t arg1, TCGv_i64 arg2)
1123951c6300SRichard Henderson {
1124951c6300SRichard Henderson     if (arg1 == 0 && TCG_TARGET_HAS_neg_i64) {
1125951c6300SRichard Henderson         /* Don't recurse with tcg_gen_neg_i64.  */
1126951c6300SRichard Henderson         tcg_gen_op2_i64(INDEX_op_neg_i64, ret, arg2);
1127951c6300SRichard Henderson     } else {
1128951c6300SRichard Henderson         TCGv_i64 t0 = tcg_const_i64(arg1);
1129951c6300SRichard Henderson         tcg_gen_sub_i64(ret, t0, arg2);
1130951c6300SRichard Henderson         tcg_temp_free_i64(t0);
1131951c6300SRichard Henderson     }
1132951c6300SRichard Henderson }
1133951c6300SRichard Henderson 
1134951c6300SRichard Henderson void tcg_gen_subi_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
1135951c6300SRichard Henderson {
1136951c6300SRichard Henderson     /* some cases can be optimized here */
1137951c6300SRichard Henderson     if (arg2 == 0) {
1138951c6300SRichard Henderson         tcg_gen_mov_i64(ret, arg1);
1139951c6300SRichard Henderson     } else {
1140951c6300SRichard Henderson         TCGv_i64 t0 = tcg_const_i64(arg2);
1141951c6300SRichard Henderson         tcg_gen_sub_i64(ret, arg1, t0);
1142951c6300SRichard Henderson         tcg_temp_free_i64(t0);
1143951c6300SRichard Henderson     }
1144951c6300SRichard Henderson }
1145951c6300SRichard Henderson 
1146951c6300SRichard Henderson void tcg_gen_andi_i64(TCGv_i64 ret, TCGv_i64 arg1, uint64_t arg2)
1147951c6300SRichard Henderson {
11483a13c3f3SRichard Henderson     TCGv_i64 t0;
11493a13c3f3SRichard Henderson 
11503a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
1151951c6300SRichard Henderson         tcg_gen_andi_i32(TCGV_LOW(ret), TCGV_LOW(arg1), arg2);
1152951c6300SRichard Henderson         tcg_gen_andi_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), arg2 >> 32);
11533a13c3f3SRichard Henderson         return;
11543a13c3f3SRichard Henderson     }
11553a13c3f3SRichard Henderson 
1156951c6300SRichard Henderson     /* Some cases can be optimized here.  */
1157951c6300SRichard Henderson     switch (arg2) {
1158951c6300SRichard Henderson     case 0:
1159951c6300SRichard Henderson         tcg_gen_movi_i64(ret, 0);
1160951c6300SRichard Henderson         return;
1161951c6300SRichard Henderson     case 0xffffffffffffffffull:
1162951c6300SRichard Henderson         tcg_gen_mov_i64(ret, arg1);
1163951c6300SRichard Henderson         return;
1164951c6300SRichard Henderson     case 0xffull:
1165951c6300SRichard Henderson         /* Don't recurse with tcg_gen_ext8u_i64.  */
1166951c6300SRichard Henderson         if (TCG_TARGET_HAS_ext8u_i64) {
1167951c6300SRichard Henderson             tcg_gen_op2_i64(INDEX_op_ext8u_i64, ret, arg1);
1168951c6300SRichard Henderson             return;
1169951c6300SRichard Henderson         }
1170951c6300SRichard Henderson         break;
1171951c6300SRichard Henderson     case 0xffffu:
1172951c6300SRichard Henderson         if (TCG_TARGET_HAS_ext16u_i64) {
1173951c6300SRichard Henderson             tcg_gen_op2_i64(INDEX_op_ext16u_i64, ret, arg1);
1174951c6300SRichard Henderson             return;
1175951c6300SRichard Henderson         }
1176951c6300SRichard Henderson         break;
1177951c6300SRichard Henderson     case 0xffffffffull:
1178951c6300SRichard Henderson         if (TCG_TARGET_HAS_ext32u_i64) {
1179951c6300SRichard Henderson             tcg_gen_op2_i64(INDEX_op_ext32u_i64, ret, arg1);
1180951c6300SRichard Henderson             return;
1181951c6300SRichard Henderson         }
1182951c6300SRichard Henderson         break;
1183951c6300SRichard Henderson     }
1184951c6300SRichard Henderson     t0 = tcg_const_i64(arg2);
1185951c6300SRichard Henderson     tcg_gen_and_i64(ret, arg1, t0);
1186951c6300SRichard Henderson     tcg_temp_free_i64(t0);
1187951c6300SRichard Henderson }
1188951c6300SRichard Henderson 
1189951c6300SRichard Henderson void tcg_gen_ori_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
1190951c6300SRichard Henderson {
11913a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
1192951c6300SRichard Henderson         tcg_gen_ori_i32(TCGV_LOW(ret), TCGV_LOW(arg1), arg2);
1193951c6300SRichard Henderson         tcg_gen_ori_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), arg2 >> 32);
11943a13c3f3SRichard Henderson         return;
11953a13c3f3SRichard Henderson     }
1196951c6300SRichard Henderson     /* Some cases can be optimized here.  */
1197951c6300SRichard Henderson     if (arg2 == -1) {
1198951c6300SRichard Henderson         tcg_gen_movi_i64(ret, -1);
1199951c6300SRichard Henderson     } else if (arg2 == 0) {
1200951c6300SRichard Henderson         tcg_gen_mov_i64(ret, arg1);
1201951c6300SRichard Henderson     } else {
1202951c6300SRichard Henderson         TCGv_i64 t0 = tcg_const_i64(arg2);
1203951c6300SRichard Henderson         tcg_gen_or_i64(ret, arg1, t0);
1204951c6300SRichard Henderson         tcg_temp_free_i64(t0);
1205951c6300SRichard Henderson     }
1206951c6300SRichard Henderson }
1207951c6300SRichard Henderson 
1208951c6300SRichard Henderson void tcg_gen_xori_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
1209951c6300SRichard Henderson {
12103a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
1211951c6300SRichard Henderson         tcg_gen_xori_i32(TCGV_LOW(ret), TCGV_LOW(arg1), arg2);
1212951c6300SRichard Henderson         tcg_gen_xori_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), arg2 >> 32);
12133a13c3f3SRichard Henderson         return;
12143a13c3f3SRichard Henderson     }
1215951c6300SRichard Henderson     /* Some cases can be optimized here.  */
1216951c6300SRichard Henderson     if (arg2 == 0) {
1217951c6300SRichard Henderson         tcg_gen_mov_i64(ret, arg1);
1218951c6300SRichard Henderson     } else if (arg2 == -1 && TCG_TARGET_HAS_not_i64) {
1219951c6300SRichard Henderson         /* Don't recurse with tcg_gen_not_i64.  */
1220951c6300SRichard Henderson         tcg_gen_op2_i64(INDEX_op_not_i64, ret, arg1);
1221951c6300SRichard Henderson     } else {
1222951c6300SRichard Henderson         TCGv_i64 t0 = tcg_const_i64(arg2);
1223951c6300SRichard Henderson         tcg_gen_xor_i64(ret, arg1, t0);
1224951c6300SRichard Henderson         tcg_temp_free_i64(t0);
1225951c6300SRichard Henderson     }
1226951c6300SRichard Henderson }
1227951c6300SRichard Henderson 
1228951c6300SRichard Henderson static inline void tcg_gen_shifti_i64(TCGv_i64 ret, TCGv_i64 arg1,
1229951c6300SRichard Henderson                                       unsigned c, bool right, bool arith)
1230951c6300SRichard Henderson {
1231951c6300SRichard Henderson     tcg_debug_assert(c < 64);
1232951c6300SRichard Henderson     if (c == 0) {
1233951c6300SRichard Henderson         tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg1));
1234951c6300SRichard Henderson         tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1));
1235951c6300SRichard Henderson     } else if (c >= 32) {
1236951c6300SRichard Henderson         c -= 32;
1237951c6300SRichard Henderson         if (right) {
1238951c6300SRichard Henderson             if (arith) {
1239951c6300SRichard Henderson                 tcg_gen_sari_i32(TCGV_LOW(ret), TCGV_HIGH(arg1), c);
1240951c6300SRichard Henderson                 tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), 31);
1241951c6300SRichard Henderson             } else {
1242951c6300SRichard Henderson                 tcg_gen_shri_i32(TCGV_LOW(ret), TCGV_HIGH(arg1), c);
1243951c6300SRichard Henderson                 tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
1244951c6300SRichard Henderson             }
1245951c6300SRichard Henderson         } else {
1246951c6300SRichard Henderson             tcg_gen_shli_i32(TCGV_HIGH(ret), TCGV_LOW(arg1), c);
1247951c6300SRichard Henderson             tcg_gen_movi_i32(TCGV_LOW(ret), 0);
1248951c6300SRichard Henderson         }
1249951c6300SRichard Henderson     } else {
1250951c6300SRichard Henderson         TCGv_i32 t0, t1;
1251951c6300SRichard Henderson 
1252951c6300SRichard Henderson         t0 = tcg_temp_new_i32();
1253951c6300SRichard Henderson         t1 = tcg_temp_new_i32();
1254951c6300SRichard Henderson         if (right) {
1255951c6300SRichard Henderson             tcg_gen_shli_i32(t0, TCGV_HIGH(arg1), 32 - c);
1256951c6300SRichard Henderson             if (arith) {
1257951c6300SRichard Henderson                 tcg_gen_sari_i32(t1, TCGV_HIGH(arg1), c);
1258951c6300SRichard Henderson             } else {
1259951c6300SRichard Henderson                 tcg_gen_shri_i32(t1, TCGV_HIGH(arg1), c);
1260951c6300SRichard Henderson             }
1261951c6300SRichard Henderson             tcg_gen_shri_i32(TCGV_LOW(ret), TCGV_LOW(arg1), c);
1262951c6300SRichard Henderson             tcg_gen_or_i32(TCGV_LOW(ret), TCGV_LOW(ret), t0);
1263951c6300SRichard Henderson             tcg_gen_mov_i32(TCGV_HIGH(ret), t1);
1264951c6300SRichard Henderson         } else {
1265951c6300SRichard Henderson             tcg_gen_shri_i32(t0, TCGV_LOW(arg1), 32 - c);
1266951c6300SRichard Henderson             /* Note: ret can be the same as arg1, so we use t1 */
1267951c6300SRichard Henderson             tcg_gen_shli_i32(t1, TCGV_LOW(arg1), c);
1268951c6300SRichard Henderson             tcg_gen_shli_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), c);
1269951c6300SRichard Henderson             tcg_gen_or_i32(TCGV_HIGH(ret), TCGV_HIGH(ret), t0);
1270951c6300SRichard Henderson             tcg_gen_mov_i32(TCGV_LOW(ret), t1);
1271951c6300SRichard Henderson         }
1272951c6300SRichard Henderson         tcg_temp_free_i32(t0);
1273951c6300SRichard Henderson         tcg_temp_free_i32(t1);
1274951c6300SRichard Henderson     }
1275951c6300SRichard Henderson }
1276951c6300SRichard Henderson 
1277951c6300SRichard Henderson void tcg_gen_shli_i64(TCGv_i64 ret, TCGv_i64 arg1, unsigned arg2)
1278951c6300SRichard Henderson {
1279951c6300SRichard Henderson     tcg_debug_assert(arg2 < 64);
12803a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
12813a13c3f3SRichard Henderson         tcg_gen_shifti_i64(ret, arg1, arg2, 0, 0);
12823a13c3f3SRichard Henderson     } else if (arg2 == 0) {
1283951c6300SRichard Henderson         tcg_gen_mov_i64(ret, arg1);
1284951c6300SRichard Henderson     } else {
1285951c6300SRichard Henderson         TCGv_i64 t0 = tcg_const_i64(arg2);
1286951c6300SRichard Henderson         tcg_gen_shl_i64(ret, arg1, t0);
1287951c6300SRichard Henderson         tcg_temp_free_i64(t0);
1288951c6300SRichard Henderson     }
1289951c6300SRichard Henderson }
1290951c6300SRichard Henderson 
1291951c6300SRichard Henderson void tcg_gen_shri_i64(TCGv_i64 ret, TCGv_i64 arg1, unsigned arg2)
1292951c6300SRichard Henderson {
1293951c6300SRichard Henderson     tcg_debug_assert(arg2 < 64);
12943a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
12953a13c3f3SRichard Henderson         tcg_gen_shifti_i64(ret, arg1, arg2, 1, 0);
12963a13c3f3SRichard Henderson     } else if (arg2 == 0) {
1297951c6300SRichard Henderson         tcg_gen_mov_i64(ret, arg1);
1298951c6300SRichard Henderson     } else {
1299951c6300SRichard Henderson         TCGv_i64 t0 = tcg_const_i64(arg2);
1300951c6300SRichard Henderson         tcg_gen_shr_i64(ret, arg1, t0);
1301951c6300SRichard Henderson         tcg_temp_free_i64(t0);
1302951c6300SRichard Henderson     }
1303951c6300SRichard Henderson }
1304951c6300SRichard Henderson 
1305951c6300SRichard Henderson void tcg_gen_sari_i64(TCGv_i64 ret, TCGv_i64 arg1, unsigned arg2)
1306951c6300SRichard Henderson {
1307951c6300SRichard Henderson     tcg_debug_assert(arg2 < 64);
13083a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
13093a13c3f3SRichard Henderson         tcg_gen_shifti_i64(ret, arg1, arg2, 1, 1);
13103a13c3f3SRichard 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_sar_i64(ret, arg1, t0);
1315951c6300SRichard Henderson         tcg_temp_free_i64(t0);
1316951c6300SRichard Henderson     }
1317951c6300SRichard Henderson }
1318951c6300SRichard Henderson 
131942a268c2SRichard Henderson void tcg_gen_brcond_i64(TCGCond cond, TCGv_i64 arg1, TCGv_i64 arg2, TCGLabel *l)
1320951c6300SRichard Henderson {
1321951c6300SRichard Henderson     if (cond == TCG_COND_ALWAYS) {
132242a268c2SRichard Henderson         tcg_gen_br(l);
1323951c6300SRichard Henderson     } else if (cond != TCG_COND_NEVER) {
13243a13c3f3SRichard Henderson         if (TCG_TARGET_REG_BITS == 32) {
1325951c6300SRichard Henderson             tcg_gen_op6ii_i32(INDEX_op_brcond2_i32, TCGV_LOW(arg1),
1326951c6300SRichard Henderson                               TCGV_HIGH(arg1), TCGV_LOW(arg2),
132742a268c2SRichard Henderson                               TCGV_HIGH(arg2), cond, label_arg(l));
13283a13c3f3SRichard Henderson         } else {
132942a268c2SRichard Henderson             tcg_gen_op4ii_i64(INDEX_op_brcond_i64, arg1, arg2, cond,
133042a268c2SRichard Henderson                               label_arg(l));
13313a13c3f3SRichard Henderson         }
1332951c6300SRichard Henderson     }
1333951c6300SRichard Henderson }
1334951c6300SRichard Henderson 
133542a268c2SRichard Henderson void tcg_gen_brcondi_i64(TCGCond cond, TCGv_i64 arg1, int64_t arg2, TCGLabel *l)
1336951c6300SRichard Henderson {
1337951c6300SRichard Henderson     if (cond == TCG_COND_ALWAYS) {
133842a268c2SRichard Henderson         tcg_gen_br(l);
1339951c6300SRichard Henderson     } else if (cond != TCG_COND_NEVER) {
1340951c6300SRichard Henderson         TCGv_i64 t0 = tcg_const_i64(arg2);
134142a268c2SRichard Henderson         tcg_gen_brcond_i64(cond, arg1, t0, l);
1342951c6300SRichard Henderson         tcg_temp_free_i64(t0);
1343951c6300SRichard Henderson     }
1344951c6300SRichard Henderson }
1345951c6300SRichard Henderson 
1346951c6300SRichard Henderson void tcg_gen_setcond_i64(TCGCond cond, TCGv_i64 ret,
1347951c6300SRichard Henderson                          TCGv_i64 arg1, TCGv_i64 arg2)
1348951c6300SRichard Henderson {
1349951c6300SRichard Henderson     if (cond == TCG_COND_ALWAYS) {
1350951c6300SRichard Henderson         tcg_gen_movi_i64(ret, 1);
1351951c6300SRichard Henderson     } else if (cond == TCG_COND_NEVER) {
1352951c6300SRichard Henderson         tcg_gen_movi_i64(ret, 0);
1353951c6300SRichard Henderson     } else {
13543a13c3f3SRichard Henderson         if (TCG_TARGET_REG_BITS == 32) {
1355951c6300SRichard Henderson             tcg_gen_op6i_i32(INDEX_op_setcond2_i32, TCGV_LOW(ret),
1356951c6300SRichard Henderson                              TCGV_LOW(arg1), TCGV_HIGH(arg1),
1357951c6300SRichard Henderson                              TCGV_LOW(arg2), TCGV_HIGH(arg2), cond);
1358951c6300SRichard Henderson             tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
13593a13c3f3SRichard Henderson         } else {
1360951c6300SRichard Henderson             tcg_gen_op4i_i64(INDEX_op_setcond_i64, ret, arg1, arg2, cond);
13613a13c3f3SRichard Henderson         }
1362951c6300SRichard Henderson     }
1363951c6300SRichard Henderson }
1364951c6300SRichard Henderson 
1365951c6300SRichard Henderson void tcg_gen_setcondi_i64(TCGCond cond, TCGv_i64 ret,
1366951c6300SRichard Henderson                           TCGv_i64 arg1, int64_t arg2)
1367951c6300SRichard Henderson {
1368951c6300SRichard Henderson     TCGv_i64 t0 = tcg_const_i64(arg2);
1369951c6300SRichard Henderson     tcg_gen_setcond_i64(cond, ret, arg1, t0);
1370951c6300SRichard Henderson     tcg_temp_free_i64(t0);
1371951c6300SRichard Henderson }
1372951c6300SRichard Henderson 
1373951c6300SRichard Henderson void tcg_gen_muli_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
1374951c6300SRichard Henderson {
1375951c6300SRichard Henderson     TCGv_i64 t0 = tcg_const_i64(arg2);
1376951c6300SRichard Henderson     tcg_gen_mul_i64(ret, arg1, t0);
1377951c6300SRichard Henderson     tcg_temp_free_i64(t0);
1378951c6300SRichard Henderson }
1379951c6300SRichard Henderson 
1380951c6300SRichard Henderson void tcg_gen_div_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
1381951c6300SRichard Henderson {
1382951c6300SRichard Henderson     if (TCG_TARGET_HAS_div_i64) {
1383951c6300SRichard Henderson         tcg_gen_op3_i64(INDEX_op_div_i64, ret, arg1, arg2);
1384951c6300SRichard Henderson     } else if (TCG_TARGET_HAS_div2_i64) {
1385951c6300SRichard Henderson         TCGv_i64 t0 = tcg_temp_new_i64();
1386951c6300SRichard Henderson         tcg_gen_sari_i64(t0, arg1, 63);
1387951c6300SRichard Henderson         tcg_gen_op5_i64(INDEX_op_div2_i64, ret, t0, arg1, t0, arg2);
1388951c6300SRichard Henderson         tcg_temp_free_i64(t0);
1389951c6300SRichard Henderson     } else {
1390951c6300SRichard Henderson         gen_helper_div_i64(ret, arg1, arg2);
1391951c6300SRichard Henderson     }
1392951c6300SRichard Henderson }
1393951c6300SRichard Henderson 
1394951c6300SRichard Henderson void tcg_gen_rem_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
1395951c6300SRichard Henderson {
1396951c6300SRichard Henderson     if (TCG_TARGET_HAS_rem_i64) {
1397951c6300SRichard Henderson         tcg_gen_op3_i64(INDEX_op_rem_i64, ret, arg1, arg2);
1398951c6300SRichard Henderson     } else if (TCG_TARGET_HAS_div_i64) {
1399951c6300SRichard Henderson         TCGv_i64 t0 = tcg_temp_new_i64();
1400951c6300SRichard Henderson         tcg_gen_op3_i64(INDEX_op_div_i64, t0, arg1, arg2);
1401951c6300SRichard Henderson         tcg_gen_mul_i64(t0, t0, arg2);
1402951c6300SRichard Henderson         tcg_gen_sub_i64(ret, arg1, t0);
1403951c6300SRichard Henderson         tcg_temp_free_i64(t0);
1404951c6300SRichard Henderson     } else if (TCG_TARGET_HAS_div2_i64) {
1405951c6300SRichard Henderson         TCGv_i64 t0 = tcg_temp_new_i64();
1406951c6300SRichard Henderson         tcg_gen_sari_i64(t0, arg1, 63);
1407951c6300SRichard Henderson         tcg_gen_op5_i64(INDEX_op_div2_i64, t0, ret, arg1, t0, arg2);
1408951c6300SRichard Henderson         tcg_temp_free_i64(t0);
1409951c6300SRichard Henderson     } else {
1410951c6300SRichard Henderson         gen_helper_rem_i64(ret, arg1, arg2);
1411951c6300SRichard Henderson     }
1412951c6300SRichard Henderson }
1413951c6300SRichard Henderson 
1414951c6300SRichard Henderson void tcg_gen_divu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
1415951c6300SRichard Henderson {
1416951c6300SRichard Henderson     if (TCG_TARGET_HAS_div_i64) {
1417951c6300SRichard Henderson         tcg_gen_op3_i64(INDEX_op_divu_i64, ret, arg1, arg2);
1418951c6300SRichard Henderson     } else if (TCG_TARGET_HAS_div2_i64) {
1419951c6300SRichard Henderson         TCGv_i64 t0 = tcg_temp_new_i64();
1420951c6300SRichard Henderson         tcg_gen_movi_i64(t0, 0);
1421951c6300SRichard Henderson         tcg_gen_op5_i64(INDEX_op_divu2_i64, ret, t0, arg1, t0, arg2);
1422951c6300SRichard Henderson         tcg_temp_free_i64(t0);
1423951c6300SRichard Henderson     } else {
1424951c6300SRichard Henderson         gen_helper_divu_i64(ret, arg1, arg2);
1425951c6300SRichard Henderson     }
1426951c6300SRichard Henderson }
1427951c6300SRichard Henderson 
1428951c6300SRichard Henderson void tcg_gen_remu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
1429951c6300SRichard Henderson {
1430951c6300SRichard Henderson     if (TCG_TARGET_HAS_rem_i64) {
1431951c6300SRichard Henderson         tcg_gen_op3_i64(INDEX_op_remu_i64, ret, arg1, arg2);
1432951c6300SRichard Henderson     } else if (TCG_TARGET_HAS_div_i64) {
1433951c6300SRichard Henderson         TCGv_i64 t0 = tcg_temp_new_i64();
1434951c6300SRichard Henderson         tcg_gen_op3_i64(INDEX_op_divu_i64, t0, arg1, arg2);
1435951c6300SRichard Henderson         tcg_gen_mul_i64(t0, t0, arg2);
1436951c6300SRichard Henderson         tcg_gen_sub_i64(ret, arg1, t0);
1437951c6300SRichard Henderson         tcg_temp_free_i64(t0);
1438951c6300SRichard Henderson     } else if (TCG_TARGET_HAS_div2_i64) {
1439951c6300SRichard Henderson         TCGv_i64 t0 = tcg_temp_new_i64();
1440951c6300SRichard Henderson         tcg_gen_movi_i64(t0, 0);
1441951c6300SRichard Henderson         tcg_gen_op5_i64(INDEX_op_divu2_i64, t0, ret, arg1, t0, arg2);
1442951c6300SRichard Henderson         tcg_temp_free_i64(t0);
1443951c6300SRichard Henderson     } else {
1444951c6300SRichard Henderson         gen_helper_remu_i64(ret, arg1, arg2);
1445951c6300SRichard Henderson     }
1446951c6300SRichard Henderson }
1447951c6300SRichard Henderson 
1448951c6300SRichard Henderson void tcg_gen_ext8s_i64(TCGv_i64 ret, TCGv_i64 arg)
1449951c6300SRichard Henderson {
14503a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
1451951c6300SRichard Henderson         tcg_gen_ext8s_i32(TCGV_LOW(ret), TCGV_LOW(arg));
1452951c6300SRichard Henderson         tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31);
14533a13c3f3SRichard Henderson     } else if (TCG_TARGET_HAS_ext8s_i64) {
1454951c6300SRichard Henderson         tcg_gen_op2_i64(INDEX_op_ext8s_i64, ret, arg);
1455951c6300SRichard Henderson     } else {
1456951c6300SRichard Henderson         tcg_gen_shli_i64(ret, arg, 56);
1457951c6300SRichard Henderson         tcg_gen_sari_i64(ret, ret, 56);
1458951c6300SRichard Henderson     }
1459951c6300SRichard Henderson }
1460951c6300SRichard Henderson 
1461951c6300SRichard Henderson void tcg_gen_ext16s_i64(TCGv_i64 ret, TCGv_i64 arg)
1462951c6300SRichard Henderson {
14633a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
1464951c6300SRichard Henderson         tcg_gen_ext16s_i32(TCGV_LOW(ret), TCGV_LOW(arg));
1465951c6300SRichard Henderson         tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31);
14663a13c3f3SRichard Henderson     } else if (TCG_TARGET_HAS_ext16s_i64) {
1467951c6300SRichard Henderson         tcg_gen_op2_i64(INDEX_op_ext16s_i64, ret, arg);
1468951c6300SRichard Henderson     } else {
1469951c6300SRichard Henderson         tcg_gen_shli_i64(ret, arg, 48);
1470951c6300SRichard Henderson         tcg_gen_sari_i64(ret, ret, 48);
1471951c6300SRichard Henderson     }
1472951c6300SRichard Henderson }
1473951c6300SRichard Henderson 
1474951c6300SRichard Henderson void tcg_gen_ext32s_i64(TCGv_i64 ret, TCGv_i64 arg)
1475951c6300SRichard Henderson {
14763a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
1477951c6300SRichard Henderson         tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg));
1478951c6300SRichard Henderson         tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31);
14793a13c3f3SRichard Henderson     } else if (TCG_TARGET_HAS_ext32s_i64) {
1480951c6300SRichard Henderson         tcg_gen_op2_i64(INDEX_op_ext32s_i64, ret, arg);
1481951c6300SRichard Henderson     } else {
1482951c6300SRichard Henderson         tcg_gen_shli_i64(ret, arg, 32);
1483951c6300SRichard Henderson         tcg_gen_sari_i64(ret, ret, 32);
1484951c6300SRichard Henderson     }
1485951c6300SRichard Henderson }
1486951c6300SRichard Henderson 
1487951c6300SRichard Henderson void tcg_gen_ext8u_i64(TCGv_i64 ret, TCGv_i64 arg)
1488951c6300SRichard Henderson {
14893a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
1490951c6300SRichard Henderson         tcg_gen_ext8u_i32(TCGV_LOW(ret), TCGV_LOW(arg));
1491951c6300SRichard Henderson         tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
14923a13c3f3SRichard Henderson     } else if (TCG_TARGET_HAS_ext8u_i64) {
1493951c6300SRichard Henderson         tcg_gen_op2_i64(INDEX_op_ext8u_i64, ret, arg);
1494951c6300SRichard Henderson     } else {
1495951c6300SRichard Henderson         tcg_gen_andi_i64(ret, arg, 0xffu);
1496951c6300SRichard Henderson     }
1497951c6300SRichard Henderson }
1498951c6300SRichard Henderson 
1499951c6300SRichard Henderson void tcg_gen_ext16u_i64(TCGv_i64 ret, TCGv_i64 arg)
1500951c6300SRichard Henderson {
15013a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
1502951c6300SRichard Henderson         tcg_gen_ext16u_i32(TCGV_LOW(ret), TCGV_LOW(arg));
1503951c6300SRichard Henderson         tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
15043a13c3f3SRichard Henderson     } else if (TCG_TARGET_HAS_ext16u_i64) {
1505951c6300SRichard Henderson         tcg_gen_op2_i64(INDEX_op_ext16u_i64, ret, arg);
1506951c6300SRichard Henderson     } else {
1507951c6300SRichard Henderson         tcg_gen_andi_i64(ret, arg, 0xffffu);
1508951c6300SRichard Henderson     }
1509951c6300SRichard Henderson }
1510951c6300SRichard Henderson 
1511951c6300SRichard Henderson void tcg_gen_ext32u_i64(TCGv_i64 ret, TCGv_i64 arg)
1512951c6300SRichard Henderson {
15133a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
1514951c6300SRichard Henderson         tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg));
1515951c6300SRichard Henderson         tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
15163a13c3f3SRichard Henderson     } else if (TCG_TARGET_HAS_ext32u_i64) {
1517951c6300SRichard Henderson         tcg_gen_op2_i64(INDEX_op_ext32u_i64, ret, arg);
1518951c6300SRichard Henderson     } else {
1519951c6300SRichard Henderson         tcg_gen_andi_i64(ret, arg, 0xffffffffu);
1520951c6300SRichard Henderson     }
1521951c6300SRichard Henderson }
1522951c6300SRichard Henderson 
1523951c6300SRichard Henderson /* Note: we assume the six high bytes are set to zero */
1524951c6300SRichard Henderson void tcg_gen_bswap16_i64(TCGv_i64 ret, TCGv_i64 arg)
1525951c6300SRichard Henderson {
15263a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
1527951c6300SRichard Henderson         tcg_gen_bswap16_i32(TCGV_LOW(ret), TCGV_LOW(arg));
1528951c6300SRichard Henderson         tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
15293a13c3f3SRichard Henderson     } else if (TCG_TARGET_HAS_bswap16_i64) {
1530951c6300SRichard Henderson         tcg_gen_op2_i64(INDEX_op_bswap16_i64, ret, arg);
1531951c6300SRichard Henderson     } else {
1532951c6300SRichard Henderson         TCGv_i64 t0 = tcg_temp_new_i64();
1533951c6300SRichard Henderson 
1534951c6300SRichard Henderson         tcg_gen_ext8u_i64(t0, arg);
1535951c6300SRichard Henderson         tcg_gen_shli_i64(t0, t0, 8);
1536951c6300SRichard Henderson         tcg_gen_shri_i64(ret, arg, 8);
1537951c6300SRichard Henderson         tcg_gen_or_i64(ret, ret, t0);
1538951c6300SRichard Henderson         tcg_temp_free_i64(t0);
1539951c6300SRichard Henderson     }
1540951c6300SRichard Henderson }
1541951c6300SRichard Henderson 
1542951c6300SRichard Henderson /* Note: we assume the four high bytes are set to zero */
1543951c6300SRichard Henderson void tcg_gen_bswap32_i64(TCGv_i64 ret, TCGv_i64 arg)
1544951c6300SRichard Henderson {
15453a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
1546951c6300SRichard Henderson         tcg_gen_bswap32_i32(TCGV_LOW(ret), TCGV_LOW(arg));
1547951c6300SRichard Henderson         tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
15483a13c3f3SRichard Henderson     } else if (TCG_TARGET_HAS_bswap32_i64) {
1549951c6300SRichard Henderson         tcg_gen_op2_i64(INDEX_op_bswap32_i64, ret, arg);
1550951c6300SRichard Henderson     } else {
1551951c6300SRichard Henderson         TCGv_i64 t0, t1;
1552951c6300SRichard Henderson         t0 = tcg_temp_new_i64();
1553951c6300SRichard Henderson         t1 = tcg_temp_new_i64();
1554951c6300SRichard Henderson 
1555951c6300SRichard Henderson         tcg_gen_shli_i64(t0, arg, 24);
1556951c6300SRichard Henderson         tcg_gen_ext32u_i64(t0, t0);
1557951c6300SRichard Henderson 
1558951c6300SRichard Henderson         tcg_gen_andi_i64(t1, arg, 0x0000ff00);
1559951c6300SRichard Henderson         tcg_gen_shli_i64(t1, t1, 8);
1560951c6300SRichard Henderson         tcg_gen_or_i64(t0, t0, t1);
1561951c6300SRichard Henderson 
1562951c6300SRichard Henderson         tcg_gen_shri_i64(t1, arg, 8);
1563951c6300SRichard Henderson         tcg_gen_andi_i64(t1, t1, 0x0000ff00);
1564951c6300SRichard Henderson         tcg_gen_or_i64(t0, t0, t1);
1565951c6300SRichard Henderson 
1566951c6300SRichard Henderson         tcg_gen_shri_i64(t1, arg, 24);
1567951c6300SRichard Henderson         tcg_gen_or_i64(ret, t0, t1);
1568951c6300SRichard Henderson         tcg_temp_free_i64(t0);
1569951c6300SRichard Henderson         tcg_temp_free_i64(t1);
1570951c6300SRichard Henderson     }
1571951c6300SRichard Henderson }
1572951c6300SRichard Henderson 
1573951c6300SRichard Henderson void tcg_gen_bswap64_i64(TCGv_i64 ret, TCGv_i64 arg)
1574951c6300SRichard Henderson {
15753a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
1576951c6300SRichard Henderson         TCGv_i32 t0, t1;
1577951c6300SRichard Henderson         t0 = tcg_temp_new_i32();
1578951c6300SRichard Henderson         t1 = tcg_temp_new_i32();
1579951c6300SRichard Henderson 
1580951c6300SRichard Henderson         tcg_gen_bswap32_i32(t0, TCGV_LOW(arg));
1581951c6300SRichard Henderson         tcg_gen_bswap32_i32(t1, TCGV_HIGH(arg));
1582951c6300SRichard Henderson         tcg_gen_mov_i32(TCGV_LOW(ret), t1);
1583951c6300SRichard Henderson         tcg_gen_mov_i32(TCGV_HIGH(ret), t0);
1584951c6300SRichard Henderson         tcg_temp_free_i32(t0);
1585951c6300SRichard Henderson         tcg_temp_free_i32(t1);
15863a13c3f3SRichard Henderson     } else if (TCG_TARGET_HAS_bswap64_i64) {
1587951c6300SRichard Henderson         tcg_gen_op2_i64(INDEX_op_bswap64_i64, ret, arg);
1588951c6300SRichard Henderson     } else {
1589951c6300SRichard Henderson         TCGv_i64 t0 = tcg_temp_new_i64();
1590951c6300SRichard Henderson         TCGv_i64 t1 = tcg_temp_new_i64();
1591951c6300SRichard Henderson 
1592951c6300SRichard Henderson         tcg_gen_shli_i64(t0, arg, 56);
1593951c6300SRichard Henderson 
1594951c6300SRichard Henderson         tcg_gen_andi_i64(t1, arg, 0x0000ff00);
1595951c6300SRichard Henderson         tcg_gen_shli_i64(t1, t1, 40);
1596951c6300SRichard Henderson         tcg_gen_or_i64(t0, t0, t1);
1597951c6300SRichard Henderson 
1598951c6300SRichard Henderson         tcg_gen_andi_i64(t1, arg, 0x00ff0000);
1599951c6300SRichard Henderson         tcg_gen_shli_i64(t1, t1, 24);
1600951c6300SRichard Henderson         tcg_gen_or_i64(t0, t0, t1);
1601951c6300SRichard Henderson 
1602951c6300SRichard Henderson         tcg_gen_andi_i64(t1, arg, 0xff000000);
1603951c6300SRichard Henderson         tcg_gen_shli_i64(t1, t1, 8);
1604951c6300SRichard Henderson         tcg_gen_or_i64(t0, t0, t1);
1605951c6300SRichard Henderson 
1606951c6300SRichard Henderson         tcg_gen_shri_i64(t1, arg, 8);
1607951c6300SRichard Henderson         tcg_gen_andi_i64(t1, t1, 0xff000000);
1608951c6300SRichard Henderson         tcg_gen_or_i64(t0, t0, t1);
1609951c6300SRichard Henderson 
1610951c6300SRichard Henderson         tcg_gen_shri_i64(t1, arg, 24);
1611951c6300SRichard Henderson         tcg_gen_andi_i64(t1, t1, 0x00ff0000);
1612951c6300SRichard Henderson         tcg_gen_or_i64(t0, t0, t1);
1613951c6300SRichard Henderson 
1614951c6300SRichard Henderson         tcg_gen_shri_i64(t1, arg, 40);
1615951c6300SRichard Henderson         tcg_gen_andi_i64(t1, t1, 0x0000ff00);
1616951c6300SRichard Henderson         tcg_gen_or_i64(t0, t0, t1);
1617951c6300SRichard Henderson 
1618951c6300SRichard Henderson         tcg_gen_shri_i64(t1, arg, 56);
1619951c6300SRichard Henderson         tcg_gen_or_i64(ret, t0, t1);
1620951c6300SRichard Henderson         tcg_temp_free_i64(t0);
1621951c6300SRichard Henderson         tcg_temp_free_i64(t1);
1622951c6300SRichard Henderson     }
1623951c6300SRichard Henderson }
1624951c6300SRichard Henderson 
1625951c6300SRichard Henderson void tcg_gen_not_i64(TCGv_i64 ret, TCGv_i64 arg)
1626951c6300SRichard Henderson {
16273a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
16283a13c3f3SRichard Henderson         tcg_gen_not_i32(TCGV_LOW(ret), TCGV_LOW(arg));
16293a13c3f3SRichard Henderson         tcg_gen_not_i32(TCGV_HIGH(ret), TCGV_HIGH(arg));
16303a13c3f3SRichard Henderson     } else if (TCG_TARGET_HAS_not_i64) {
1631951c6300SRichard Henderson         tcg_gen_op2_i64(INDEX_op_not_i64, ret, arg);
1632951c6300SRichard Henderson     } else {
1633951c6300SRichard Henderson         tcg_gen_xori_i64(ret, arg, -1);
1634951c6300SRichard Henderson     }
1635951c6300SRichard Henderson }
1636951c6300SRichard Henderson 
1637951c6300SRichard Henderson void tcg_gen_andc_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
1638951c6300SRichard Henderson {
16393a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
16403a13c3f3SRichard Henderson         tcg_gen_andc_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2));
16413a13c3f3SRichard Henderson         tcg_gen_andc_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2));
16423a13c3f3SRichard Henderson     } else if (TCG_TARGET_HAS_andc_i64) {
1643951c6300SRichard Henderson         tcg_gen_op3_i64(INDEX_op_andc_i64, ret, arg1, arg2);
1644951c6300SRichard Henderson     } else {
1645951c6300SRichard Henderson         TCGv_i64 t0 = tcg_temp_new_i64();
1646951c6300SRichard Henderson         tcg_gen_not_i64(t0, arg2);
1647951c6300SRichard Henderson         tcg_gen_and_i64(ret, arg1, t0);
1648951c6300SRichard Henderson         tcg_temp_free_i64(t0);
1649951c6300SRichard Henderson     }
1650951c6300SRichard Henderson }
1651951c6300SRichard Henderson 
1652951c6300SRichard Henderson void tcg_gen_eqv_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
1653951c6300SRichard Henderson {
16543a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
16553a13c3f3SRichard Henderson         tcg_gen_eqv_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2));
16563a13c3f3SRichard Henderson         tcg_gen_eqv_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2));
16573a13c3f3SRichard Henderson     } else if (TCG_TARGET_HAS_eqv_i64) {
1658951c6300SRichard Henderson         tcg_gen_op3_i64(INDEX_op_eqv_i64, ret, arg1, arg2);
1659951c6300SRichard Henderson     } else {
1660951c6300SRichard Henderson         tcg_gen_xor_i64(ret, arg1, arg2);
1661951c6300SRichard Henderson         tcg_gen_not_i64(ret, ret);
1662951c6300SRichard Henderson     }
1663951c6300SRichard Henderson }
1664951c6300SRichard Henderson 
1665951c6300SRichard Henderson void tcg_gen_nand_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
1666951c6300SRichard Henderson {
16673a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
16683a13c3f3SRichard Henderson         tcg_gen_nand_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2));
16693a13c3f3SRichard Henderson         tcg_gen_nand_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2));
16703a13c3f3SRichard Henderson     } else if (TCG_TARGET_HAS_nand_i64) {
1671951c6300SRichard Henderson         tcg_gen_op3_i64(INDEX_op_nand_i64, ret, arg1, arg2);
1672951c6300SRichard Henderson     } else {
1673951c6300SRichard Henderson         tcg_gen_and_i64(ret, arg1, arg2);
1674951c6300SRichard Henderson         tcg_gen_not_i64(ret, ret);
1675951c6300SRichard Henderson     }
1676951c6300SRichard Henderson }
1677951c6300SRichard Henderson 
1678951c6300SRichard Henderson void tcg_gen_nor_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
1679951c6300SRichard Henderson {
16803a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
16813a13c3f3SRichard Henderson         tcg_gen_nor_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2));
16823a13c3f3SRichard Henderson         tcg_gen_nor_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2));
16833a13c3f3SRichard Henderson     } else if (TCG_TARGET_HAS_nor_i64) {
1684951c6300SRichard Henderson         tcg_gen_op3_i64(INDEX_op_nor_i64, ret, arg1, arg2);
1685951c6300SRichard Henderson     } else {
1686951c6300SRichard Henderson         tcg_gen_or_i64(ret, arg1, arg2);
1687951c6300SRichard Henderson         tcg_gen_not_i64(ret, ret);
1688951c6300SRichard Henderson     }
1689951c6300SRichard Henderson }
1690951c6300SRichard Henderson 
1691951c6300SRichard Henderson void tcg_gen_orc_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
1692951c6300SRichard Henderson {
16933a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
16943a13c3f3SRichard Henderson         tcg_gen_orc_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2));
16953a13c3f3SRichard Henderson         tcg_gen_orc_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2));
16963a13c3f3SRichard Henderson     } else if (TCG_TARGET_HAS_orc_i64) {
1697951c6300SRichard Henderson         tcg_gen_op3_i64(INDEX_op_orc_i64, ret, arg1, arg2);
1698951c6300SRichard Henderson     } else {
1699951c6300SRichard Henderson         TCGv_i64 t0 = tcg_temp_new_i64();
1700951c6300SRichard Henderson         tcg_gen_not_i64(t0, arg2);
1701951c6300SRichard Henderson         tcg_gen_or_i64(ret, arg1, t0);
1702951c6300SRichard Henderson         tcg_temp_free_i64(t0);
1703951c6300SRichard Henderson     }
1704951c6300SRichard Henderson }
1705951c6300SRichard Henderson 
1706951c6300SRichard Henderson void tcg_gen_rotl_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
1707951c6300SRichard Henderson {
1708951c6300SRichard Henderson     if (TCG_TARGET_HAS_rot_i64) {
1709951c6300SRichard Henderson         tcg_gen_op3_i64(INDEX_op_rotl_i64, ret, arg1, arg2);
1710951c6300SRichard Henderson     } else {
1711951c6300SRichard Henderson         TCGv_i64 t0, t1;
1712951c6300SRichard Henderson         t0 = tcg_temp_new_i64();
1713951c6300SRichard Henderson         t1 = tcg_temp_new_i64();
1714951c6300SRichard Henderson         tcg_gen_shl_i64(t0, arg1, arg2);
1715951c6300SRichard Henderson         tcg_gen_subfi_i64(t1, 64, arg2);
1716951c6300SRichard Henderson         tcg_gen_shr_i64(t1, arg1, t1);
1717951c6300SRichard Henderson         tcg_gen_or_i64(ret, t0, t1);
1718951c6300SRichard Henderson         tcg_temp_free_i64(t0);
1719951c6300SRichard Henderson         tcg_temp_free_i64(t1);
1720951c6300SRichard Henderson     }
1721951c6300SRichard Henderson }
1722951c6300SRichard Henderson 
1723951c6300SRichard Henderson void tcg_gen_rotli_i64(TCGv_i64 ret, TCGv_i64 arg1, unsigned arg2)
1724951c6300SRichard Henderson {
1725951c6300SRichard Henderson     tcg_debug_assert(arg2 < 64);
1726951c6300SRichard Henderson     /* some cases can be optimized here */
1727951c6300SRichard Henderson     if (arg2 == 0) {
1728951c6300SRichard Henderson         tcg_gen_mov_i64(ret, arg1);
1729951c6300SRichard Henderson     } else if (TCG_TARGET_HAS_rot_i64) {
1730951c6300SRichard Henderson         TCGv_i64 t0 = tcg_const_i64(arg2);
1731951c6300SRichard Henderson         tcg_gen_rotl_i64(ret, arg1, t0);
1732951c6300SRichard Henderson         tcg_temp_free_i64(t0);
1733951c6300SRichard Henderson     } else {
1734951c6300SRichard Henderson         TCGv_i64 t0, t1;
1735951c6300SRichard Henderson         t0 = tcg_temp_new_i64();
1736951c6300SRichard Henderson         t1 = tcg_temp_new_i64();
1737951c6300SRichard Henderson         tcg_gen_shli_i64(t0, arg1, arg2);
1738951c6300SRichard Henderson         tcg_gen_shri_i64(t1, arg1, 64 - arg2);
1739951c6300SRichard Henderson         tcg_gen_or_i64(ret, t0, t1);
1740951c6300SRichard Henderson         tcg_temp_free_i64(t0);
1741951c6300SRichard Henderson         tcg_temp_free_i64(t1);
1742951c6300SRichard Henderson     }
1743951c6300SRichard Henderson }
1744951c6300SRichard Henderson 
1745951c6300SRichard Henderson void tcg_gen_rotr_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
1746951c6300SRichard Henderson {
1747951c6300SRichard Henderson     if (TCG_TARGET_HAS_rot_i64) {
1748951c6300SRichard Henderson         tcg_gen_op3_i64(INDEX_op_rotr_i64, ret, arg1, arg2);
1749951c6300SRichard Henderson     } else {
1750951c6300SRichard Henderson         TCGv_i64 t0, t1;
1751951c6300SRichard Henderson         t0 = tcg_temp_new_i64();
1752951c6300SRichard Henderson         t1 = tcg_temp_new_i64();
1753951c6300SRichard Henderson         tcg_gen_shr_i64(t0, arg1, arg2);
1754951c6300SRichard Henderson         tcg_gen_subfi_i64(t1, 64, arg2);
1755951c6300SRichard Henderson         tcg_gen_shl_i64(t1, arg1, t1);
1756951c6300SRichard Henderson         tcg_gen_or_i64(ret, t0, t1);
1757951c6300SRichard Henderson         tcg_temp_free_i64(t0);
1758951c6300SRichard Henderson         tcg_temp_free_i64(t1);
1759951c6300SRichard Henderson     }
1760951c6300SRichard Henderson }
1761951c6300SRichard Henderson 
1762951c6300SRichard Henderson void tcg_gen_rotri_i64(TCGv_i64 ret, TCGv_i64 arg1, unsigned arg2)
1763951c6300SRichard Henderson {
1764951c6300SRichard Henderson     tcg_debug_assert(arg2 < 64);
1765951c6300SRichard Henderson     /* some cases can be optimized here */
1766951c6300SRichard Henderson     if (arg2 == 0) {
1767951c6300SRichard Henderson         tcg_gen_mov_i64(ret, arg1);
1768951c6300SRichard Henderson     } else {
1769951c6300SRichard Henderson         tcg_gen_rotli_i64(ret, arg1, 64 - arg2);
1770951c6300SRichard Henderson     }
1771951c6300SRichard Henderson }
1772951c6300SRichard Henderson 
1773951c6300SRichard Henderson void tcg_gen_deposit_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2,
1774951c6300SRichard Henderson                          unsigned int ofs, unsigned int len)
1775951c6300SRichard Henderson {
1776951c6300SRichard Henderson     uint64_t mask;
1777951c6300SRichard Henderson     TCGv_i64 t1;
1778951c6300SRichard Henderson 
1779951c6300SRichard Henderson     tcg_debug_assert(ofs < 64);
17800d0d309dSRichard Henderson     tcg_debug_assert(len > 0);
1781951c6300SRichard Henderson     tcg_debug_assert(len <= 64);
1782951c6300SRichard Henderson     tcg_debug_assert(ofs + len <= 64);
1783951c6300SRichard Henderson 
17840d0d309dSRichard Henderson     if (len == 64) {
1785951c6300SRichard Henderson         tcg_gen_mov_i64(ret, arg2);
1786951c6300SRichard Henderson         return;
1787951c6300SRichard Henderson     }
1788951c6300SRichard Henderson     if (TCG_TARGET_HAS_deposit_i64 && TCG_TARGET_deposit_i64_valid(ofs, len)) {
1789951c6300SRichard Henderson         tcg_gen_op5ii_i64(INDEX_op_deposit_i64, ret, arg1, arg2, ofs, len);
1790951c6300SRichard Henderson         return;
1791951c6300SRichard Henderson     }
1792951c6300SRichard Henderson 
17933a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
1794951c6300SRichard Henderson         if (ofs >= 32) {
1795951c6300SRichard Henderson             tcg_gen_deposit_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1),
1796951c6300SRichard Henderson                                 TCGV_LOW(arg2), ofs - 32, len);
1797951c6300SRichard Henderson             tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg1));
1798951c6300SRichard Henderson             return;
1799951c6300SRichard Henderson         }
1800951c6300SRichard Henderson         if (ofs + len <= 32) {
1801951c6300SRichard Henderson             tcg_gen_deposit_i32(TCGV_LOW(ret), TCGV_LOW(arg1),
1802951c6300SRichard Henderson                                 TCGV_LOW(arg2), ofs, len);
1803951c6300SRichard Henderson             tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1));
1804951c6300SRichard Henderson             return;
1805951c6300SRichard Henderson         }
18063a13c3f3SRichard Henderson     }
1807951c6300SRichard Henderson 
1808951c6300SRichard Henderson     mask = (1ull << len) - 1;
1809951c6300SRichard Henderson     t1 = tcg_temp_new_i64();
1810951c6300SRichard Henderson 
1811951c6300SRichard Henderson     if (ofs + len < 64) {
1812951c6300SRichard Henderson         tcg_gen_andi_i64(t1, arg2, mask);
1813951c6300SRichard Henderson         tcg_gen_shli_i64(t1, t1, ofs);
1814951c6300SRichard Henderson     } else {
1815951c6300SRichard Henderson         tcg_gen_shli_i64(t1, arg2, ofs);
1816951c6300SRichard Henderson     }
1817951c6300SRichard Henderson     tcg_gen_andi_i64(ret, arg1, ~(mask << ofs));
1818951c6300SRichard Henderson     tcg_gen_or_i64(ret, ret, t1);
1819951c6300SRichard Henderson 
1820951c6300SRichard Henderson     tcg_temp_free_i64(t1);
1821951c6300SRichard Henderson }
1822951c6300SRichard Henderson 
1823*07cc68d5SRichard Henderson void tcg_gen_deposit_z_i64(TCGv_i64 ret, TCGv_i64 arg,
1824*07cc68d5SRichard Henderson                            unsigned int ofs, unsigned int len)
1825*07cc68d5SRichard Henderson {
1826*07cc68d5SRichard Henderson     tcg_debug_assert(ofs < 64);
1827*07cc68d5SRichard Henderson     tcg_debug_assert(len > 0);
1828*07cc68d5SRichard Henderson     tcg_debug_assert(len <= 64);
1829*07cc68d5SRichard Henderson     tcg_debug_assert(ofs + len <= 64);
1830*07cc68d5SRichard Henderson 
1831*07cc68d5SRichard Henderson     if (ofs + len == 64) {
1832*07cc68d5SRichard Henderson         tcg_gen_shli_i64(ret, arg, ofs);
1833*07cc68d5SRichard Henderson     } else if (ofs == 0) {
1834*07cc68d5SRichard Henderson         tcg_gen_andi_i64(ret, arg, (1ull << len) - 1);
1835*07cc68d5SRichard Henderson     } else if (TCG_TARGET_HAS_deposit_i64
1836*07cc68d5SRichard Henderson                && TCG_TARGET_deposit_i64_valid(ofs, len)) {
1837*07cc68d5SRichard Henderson         TCGv_i64 zero = tcg_const_i64(0);
1838*07cc68d5SRichard Henderson         tcg_gen_op5ii_i64(INDEX_op_deposit_i64, ret, zero, arg, ofs, len);
1839*07cc68d5SRichard Henderson         tcg_temp_free_i64(zero);
1840*07cc68d5SRichard Henderson     } else {
1841*07cc68d5SRichard Henderson         if (TCG_TARGET_REG_BITS == 32) {
1842*07cc68d5SRichard Henderson             if (ofs >= 32) {
1843*07cc68d5SRichard Henderson                 tcg_gen_deposit_z_i32(TCGV_HIGH(ret), TCGV_LOW(arg),
1844*07cc68d5SRichard Henderson                                       ofs - 32, len);
1845*07cc68d5SRichard Henderson                 tcg_gen_movi_i32(TCGV_LOW(ret), 0);
1846*07cc68d5SRichard Henderson                 return;
1847*07cc68d5SRichard Henderson             }
1848*07cc68d5SRichard Henderson             if (ofs + len <= 32) {
1849*07cc68d5SRichard Henderson                 tcg_gen_deposit_z_i32(TCGV_LOW(ret), TCGV_LOW(arg), ofs, len);
1850*07cc68d5SRichard Henderson                 tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
1851*07cc68d5SRichard Henderson                 return;
1852*07cc68d5SRichard Henderson             }
1853*07cc68d5SRichard Henderson         }
1854*07cc68d5SRichard Henderson         /* To help two-operand hosts we prefer to zero-extend first,
1855*07cc68d5SRichard Henderson            which allows ARG to stay live.  */
1856*07cc68d5SRichard Henderson         switch (len) {
1857*07cc68d5SRichard Henderson         case 32:
1858*07cc68d5SRichard Henderson             if (TCG_TARGET_HAS_ext32u_i64) {
1859*07cc68d5SRichard Henderson                 tcg_gen_ext32u_i64(ret, arg);
1860*07cc68d5SRichard Henderson                 tcg_gen_shli_i64(ret, ret, ofs);
1861*07cc68d5SRichard Henderson                 return;
1862*07cc68d5SRichard Henderson             }
1863*07cc68d5SRichard Henderson             break;
1864*07cc68d5SRichard Henderson         case 16:
1865*07cc68d5SRichard Henderson             if (TCG_TARGET_HAS_ext16u_i64) {
1866*07cc68d5SRichard Henderson                 tcg_gen_ext16u_i64(ret, arg);
1867*07cc68d5SRichard Henderson                 tcg_gen_shli_i64(ret, ret, ofs);
1868*07cc68d5SRichard Henderson                 return;
1869*07cc68d5SRichard Henderson             }
1870*07cc68d5SRichard Henderson             break;
1871*07cc68d5SRichard Henderson         case 8:
1872*07cc68d5SRichard Henderson             if (TCG_TARGET_HAS_ext8u_i64) {
1873*07cc68d5SRichard Henderson                 tcg_gen_ext8u_i64(ret, arg);
1874*07cc68d5SRichard Henderson                 tcg_gen_shli_i64(ret, ret, ofs);
1875*07cc68d5SRichard Henderson                 return;
1876*07cc68d5SRichard Henderson             }
1877*07cc68d5SRichard Henderson             break;
1878*07cc68d5SRichard Henderson         }
1879*07cc68d5SRichard Henderson         /* Otherwise prefer zero-extension over AND for code size.  */
1880*07cc68d5SRichard Henderson         switch (ofs + len) {
1881*07cc68d5SRichard Henderson         case 32:
1882*07cc68d5SRichard Henderson             if (TCG_TARGET_HAS_ext32u_i64) {
1883*07cc68d5SRichard Henderson                 tcg_gen_shli_i64(ret, arg, ofs);
1884*07cc68d5SRichard Henderson                 tcg_gen_ext32u_i64(ret, ret);
1885*07cc68d5SRichard Henderson                 return;
1886*07cc68d5SRichard Henderson             }
1887*07cc68d5SRichard Henderson             break;
1888*07cc68d5SRichard Henderson         case 16:
1889*07cc68d5SRichard Henderson             if (TCG_TARGET_HAS_ext16u_i64) {
1890*07cc68d5SRichard Henderson                 tcg_gen_shli_i64(ret, arg, ofs);
1891*07cc68d5SRichard Henderson                 tcg_gen_ext16u_i64(ret, ret);
1892*07cc68d5SRichard Henderson                 return;
1893*07cc68d5SRichard Henderson             }
1894*07cc68d5SRichard Henderson             break;
1895*07cc68d5SRichard Henderson         case 8:
1896*07cc68d5SRichard Henderson             if (TCG_TARGET_HAS_ext8u_i64) {
1897*07cc68d5SRichard Henderson                 tcg_gen_shli_i64(ret, arg, ofs);
1898*07cc68d5SRichard Henderson                 tcg_gen_ext8u_i64(ret, ret);
1899*07cc68d5SRichard Henderson                 return;
1900*07cc68d5SRichard Henderson             }
1901*07cc68d5SRichard Henderson             break;
1902*07cc68d5SRichard Henderson         }
1903*07cc68d5SRichard Henderson         tcg_gen_andi_i64(ret, arg, (1ull << len) - 1);
1904*07cc68d5SRichard Henderson         tcg_gen_shli_i64(ret, ret, ofs);
1905*07cc68d5SRichard Henderson     }
1906*07cc68d5SRichard Henderson }
1907*07cc68d5SRichard Henderson 
19087ec8bab3SRichard Henderson void tcg_gen_extract_i64(TCGv_i64 ret, TCGv_i64 arg,
19097ec8bab3SRichard Henderson                          unsigned int ofs, unsigned int len)
19107ec8bab3SRichard Henderson {
19117ec8bab3SRichard Henderson     tcg_debug_assert(ofs < 64);
19127ec8bab3SRichard Henderson     tcg_debug_assert(len > 0);
19137ec8bab3SRichard Henderson     tcg_debug_assert(len <= 64);
19147ec8bab3SRichard Henderson     tcg_debug_assert(ofs + len <= 64);
19157ec8bab3SRichard Henderson 
19167ec8bab3SRichard Henderson     /* Canonicalize certain special cases, even if extract is supported.  */
19177ec8bab3SRichard Henderson     if (ofs + len == 64) {
19187ec8bab3SRichard Henderson         tcg_gen_shri_i64(ret, arg, 64 - len);
19197ec8bab3SRichard Henderson         return;
19207ec8bab3SRichard Henderson     }
19217ec8bab3SRichard Henderson     if (ofs == 0) {
19227ec8bab3SRichard Henderson         tcg_gen_andi_i64(ret, arg, (1ull << len) - 1);
19237ec8bab3SRichard Henderson         return;
19247ec8bab3SRichard Henderson     }
19257ec8bab3SRichard Henderson 
19267ec8bab3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
19277ec8bab3SRichard Henderson         /* Look for a 32-bit extract within one of the two words.  */
19287ec8bab3SRichard Henderson         if (ofs >= 32) {
19297ec8bab3SRichard Henderson             tcg_gen_extract_i32(TCGV_LOW(ret), TCGV_HIGH(arg), ofs - 32, len);
19307ec8bab3SRichard Henderson             tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
19317ec8bab3SRichard Henderson             return;
19327ec8bab3SRichard Henderson         }
19337ec8bab3SRichard Henderson         if (ofs + len <= 32) {
19347ec8bab3SRichard Henderson             tcg_gen_extract_i32(TCGV_LOW(ret), TCGV_LOW(arg), ofs, len);
19357ec8bab3SRichard Henderson             tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
19367ec8bab3SRichard Henderson             return;
19377ec8bab3SRichard Henderson         }
19387ec8bab3SRichard Henderson         /* The field is split across two words.  One double-word
19397ec8bab3SRichard Henderson            shift is better than two double-word shifts.  */
19407ec8bab3SRichard Henderson         goto do_shift_and;
19417ec8bab3SRichard Henderson     }
19427ec8bab3SRichard Henderson 
19437ec8bab3SRichard Henderson     if (TCG_TARGET_HAS_extract_i64
19447ec8bab3SRichard Henderson         && TCG_TARGET_extract_i64_valid(ofs, len)) {
19457ec8bab3SRichard Henderson         tcg_gen_op4ii_i64(INDEX_op_extract_i64, ret, arg, ofs, len);
19467ec8bab3SRichard Henderson         return;
19477ec8bab3SRichard Henderson     }
19487ec8bab3SRichard Henderson 
19497ec8bab3SRichard Henderson     /* Assume that zero-extension, if available, is cheaper than a shift.  */
19507ec8bab3SRichard Henderson     switch (ofs + len) {
19517ec8bab3SRichard Henderson     case 32:
19527ec8bab3SRichard Henderson         if (TCG_TARGET_HAS_ext32u_i64) {
19537ec8bab3SRichard Henderson             tcg_gen_ext32u_i64(ret, arg);
19547ec8bab3SRichard Henderson             tcg_gen_shri_i64(ret, ret, ofs);
19557ec8bab3SRichard Henderson             return;
19567ec8bab3SRichard Henderson         }
19577ec8bab3SRichard Henderson         break;
19587ec8bab3SRichard Henderson     case 16:
19597ec8bab3SRichard Henderson         if (TCG_TARGET_HAS_ext16u_i64) {
19607ec8bab3SRichard Henderson             tcg_gen_ext16u_i64(ret, arg);
19617ec8bab3SRichard Henderson             tcg_gen_shri_i64(ret, ret, ofs);
19627ec8bab3SRichard Henderson             return;
19637ec8bab3SRichard Henderson         }
19647ec8bab3SRichard Henderson         break;
19657ec8bab3SRichard Henderson     case 8:
19667ec8bab3SRichard Henderson         if (TCG_TARGET_HAS_ext8u_i64) {
19677ec8bab3SRichard Henderson             tcg_gen_ext8u_i64(ret, arg);
19687ec8bab3SRichard Henderson             tcg_gen_shri_i64(ret, ret, ofs);
19697ec8bab3SRichard Henderson             return;
19707ec8bab3SRichard Henderson         }
19717ec8bab3SRichard Henderson         break;
19727ec8bab3SRichard Henderson     }
19737ec8bab3SRichard Henderson 
19747ec8bab3SRichard Henderson     /* ??? Ideally we'd know what values are available for immediate AND.
19757ec8bab3SRichard Henderson        Assume that 8 bits are available, plus the special cases of 16 and 32,
19767ec8bab3SRichard Henderson        so that we get ext8u, ext16u, and ext32u.  */
19777ec8bab3SRichard Henderson     switch (len) {
19787ec8bab3SRichard Henderson     case 1 ... 8: case 16: case 32:
19797ec8bab3SRichard Henderson     do_shift_and:
19807ec8bab3SRichard Henderson         tcg_gen_shri_i64(ret, arg, ofs);
19817ec8bab3SRichard Henderson         tcg_gen_andi_i64(ret, ret, (1ull << len) - 1);
19827ec8bab3SRichard Henderson         break;
19837ec8bab3SRichard Henderson     default:
19847ec8bab3SRichard Henderson         tcg_gen_shli_i64(ret, arg, 64 - len - ofs);
19857ec8bab3SRichard Henderson         tcg_gen_shri_i64(ret, ret, 64 - len);
19867ec8bab3SRichard Henderson         break;
19877ec8bab3SRichard Henderson     }
19887ec8bab3SRichard Henderson }
19897ec8bab3SRichard Henderson 
19907ec8bab3SRichard Henderson void tcg_gen_sextract_i64(TCGv_i64 ret, TCGv_i64 arg,
19917ec8bab3SRichard Henderson                           unsigned int ofs, unsigned int len)
19927ec8bab3SRichard Henderson {
19937ec8bab3SRichard Henderson     tcg_debug_assert(ofs < 64);
19947ec8bab3SRichard Henderson     tcg_debug_assert(len > 0);
19957ec8bab3SRichard Henderson     tcg_debug_assert(len <= 64);
19967ec8bab3SRichard Henderson     tcg_debug_assert(ofs + len <= 64);
19977ec8bab3SRichard Henderson 
19987ec8bab3SRichard Henderson     /* Canonicalize certain special cases, even if sextract is supported.  */
19997ec8bab3SRichard Henderson     if (ofs + len == 64) {
20007ec8bab3SRichard Henderson         tcg_gen_sari_i64(ret, arg, 64 - len);
20017ec8bab3SRichard Henderson         return;
20027ec8bab3SRichard Henderson     }
20037ec8bab3SRichard Henderson     if (ofs == 0) {
20047ec8bab3SRichard Henderson         switch (len) {
20057ec8bab3SRichard Henderson         case 32:
20067ec8bab3SRichard Henderson             tcg_gen_ext32s_i64(ret, arg);
20077ec8bab3SRichard Henderson             return;
20087ec8bab3SRichard Henderson         case 16:
20097ec8bab3SRichard Henderson             tcg_gen_ext16s_i64(ret, arg);
20107ec8bab3SRichard Henderson             return;
20117ec8bab3SRichard Henderson         case 8:
20127ec8bab3SRichard Henderson             tcg_gen_ext8s_i64(ret, arg);
20137ec8bab3SRichard Henderson             return;
20147ec8bab3SRichard Henderson         }
20157ec8bab3SRichard Henderson     }
20167ec8bab3SRichard Henderson 
20177ec8bab3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
20187ec8bab3SRichard Henderson         /* Look for a 32-bit extract within one of the two words.  */
20197ec8bab3SRichard Henderson         if (ofs >= 32) {
20207ec8bab3SRichard Henderson             tcg_gen_sextract_i32(TCGV_LOW(ret), TCGV_HIGH(arg), ofs - 32, len);
20217ec8bab3SRichard Henderson         } else if (ofs + len <= 32) {
20227ec8bab3SRichard Henderson             tcg_gen_sextract_i32(TCGV_LOW(ret), TCGV_LOW(arg), ofs, len);
20237ec8bab3SRichard Henderson         } else if (ofs == 0) {
20247ec8bab3SRichard Henderson             tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg));
20257ec8bab3SRichard Henderson             tcg_gen_sextract_i32(TCGV_HIGH(ret), TCGV_HIGH(arg), 0, len - 32);
20267ec8bab3SRichard Henderson             return;
20277ec8bab3SRichard Henderson         } else if (len > 32) {
20287ec8bab3SRichard Henderson             TCGv_i32 t = tcg_temp_new_i32();
20297ec8bab3SRichard Henderson             /* Extract the bits for the high word normally.  */
20307ec8bab3SRichard Henderson             tcg_gen_sextract_i32(t, TCGV_HIGH(arg), ofs + 32, len - 32);
20317ec8bab3SRichard Henderson             /* Shift the field down for the low part.  */
20327ec8bab3SRichard Henderson             tcg_gen_shri_i64(ret, arg, ofs);
20337ec8bab3SRichard Henderson             /* Overwrite the shift into the high part.  */
20347ec8bab3SRichard Henderson             tcg_gen_mov_i32(TCGV_HIGH(ret), t);
20357ec8bab3SRichard Henderson             tcg_temp_free_i32(t);
20367ec8bab3SRichard Henderson             return;
20377ec8bab3SRichard Henderson         } else {
20387ec8bab3SRichard Henderson             /* Shift the field down for the low part, such that the
20397ec8bab3SRichard Henderson                field sits at the MSB.  */
20407ec8bab3SRichard Henderson             tcg_gen_shri_i64(ret, arg, ofs + len - 32);
20417ec8bab3SRichard Henderson             /* Shift the field down from the MSB, sign extending.  */
20427ec8bab3SRichard Henderson             tcg_gen_sari_i32(TCGV_LOW(ret), TCGV_LOW(ret), 32 - len);
20437ec8bab3SRichard Henderson         }
20447ec8bab3SRichard Henderson         /* Sign-extend the field from 32 bits.  */
20457ec8bab3SRichard Henderson         tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31);
20467ec8bab3SRichard Henderson         return;
20477ec8bab3SRichard Henderson     }
20487ec8bab3SRichard Henderson 
20497ec8bab3SRichard Henderson     if (TCG_TARGET_HAS_sextract_i64
20507ec8bab3SRichard Henderson         && TCG_TARGET_extract_i64_valid(ofs, len)) {
20517ec8bab3SRichard Henderson         tcg_gen_op4ii_i64(INDEX_op_sextract_i64, ret, arg, ofs, len);
20527ec8bab3SRichard Henderson         return;
20537ec8bab3SRichard Henderson     }
20547ec8bab3SRichard Henderson 
20557ec8bab3SRichard Henderson     /* Assume that sign-extension, if available, is cheaper than a shift.  */
20567ec8bab3SRichard Henderson     switch (ofs + len) {
20577ec8bab3SRichard Henderson     case 32:
20587ec8bab3SRichard Henderson         if (TCG_TARGET_HAS_ext32s_i64) {
20597ec8bab3SRichard Henderson             tcg_gen_ext32s_i64(ret, arg);
20607ec8bab3SRichard Henderson             tcg_gen_sari_i64(ret, ret, ofs);
20617ec8bab3SRichard Henderson             return;
20627ec8bab3SRichard Henderson         }
20637ec8bab3SRichard Henderson         break;
20647ec8bab3SRichard Henderson     case 16:
20657ec8bab3SRichard Henderson         if (TCG_TARGET_HAS_ext16s_i64) {
20667ec8bab3SRichard Henderson             tcg_gen_ext16s_i64(ret, arg);
20677ec8bab3SRichard Henderson             tcg_gen_sari_i64(ret, ret, ofs);
20687ec8bab3SRichard Henderson             return;
20697ec8bab3SRichard Henderson         }
20707ec8bab3SRichard Henderson         break;
20717ec8bab3SRichard Henderson     case 8:
20727ec8bab3SRichard Henderson         if (TCG_TARGET_HAS_ext8s_i64) {
20737ec8bab3SRichard Henderson             tcg_gen_ext8s_i64(ret, arg);
20747ec8bab3SRichard Henderson             tcg_gen_sari_i64(ret, ret, ofs);
20757ec8bab3SRichard Henderson             return;
20767ec8bab3SRichard Henderson         }
20777ec8bab3SRichard Henderson         break;
20787ec8bab3SRichard Henderson     }
20797ec8bab3SRichard Henderson     switch (len) {
20807ec8bab3SRichard Henderson     case 32:
20817ec8bab3SRichard Henderson         if (TCG_TARGET_HAS_ext32s_i64) {
20827ec8bab3SRichard Henderson             tcg_gen_shri_i64(ret, arg, ofs);
20837ec8bab3SRichard Henderson             tcg_gen_ext32s_i64(ret, ret);
20847ec8bab3SRichard Henderson             return;
20857ec8bab3SRichard Henderson         }
20867ec8bab3SRichard Henderson         break;
20877ec8bab3SRichard Henderson     case 16:
20887ec8bab3SRichard Henderson         if (TCG_TARGET_HAS_ext16s_i64) {
20897ec8bab3SRichard Henderson             tcg_gen_shri_i64(ret, arg, ofs);
20907ec8bab3SRichard Henderson             tcg_gen_ext16s_i64(ret, ret);
20917ec8bab3SRichard Henderson             return;
20927ec8bab3SRichard Henderson         }
20937ec8bab3SRichard Henderson         break;
20947ec8bab3SRichard Henderson     case 8:
20957ec8bab3SRichard Henderson         if (TCG_TARGET_HAS_ext8s_i64) {
20967ec8bab3SRichard Henderson             tcg_gen_shri_i64(ret, arg, ofs);
20977ec8bab3SRichard Henderson             tcg_gen_ext8s_i64(ret, ret);
20987ec8bab3SRichard Henderson             return;
20997ec8bab3SRichard Henderson         }
21007ec8bab3SRichard Henderson         break;
21017ec8bab3SRichard Henderson     }
21027ec8bab3SRichard Henderson     tcg_gen_shli_i64(ret, arg, 64 - len - ofs);
21037ec8bab3SRichard Henderson     tcg_gen_sari_i64(ret, ret, 64 - len);
21047ec8bab3SRichard Henderson }
21057ec8bab3SRichard Henderson 
2106951c6300SRichard Henderson void tcg_gen_movcond_i64(TCGCond cond, TCGv_i64 ret, TCGv_i64 c1,
2107951c6300SRichard Henderson                          TCGv_i64 c2, TCGv_i64 v1, TCGv_i64 v2)
2108951c6300SRichard Henderson {
210937ed3bf1SRichard Henderson     if (cond == TCG_COND_ALWAYS) {
211037ed3bf1SRichard Henderson         tcg_gen_mov_i64(ret, v1);
211137ed3bf1SRichard Henderson     } else if (cond == TCG_COND_NEVER) {
211237ed3bf1SRichard Henderson         tcg_gen_mov_i64(ret, v2);
211337ed3bf1SRichard Henderson     } else if (TCG_TARGET_REG_BITS == 32) {
2114951c6300SRichard Henderson         TCGv_i32 t0 = tcg_temp_new_i32();
2115951c6300SRichard Henderson         TCGv_i32 t1 = tcg_temp_new_i32();
2116951c6300SRichard Henderson         tcg_gen_op6i_i32(INDEX_op_setcond2_i32, t0,
2117951c6300SRichard Henderson                          TCGV_LOW(c1), TCGV_HIGH(c1),
2118951c6300SRichard Henderson                          TCGV_LOW(c2), TCGV_HIGH(c2), cond);
2119951c6300SRichard Henderson 
2120951c6300SRichard Henderson         if (TCG_TARGET_HAS_movcond_i32) {
2121951c6300SRichard Henderson             tcg_gen_movi_i32(t1, 0);
2122951c6300SRichard Henderson             tcg_gen_movcond_i32(TCG_COND_NE, TCGV_LOW(ret), t0, t1,
2123951c6300SRichard Henderson                                 TCGV_LOW(v1), TCGV_LOW(v2));
2124951c6300SRichard Henderson             tcg_gen_movcond_i32(TCG_COND_NE, TCGV_HIGH(ret), t0, t1,
2125951c6300SRichard Henderson                                 TCGV_HIGH(v1), TCGV_HIGH(v2));
2126951c6300SRichard Henderson         } else {
2127951c6300SRichard Henderson             tcg_gen_neg_i32(t0, t0);
2128951c6300SRichard Henderson 
2129951c6300SRichard Henderson             tcg_gen_and_i32(t1, TCGV_LOW(v1), t0);
2130951c6300SRichard Henderson             tcg_gen_andc_i32(TCGV_LOW(ret), TCGV_LOW(v2), t0);
2131951c6300SRichard Henderson             tcg_gen_or_i32(TCGV_LOW(ret), TCGV_LOW(ret), t1);
2132951c6300SRichard Henderson 
2133951c6300SRichard Henderson             tcg_gen_and_i32(t1, TCGV_HIGH(v1), t0);
2134951c6300SRichard Henderson             tcg_gen_andc_i32(TCGV_HIGH(ret), TCGV_HIGH(v2), t0);
2135951c6300SRichard Henderson             tcg_gen_or_i32(TCGV_HIGH(ret), TCGV_HIGH(ret), t1);
2136951c6300SRichard Henderson         }
2137951c6300SRichard Henderson         tcg_temp_free_i32(t0);
2138951c6300SRichard Henderson         tcg_temp_free_i32(t1);
21393a13c3f3SRichard Henderson     } else if (TCG_TARGET_HAS_movcond_i64) {
2140951c6300SRichard Henderson         tcg_gen_op6i_i64(INDEX_op_movcond_i64, ret, c1, c2, v1, v2, cond);
2141951c6300SRichard Henderson     } else {
2142951c6300SRichard Henderson         TCGv_i64 t0 = tcg_temp_new_i64();
2143951c6300SRichard Henderson         TCGv_i64 t1 = tcg_temp_new_i64();
2144951c6300SRichard Henderson         tcg_gen_setcond_i64(cond, t0, c1, c2);
2145951c6300SRichard Henderson         tcg_gen_neg_i64(t0, t0);
2146951c6300SRichard Henderson         tcg_gen_and_i64(t1, v1, t0);
2147951c6300SRichard Henderson         tcg_gen_andc_i64(ret, v2, t0);
2148951c6300SRichard Henderson         tcg_gen_or_i64(ret, ret, t1);
2149951c6300SRichard Henderson         tcg_temp_free_i64(t0);
2150951c6300SRichard Henderson         tcg_temp_free_i64(t1);
2151951c6300SRichard Henderson     }
2152951c6300SRichard Henderson }
2153951c6300SRichard Henderson 
2154951c6300SRichard Henderson void tcg_gen_add2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 al,
2155951c6300SRichard Henderson                       TCGv_i64 ah, TCGv_i64 bl, TCGv_i64 bh)
2156951c6300SRichard Henderson {
2157951c6300SRichard Henderson     if (TCG_TARGET_HAS_add2_i64) {
2158951c6300SRichard Henderson         tcg_gen_op6_i64(INDEX_op_add2_i64, rl, rh, al, ah, bl, bh);
2159951c6300SRichard Henderson     } else {
2160951c6300SRichard Henderson         TCGv_i64 t0 = tcg_temp_new_i64();
2161951c6300SRichard Henderson         TCGv_i64 t1 = tcg_temp_new_i64();
2162951c6300SRichard Henderson         tcg_gen_add_i64(t0, al, bl);
2163951c6300SRichard Henderson         tcg_gen_setcond_i64(TCG_COND_LTU, t1, t0, al);
2164951c6300SRichard Henderson         tcg_gen_add_i64(rh, ah, bh);
2165951c6300SRichard Henderson         tcg_gen_add_i64(rh, rh, t1);
2166951c6300SRichard Henderson         tcg_gen_mov_i64(rl, t0);
2167951c6300SRichard Henderson         tcg_temp_free_i64(t0);
2168951c6300SRichard Henderson         tcg_temp_free_i64(t1);
2169951c6300SRichard Henderson     }
2170951c6300SRichard Henderson }
2171951c6300SRichard Henderson 
2172951c6300SRichard Henderson void tcg_gen_sub2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 al,
2173951c6300SRichard Henderson                       TCGv_i64 ah, TCGv_i64 bl, TCGv_i64 bh)
2174951c6300SRichard Henderson {
2175951c6300SRichard Henderson     if (TCG_TARGET_HAS_sub2_i64) {
2176951c6300SRichard Henderson         tcg_gen_op6_i64(INDEX_op_sub2_i64, rl, rh, al, ah, bl, bh);
2177951c6300SRichard Henderson     } else {
2178951c6300SRichard Henderson         TCGv_i64 t0 = tcg_temp_new_i64();
2179951c6300SRichard Henderson         TCGv_i64 t1 = tcg_temp_new_i64();
2180951c6300SRichard Henderson         tcg_gen_sub_i64(t0, al, bl);
2181951c6300SRichard Henderson         tcg_gen_setcond_i64(TCG_COND_LTU, t1, al, bl);
2182951c6300SRichard Henderson         tcg_gen_sub_i64(rh, ah, bh);
2183951c6300SRichard Henderson         tcg_gen_sub_i64(rh, rh, t1);
2184951c6300SRichard Henderson         tcg_gen_mov_i64(rl, t0);
2185951c6300SRichard Henderson         tcg_temp_free_i64(t0);
2186951c6300SRichard Henderson         tcg_temp_free_i64(t1);
2187951c6300SRichard Henderson     }
2188951c6300SRichard Henderson }
2189951c6300SRichard Henderson 
2190951c6300SRichard Henderson void tcg_gen_mulu2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 arg1, TCGv_i64 arg2)
2191951c6300SRichard Henderson {
2192951c6300SRichard Henderson     if (TCG_TARGET_HAS_mulu2_i64) {
2193951c6300SRichard Henderson         tcg_gen_op4_i64(INDEX_op_mulu2_i64, rl, rh, arg1, arg2);
2194951c6300SRichard Henderson     } else if (TCG_TARGET_HAS_muluh_i64) {
2195951c6300SRichard Henderson         TCGv_i64 t = tcg_temp_new_i64();
2196951c6300SRichard Henderson         tcg_gen_op3_i64(INDEX_op_mul_i64, t, arg1, arg2);
2197951c6300SRichard Henderson         tcg_gen_op3_i64(INDEX_op_muluh_i64, rh, arg1, arg2);
2198951c6300SRichard Henderson         tcg_gen_mov_i64(rl, t);
2199951c6300SRichard Henderson         tcg_temp_free_i64(t);
2200951c6300SRichard Henderson     } else {
2201951c6300SRichard Henderson         TCGv_i64 t0 = tcg_temp_new_i64();
2202951c6300SRichard Henderson         tcg_gen_mul_i64(t0, arg1, arg2);
2203951c6300SRichard Henderson         gen_helper_muluh_i64(rh, arg1, arg2);
2204951c6300SRichard Henderson         tcg_gen_mov_i64(rl, t0);
2205951c6300SRichard Henderson         tcg_temp_free_i64(t0);
2206951c6300SRichard Henderson     }
2207951c6300SRichard Henderson }
2208951c6300SRichard Henderson 
2209951c6300SRichard Henderson void tcg_gen_muls2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 arg1, TCGv_i64 arg2)
2210951c6300SRichard Henderson {
2211951c6300SRichard Henderson     if (TCG_TARGET_HAS_muls2_i64) {
2212951c6300SRichard Henderson         tcg_gen_op4_i64(INDEX_op_muls2_i64, rl, rh, arg1, arg2);
2213951c6300SRichard Henderson     } else if (TCG_TARGET_HAS_mulsh_i64) {
2214951c6300SRichard Henderson         TCGv_i64 t = tcg_temp_new_i64();
2215951c6300SRichard Henderson         tcg_gen_op3_i64(INDEX_op_mul_i64, t, arg1, arg2);
2216951c6300SRichard Henderson         tcg_gen_op3_i64(INDEX_op_mulsh_i64, rh, arg1, arg2);
2217951c6300SRichard Henderson         tcg_gen_mov_i64(rl, t);
2218951c6300SRichard Henderson         tcg_temp_free_i64(t);
2219951c6300SRichard Henderson     } else if (TCG_TARGET_HAS_mulu2_i64 || TCG_TARGET_HAS_muluh_i64) {
2220951c6300SRichard Henderson         TCGv_i64 t0 = tcg_temp_new_i64();
2221951c6300SRichard Henderson         TCGv_i64 t1 = tcg_temp_new_i64();
2222951c6300SRichard Henderson         TCGv_i64 t2 = tcg_temp_new_i64();
2223951c6300SRichard Henderson         TCGv_i64 t3 = tcg_temp_new_i64();
2224951c6300SRichard Henderson         tcg_gen_mulu2_i64(t0, t1, arg1, arg2);
2225951c6300SRichard Henderson         /* Adjust for negative inputs.  */
2226951c6300SRichard Henderson         tcg_gen_sari_i64(t2, arg1, 63);
2227951c6300SRichard Henderson         tcg_gen_sari_i64(t3, arg2, 63);
2228951c6300SRichard Henderson         tcg_gen_and_i64(t2, t2, arg2);
2229951c6300SRichard Henderson         tcg_gen_and_i64(t3, t3, arg1);
2230951c6300SRichard Henderson         tcg_gen_sub_i64(rh, t1, t2);
2231951c6300SRichard Henderson         tcg_gen_sub_i64(rh, rh, t3);
2232951c6300SRichard Henderson         tcg_gen_mov_i64(rl, t0);
2233951c6300SRichard Henderson         tcg_temp_free_i64(t0);
2234951c6300SRichard Henderson         tcg_temp_free_i64(t1);
2235951c6300SRichard Henderson         tcg_temp_free_i64(t2);
2236951c6300SRichard Henderson         tcg_temp_free_i64(t3);
2237951c6300SRichard Henderson     } else {
2238951c6300SRichard Henderson         TCGv_i64 t0 = tcg_temp_new_i64();
2239951c6300SRichard Henderson         tcg_gen_mul_i64(t0, arg1, arg2);
2240951c6300SRichard Henderson         gen_helper_mulsh_i64(rh, arg1, arg2);
2241951c6300SRichard Henderson         tcg_gen_mov_i64(rl, t0);
2242951c6300SRichard Henderson         tcg_temp_free_i64(t0);
2243951c6300SRichard Henderson     }
2244951c6300SRichard Henderson }
2245951c6300SRichard Henderson 
22465087abfbSRichard Henderson void tcg_gen_mulsu2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 arg1, TCGv_i64 arg2)
22475087abfbSRichard Henderson {
22485087abfbSRichard Henderson     TCGv_i64 t0 = tcg_temp_new_i64();
22495087abfbSRichard Henderson     TCGv_i64 t1 = tcg_temp_new_i64();
22505087abfbSRichard Henderson     TCGv_i64 t2 = tcg_temp_new_i64();
22515087abfbSRichard Henderson     tcg_gen_mulu2_i64(t0, t1, arg1, arg2);
22525087abfbSRichard Henderson     /* Adjust for negative input for the signed arg1.  */
22535087abfbSRichard Henderson     tcg_gen_sari_i64(t2, arg1, 63);
22545087abfbSRichard Henderson     tcg_gen_and_i64(t2, t2, arg2);
22555087abfbSRichard Henderson     tcg_gen_sub_i64(rh, t1, t2);
22565087abfbSRichard Henderson     tcg_gen_mov_i64(rl, t0);
22575087abfbSRichard Henderson     tcg_temp_free_i64(t0);
22585087abfbSRichard Henderson     tcg_temp_free_i64(t1);
22595087abfbSRichard Henderson     tcg_temp_free_i64(t2);
22605087abfbSRichard Henderson }
22615087abfbSRichard Henderson 
2262951c6300SRichard Henderson /* Size changing operations.  */
2263951c6300SRichard Henderson 
2264609ad705SRichard Henderson void tcg_gen_extrl_i64_i32(TCGv_i32 ret, TCGv_i64 arg)
2265951c6300SRichard Henderson {
22663a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
2267951c6300SRichard Henderson         tcg_gen_mov_i32(ret, TCGV_LOW(arg));
2268609ad705SRichard Henderson     } else if (TCG_TARGET_HAS_extrl_i64_i32) {
2269609ad705SRichard Henderson         tcg_gen_op2(&tcg_ctx, INDEX_op_extrl_i64_i32,
2270609ad705SRichard Henderson                     GET_TCGV_I32(ret), GET_TCGV_I64(arg));
2271951c6300SRichard Henderson     } else {
2272951c6300SRichard Henderson         tcg_gen_mov_i32(ret, MAKE_TCGV_I32(GET_TCGV_I64(arg)));
2273609ad705SRichard Henderson     }
2274609ad705SRichard Henderson }
2275609ad705SRichard Henderson 
2276609ad705SRichard Henderson void tcg_gen_extrh_i64_i32(TCGv_i32 ret, TCGv_i64 arg)
2277609ad705SRichard Henderson {
2278609ad705SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
2279609ad705SRichard Henderson         tcg_gen_mov_i32(ret, TCGV_HIGH(arg));
2280609ad705SRichard Henderson     } else if (TCG_TARGET_HAS_extrh_i64_i32) {
2281609ad705SRichard Henderson         tcg_gen_op2(&tcg_ctx, INDEX_op_extrh_i64_i32,
2282609ad705SRichard Henderson                     GET_TCGV_I32(ret), GET_TCGV_I64(arg));
2283951c6300SRichard Henderson     } else {
2284951c6300SRichard Henderson         TCGv_i64 t = tcg_temp_new_i64();
2285609ad705SRichard Henderson         tcg_gen_shri_i64(t, arg, 32);
2286951c6300SRichard Henderson         tcg_gen_mov_i32(ret, MAKE_TCGV_I32(GET_TCGV_I64(t)));
2287951c6300SRichard Henderson         tcg_temp_free_i64(t);
2288951c6300SRichard Henderson     }
2289951c6300SRichard Henderson }
2290951c6300SRichard Henderson 
2291951c6300SRichard Henderson void tcg_gen_extu_i32_i64(TCGv_i64 ret, TCGv_i32 arg)
2292951c6300SRichard Henderson {
22933a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
2294951c6300SRichard Henderson         tcg_gen_mov_i32(TCGV_LOW(ret), arg);
2295951c6300SRichard Henderson         tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
22963a13c3f3SRichard Henderson     } else {
22974f2331e5SAurelien Jarno         tcg_gen_op2(&tcg_ctx, INDEX_op_extu_i32_i64,
22984f2331e5SAurelien Jarno                     GET_TCGV_I64(ret), GET_TCGV_I32(arg));
22993a13c3f3SRichard Henderson     }
2300951c6300SRichard Henderson }
2301951c6300SRichard Henderson 
2302951c6300SRichard Henderson void tcg_gen_ext_i32_i64(TCGv_i64 ret, TCGv_i32 arg)
2303951c6300SRichard Henderson {
23043a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
2305951c6300SRichard Henderson         tcg_gen_mov_i32(TCGV_LOW(ret), arg);
2306951c6300SRichard Henderson         tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31);
23073a13c3f3SRichard Henderson     } else {
23084f2331e5SAurelien Jarno         tcg_gen_op2(&tcg_ctx, INDEX_op_ext_i32_i64,
23094f2331e5SAurelien Jarno                     GET_TCGV_I64(ret), GET_TCGV_I32(arg));
23103a13c3f3SRichard Henderson     }
2311951c6300SRichard Henderson }
2312951c6300SRichard Henderson 
2313951c6300SRichard Henderson void tcg_gen_concat_i32_i64(TCGv_i64 dest, TCGv_i32 low, TCGv_i32 high)
2314951c6300SRichard Henderson {
23153a13c3f3SRichard Henderson     TCGv_i64 tmp;
23163a13c3f3SRichard Henderson 
23173a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
2318951c6300SRichard Henderson         tcg_gen_mov_i32(TCGV_LOW(dest), low);
2319951c6300SRichard Henderson         tcg_gen_mov_i32(TCGV_HIGH(dest), high);
23203a13c3f3SRichard Henderson         return;
23213a13c3f3SRichard Henderson     }
23223a13c3f3SRichard Henderson 
23233a13c3f3SRichard Henderson     tmp = tcg_temp_new_i64();
2324951c6300SRichard Henderson     /* These extensions are only needed for type correctness.
2325951c6300SRichard Henderson        We may be able to do better given target specific information.  */
2326951c6300SRichard Henderson     tcg_gen_extu_i32_i64(tmp, high);
2327951c6300SRichard Henderson     tcg_gen_extu_i32_i64(dest, low);
2328951c6300SRichard Henderson     /* If deposit is available, use it.  Otherwise use the extra
2329951c6300SRichard Henderson        knowledge that we have of the zero-extensions above.  */
2330951c6300SRichard Henderson     if (TCG_TARGET_HAS_deposit_i64 && TCG_TARGET_deposit_i64_valid(32, 32)) {
2331951c6300SRichard Henderson         tcg_gen_deposit_i64(dest, dest, tmp, 32, 32);
2332951c6300SRichard Henderson     } else {
2333951c6300SRichard Henderson         tcg_gen_shli_i64(tmp, tmp, 32);
2334951c6300SRichard Henderson         tcg_gen_or_i64(dest, dest, tmp);
2335951c6300SRichard Henderson     }
2336951c6300SRichard Henderson     tcg_temp_free_i64(tmp);
2337951c6300SRichard Henderson }
2338951c6300SRichard Henderson 
2339951c6300SRichard Henderson void tcg_gen_extr_i64_i32(TCGv_i32 lo, TCGv_i32 hi, TCGv_i64 arg)
2340951c6300SRichard Henderson {
23413a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
2342951c6300SRichard Henderson         tcg_gen_mov_i32(lo, TCGV_LOW(arg));
2343951c6300SRichard Henderson         tcg_gen_mov_i32(hi, TCGV_HIGH(arg));
23443a13c3f3SRichard Henderson     } else {
2345609ad705SRichard Henderson         tcg_gen_extrl_i64_i32(lo, arg);
2346609ad705SRichard Henderson         tcg_gen_extrh_i64_i32(hi, arg);
23473a13c3f3SRichard Henderson     }
2348951c6300SRichard Henderson }
2349951c6300SRichard Henderson 
2350951c6300SRichard Henderson void tcg_gen_extr32_i64(TCGv_i64 lo, TCGv_i64 hi, TCGv_i64 arg)
2351951c6300SRichard Henderson {
2352951c6300SRichard Henderson     tcg_gen_ext32u_i64(lo, arg);
2353951c6300SRichard Henderson     tcg_gen_shri_i64(hi, arg, 32);
2354951c6300SRichard Henderson }
2355951c6300SRichard Henderson 
2356951c6300SRichard Henderson /* QEMU specific operations.  */
2357951c6300SRichard Henderson 
2358951c6300SRichard Henderson void tcg_gen_goto_tb(unsigned idx)
2359951c6300SRichard Henderson {
2360951c6300SRichard Henderson     /* We only support two chained exits.  */
2361951c6300SRichard Henderson     tcg_debug_assert(idx <= 1);
2362951c6300SRichard Henderson #ifdef CONFIG_DEBUG_TCG
2363951c6300SRichard Henderson     /* Verify that we havn't seen this numbered exit before.  */
2364951c6300SRichard Henderson     tcg_debug_assert((tcg_ctx.goto_tb_issue_mask & (1 << idx)) == 0);
2365951c6300SRichard Henderson     tcg_ctx.goto_tb_issue_mask |= 1 << idx;
2366951c6300SRichard Henderson #endif
2367951c6300SRichard Henderson     tcg_gen_op1i(INDEX_op_goto_tb, idx);
2368951c6300SRichard Henderson }
2369951c6300SRichard Henderson 
2370951c6300SRichard Henderson static inline TCGMemOp tcg_canonicalize_memop(TCGMemOp op, bool is64, bool st)
2371951c6300SRichard Henderson {
23721f00b27fSSergey Sorokin     /* Trigger the asserts within as early as possible.  */
23731f00b27fSSergey Sorokin     (void)get_alignment_bits(op);
23741f00b27fSSergey Sorokin 
2375951c6300SRichard Henderson     switch (op & MO_SIZE) {
2376951c6300SRichard Henderson     case MO_8:
2377951c6300SRichard Henderson         op &= ~MO_BSWAP;
2378951c6300SRichard Henderson         break;
2379951c6300SRichard Henderson     case MO_16:
2380951c6300SRichard Henderson         break;
2381951c6300SRichard Henderson     case MO_32:
2382951c6300SRichard Henderson         if (!is64) {
2383951c6300SRichard Henderson             op &= ~MO_SIGN;
2384951c6300SRichard Henderson         }
2385951c6300SRichard Henderson         break;
2386951c6300SRichard Henderson     case MO_64:
2387951c6300SRichard Henderson         if (!is64) {
2388951c6300SRichard Henderson             tcg_abort();
2389951c6300SRichard Henderson         }
2390951c6300SRichard Henderson         break;
2391951c6300SRichard Henderson     }
2392951c6300SRichard Henderson     if (st) {
2393951c6300SRichard Henderson         op &= ~MO_SIGN;
2394951c6300SRichard Henderson     }
2395951c6300SRichard Henderson     return op;
2396951c6300SRichard Henderson }
2397951c6300SRichard Henderson 
2398c45cb8bbSRichard Henderson static void gen_ldst_i32(TCGOpcode opc, TCGv_i32 val, TCGv addr,
2399c45cb8bbSRichard Henderson                          TCGMemOp memop, TCGArg idx)
2400951c6300SRichard Henderson {
240159227d5dSRichard Henderson     TCGMemOpIdx oi = make_memop_idx(memop, idx);
2402951c6300SRichard Henderson #if TARGET_LONG_BITS == 32
240359227d5dSRichard Henderson     tcg_gen_op3i_i32(opc, val, addr, oi);
2404951c6300SRichard Henderson #else
2405c45cb8bbSRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
240659227d5dSRichard Henderson         tcg_gen_op4i_i32(opc, val, TCGV_LOW(addr), TCGV_HIGH(addr), oi);
2407c45cb8bbSRichard Henderson     } else {
240859227d5dSRichard Henderson         tcg_gen_op3(&tcg_ctx, opc, GET_TCGV_I32(val), GET_TCGV_I64(addr), oi);
2409c45cb8bbSRichard Henderson     }
2410951c6300SRichard Henderson #endif
2411c45cb8bbSRichard Henderson }
2412c45cb8bbSRichard Henderson 
2413c45cb8bbSRichard Henderson static void gen_ldst_i64(TCGOpcode opc, TCGv_i64 val, TCGv addr,
2414c45cb8bbSRichard Henderson                          TCGMemOp memop, TCGArg idx)
2415c45cb8bbSRichard Henderson {
241659227d5dSRichard Henderson     TCGMemOpIdx oi = make_memop_idx(memop, idx);
2417c45cb8bbSRichard Henderson #if TARGET_LONG_BITS == 32
2418c45cb8bbSRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
241959227d5dSRichard Henderson         tcg_gen_op4i_i32(opc, TCGV_LOW(val), TCGV_HIGH(val), addr, oi);
2420c45cb8bbSRichard Henderson     } else {
242159227d5dSRichard Henderson         tcg_gen_op3(&tcg_ctx, opc, GET_TCGV_I64(val), GET_TCGV_I32(addr), oi);
2422c45cb8bbSRichard Henderson     }
2423c45cb8bbSRichard Henderson #else
2424c45cb8bbSRichard Henderson     if (TCG_TARGET_REG_BITS == 32) {
242559227d5dSRichard Henderson         tcg_gen_op5i_i32(opc, TCGV_LOW(val), TCGV_HIGH(val),
242659227d5dSRichard Henderson                          TCGV_LOW(addr), TCGV_HIGH(addr), oi);
2427c45cb8bbSRichard Henderson     } else {
242859227d5dSRichard Henderson         tcg_gen_op3i_i64(opc, val, addr, oi);
2429c45cb8bbSRichard Henderson     }
2430c45cb8bbSRichard Henderson #endif
2431c45cb8bbSRichard Henderson }
2432951c6300SRichard Henderson 
2433951c6300SRichard Henderson void tcg_gen_qemu_ld_i32(TCGv_i32 val, TCGv addr, TCGArg idx, TCGMemOp memop)
2434951c6300SRichard Henderson {
2435951c6300SRichard Henderson     memop = tcg_canonicalize_memop(memop, 0, 0);
2436dcdaadb6SLluís Vilanova     trace_guest_mem_before_tcg(tcg_ctx.cpu, tcg_ctx.tcg_env,
2437dcdaadb6SLluís Vilanova                                addr, trace_mem_get_info(memop, 0));
2438c45cb8bbSRichard Henderson     gen_ldst_i32(INDEX_op_qemu_ld_i32, val, addr, memop, idx);
2439951c6300SRichard Henderson }
2440951c6300SRichard Henderson 
2441951c6300SRichard Henderson void tcg_gen_qemu_st_i32(TCGv_i32 val, TCGv addr, TCGArg idx, TCGMemOp memop)
2442951c6300SRichard Henderson {
2443951c6300SRichard Henderson     memop = tcg_canonicalize_memop(memop, 0, 1);
2444dcdaadb6SLluís Vilanova     trace_guest_mem_before_tcg(tcg_ctx.cpu, tcg_ctx.tcg_env,
2445dcdaadb6SLluís Vilanova                                addr, trace_mem_get_info(memop, 1));
2446c45cb8bbSRichard Henderson     gen_ldst_i32(INDEX_op_qemu_st_i32, val, addr, memop, idx);
2447951c6300SRichard Henderson }
2448951c6300SRichard Henderson 
2449951c6300SRichard Henderson void tcg_gen_qemu_ld_i64(TCGv_i64 val, TCGv addr, TCGArg idx, TCGMemOp memop)
2450951c6300SRichard Henderson {
24513a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && (memop & MO_SIZE) < MO_64) {
2452951c6300SRichard Henderson         tcg_gen_qemu_ld_i32(TCGV_LOW(val), addr, idx, memop);
2453951c6300SRichard Henderson         if (memop & MO_SIGN) {
2454951c6300SRichard Henderson             tcg_gen_sari_i32(TCGV_HIGH(val), TCGV_LOW(val), 31);
2455951c6300SRichard Henderson         } else {
2456951c6300SRichard Henderson             tcg_gen_movi_i32(TCGV_HIGH(val), 0);
2457951c6300SRichard Henderson         }
2458951c6300SRichard Henderson         return;
2459951c6300SRichard Henderson     }
2460951c6300SRichard Henderson 
2461c45cb8bbSRichard Henderson     memop = tcg_canonicalize_memop(memop, 1, 0);
2462dcdaadb6SLluís Vilanova     trace_guest_mem_before_tcg(tcg_ctx.cpu, tcg_ctx.tcg_env,
2463dcdaadb6SLluís Vilanova                                addr, trace_mem_get_info(memop, 0));
2464c45cb8bbSRichard Henderson     gen_ldst_i64(INDEX_op_qemu_ld_i64, val, addr, memop, idx);
2465951c6300SRichard Henderson }
2466951c6300SRichard Henderson 
2467951c6300SRichard Henderson void tcg_gen_qemu_st_i64(TCGv_i64 val, TCGv addr, TCGArg idx, TCGMemOp memop)
2468951c6300SRichard Henderson {
24693a13c3f3SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && (memop & MO_SIZE) < MO_64) {
2470951c6300SRichard Henderson         tcg_gen_qemu_st_i32(TCGV_LOW(val), addr, idx, memop);
2471951c6300SRichard Henderson         return;
2472951c6300SRichard Henderson     }
2473951c6300SRichard Henderson 
2474c45cb8bbSRichard Henderson     memop = tcg_canonicalize_memop(memop, 1, 1);
2475dcdaadb6SLluís Vilanova     trace_guest_mem_before_tcg(tcg_ctx.cpu, tcg_ctx.tcg_env,
2476dcdaadb6SLluís Vilanova                                addr, trace_mem_get_info(memop, 1));
2477c45cb8bbSRichard Henderson     gen_ldst_i64(INDEX_op_qemu_st_i64, val, addr, memop, idx);
2478951c6300SRichard Henderson }
2479c482cb11SRichard Henderson 
2480c482cb11SRichard Henderson static void tcg_gen_ext_i32(TCGv_i32 ret, TCGv_i32 val, TCGMemOp opc)
2481c482cb11SRichard Henderson {
2482c482cb11SRichard Henderson     switch (opc & MO_SSIZE) {
2483c482cb11SRichard Henderson     case MO_SB:
2484c482cb11SRichard Henderson         tcg_gen_ext8s_i32(ret, val);
2485c482cb11SRichard Henderson         break;
2486c482cb11SRichard Henderson     case MO_UB:
2487c482cb11SRichard Henderson         tcg_gen_ext8u_i32(ret, val);
2488c482cb11SRichard Henderson         break;
2489c482cb11SRichard Henderson     case MO_SW:
2490c482cb11SRichard Henderson         tcg_gen_ext16s_i32(ret, val);
2491c482cb11SRichard Henderson         break;
2492c482cb11SRichard Henderson     case MO_UW:
2493c482cb11SRichard Henderson         tcg_gen_ext16u_i32(ret, val);
2494c482cb11SRichard Henderson         break;
2495c482cb11SRichard Henderson     default:
2496c482cb11SRichard Henderson         tcg_gen_mov_i32(ret, val);
2497c482cb11SRichard Henderson         break;
2498c482cb11SRichard Henderson     }
2499c482cb11SRichard Henderson }
2500c482cb11SRichard Henderson 
2501c482cb11SRichard Henderson static void tcg_gen_ext_i64(TCGv_i64 ret, TCGv_i64 val, TCGMemOp opc)
2502c482cb11SRichard Henderson {
2503c482cb11SRichard Henderson     switch (opc & MO_SSIZE) {
2504c482cb11SRichard Henderson     case MO_SB:
2505c482cb11SRichard Henderson         tcg_gen_ext8s_i64(ret, val);
2506c482cb11SRichard Henderson         break;
2507c482cb11SRichard Henderson     case MO_UB:
2508c482cb11SRichard Henderson         tcg_gen_ext8u_i64(ret, val);
2509c482cb11SRichard Henderson         break;
2510c482cb11SRichard Henderson     case MO_SW:
2511c482cb11SRichard Henderson         tcg_gen_ext16s_i64(ret, val);
2512c482cb11SRichard Henderson         break;
2513c482cb11SRichard Henderson     case MO_UW:
2514c482cb11SRichard Henderson         tcg_gen_ext16u_i64(ret, val);
2515c482cb11SRichard Henderson         break;
2516c482cb11SRichard Henderson     case MO_SL:
2517c482cb11SRichard Henderson         tcg_gen_ext32s_i64(ret, val);
2518c482cb11SRichard Henderson         break;
2519c482cb11SRichard Henderson     case MO_UL:
2520c482cb11SRichard Henderson         tcg_gen_ext32u_i64(ret, val);
2521c482cb11SRichard Henderson         break;
2522c482cb11SRichard Henderson     default:
2523c482cb11SRichard Henderson         tcg_gen_mov_i64(ret, val);
2524c482cb11SRichard Henderson         break;
2525c482cb11SRichard Henderson     }
2526c482cb11SRichard Henderson }
2527c482cb11SRichard Henderson 
2528c482cb11SRichard Henderson #ifdef CONFIG_SOFTMMU
2529c482cb11SRichard Henderson typedef void (*gen_atomic_cx_i32)(TCGv_i32, TCGv_env, TCGv,
2530c482cb11SRichard Henderson                                   TCGv_i32, TCGv_i32, TCGv_i32);
2531c482cb11SRichard Henderson typedef void (*gen_atomic_cx_i64)(TCGv_i64, TCGv_env, TCGv,
2532c482cb11SRichard Henderson                                   TCGv_i64, TCGv_i64, TCGv_i32);
2533c482cb11SRichard Henderson typedef void (*gen_atomic_op_i32)(TCGv_i32, TCGv_env, TCGv,
2534c482cb11SRichard Henderson                                   TCGv_i32, TCGv_i32);
2535c482cb11SRichard Henderson typedef void (*gen_atomic_op_i64)(TCGv_i64, TCGv_env, TCGv,
2536c482cb11SRichard Henderson                                   TCGv_i64, TCGv_i32);
2537c482cb11SRichard Henderson #else
2538c482cb11SRichard Henderson typedef void (*gen_atomic_cx_i32)(TCGv_i32, TCGv_env, TCGv, TCGv_i32, TCGv_i32);
2539c482cb11SRichard Henderson typedef void (*gen_atomic_cx_i64)(TCGv_i64, TCGv_env, TCGv, TCGv_i64, TCGv_i64);
2540c482cb11SRichard Henderson typedef void (*gen_atomic_op_i32)(TCGv_i32, TCGv_env, TCGv, TCGv_i32);
2541c482cb11SRichard Henderson typedef void (*gen_atomic_op_i64)(TCGv_i64, TCGv_env, TCGv, TCGv_i64);
2542c482cb11SRichard Henderson #endif
2543c482cb11SRichard Henderson 
2544df79b996SRichard Henderson #ifdef CONFIG_ATOMIC64
2545df79b996SRichard Henderson # define WITH_ATOMIC64(X) X,
2546df79b996SRichard Henderson #else
2547df79b996SRichard Henderson # define WITH_ATOMIC64(X)
2548df79b996SRichard Henderson #endif
2549df79b996SRichard Henderson 
2550c482cb11SRichard Henderson static void * const table_cmpxchg[16] = {
2551c482cb11SRichard Henderson     [MO_8] = gen_helper_atomic_cmpxchgb,
2552c482cb11SRichard Henderson     [MO_16 | MO_LE] = gen_helper_atomic_cmpxchgw_le,
2553c482cb11SRichard Henderson     [MO_16 | MO_BE] = gen_helper_atomic_cmpxchgw_be,
2554c482cb11SRichard Henderson     [MO_32 | MO_LE] = gen_helper_atomic_cmpxchgl_le,
2555c482cb11SRichard Henderson     [MO_32 | MO_BE] = gen_helper_atomic_cmpxchgl_be,
2556df79b996SRichard Henderson     WITH_ATOMIC64([MO_64 | MO_LE] = gen_helper_atomic_cmpxchgq_le)
2557df79b996SRichard Henderson     WITH_ATOMIC64([MO_64 | MO_BE] = gen_helper_atomic_cmpxchgq_be)
2558c482cb11SRichard Henderson };
2559c482cb11SRichard Henderson 
2560c482cb11SRichard Henderson void tcg_gen_atomic_cmpxchg_i32(TCGv_i32 retv, TCGv addr, TCGv_i32 cmpv,
2561c482cb11SRichard Henderson                                 TCGv_i32 newv, TCGArg idx, TCGMemOp memop)
2562c482cb11SRichard Henderson {
2563c482cb11SRichard Henderson     memop = tcg_canonicalize_memop(memop, 0, 0);
2564c482cb11SRichard Henderson 
2565c482cb11SRichard Henderson     if (!parallel_cpus) {
2566c482cb11SRichard Henderson         TCGv_i32 t1 = tcg_temp_new_i32();
2567c482cb11SRichard Henderson         TCGv_i32 t2 = tcg_temp_new_i32();
2568c482cb11SRichard Henderson 
2569c482cb11SRichard Henderson         tcg_gen_ext_i32(t2, cmpv, memop & MO_SIZE);
2570c482cb11SRichard Henderson 
2571c482cb11SRichard Henderson         tcg_gen_qemu_ld_i32(t1, addr, idx, memop & ~MO_SIGN);
2572c482cb11SRichard Henderson         tcg_gen_movcond_i32(TCG_COND_EQ, t2, t1, t2, newv, t1);
2573c482cb11SRichard Henderson         tcg_gen_qemu_st_i32(t2, addr, idx, memop);
2574c482cb11SRichard Henderson         tcg_temp_free_i32(t2);
2575c482cb11SRichard Henderson 
2576c482cb11SRichard Henderson         if (memop & MO_SIGN) {
2577c482cb11SRichard Henderson             tcg_gen_ext_i32(retv, t1, memop);
2578c482cb11SRichard Henderson         } else {
2579c482cb11SRichard Henderson             tcg_gen_mov_i32(retv, t1);
2580c482cb11SRichard Henderson         }
2581c482cb11SRichard Henderson         tcg_temp_free_i32(t1);
2582c482cb11SRichard Henderson     } else {
2583c482cb11SRichard Henderson         gen_atomic_cx_i32 gen;
2584c482cb11SRichard Henderson 
2585c482cb11SRichard Henderson         gen = table_cmpxchg[memop & (MO_SIZE | MO_BSWAP)];
2586c482cb11SRichard Henderson         tcg_debug_assert(gen != NULL);
2587c482cb11SRichard Henderson 
2588c482cb11SRichard Henderson #ifdef CONFIG_SOFTMMU
2589c482cb11SRichard Henderson         {
2590c482cb11SRichard Henderson             TCGv_i32 oi = tcg_const_i32(make_memop_idx(memop & ~MO_SIGN, idx));
2591c482cb11SRichard Henderson             gen(retv, tcg_ctx.tcg_env, addr, cmpv, newv, oi);
2592c482cb11SRichard Henderson             tcg_temp_free_i32(oi);
2593c482cb11SRichard Henderson         }
2594c482cb11SRichard Henderson #else
2595c482cb11SRichard Henderson         gen(retv, tcg_ctx.tcg_env, addr, cmpv, newv);
2596c482cb11SRichard Henderson #endif
2597c482cb11SRichard Henderson 
2598c482cb11SRichard Henderson         if (memop & MO_SIGN) {
2599c482cb11SRichard Henderson             tcg_gen_ext_i32(retv, retv, memop);
2600c482cb11SRichard Henderson         }
2601c482cb11SRichard Henderson     }
2602c482cb11SRichard Henderson }
2603c482cb11SRichard Henderson 
2604c482cb11SRichard Henderson void tcg_gen_atomic_cmpxchg_i64(TCGv_i64 retv, TCGv addr, TCGv_i64 cmpv,
2605c482cb11SRichard Henderson                                 TCGv_i64 newv, TCGArg idx, TCGMemOp memop)
2606c482cb11SRichard Henderson {
2607c482cb11SRichard Henderson     memop = tcg_canonicalize_memop(memop, 1, 0);
2608c482cb11SRichard Henderson 
2609c482cb11SRichard Henderson     if (!parallel_cpus) {
2610c482cb11SRichard Henderson         TCGv_i64 t1 = tcg_temp_new_i64();
2611c482cb11SRichard Henderson         TCGv_i64 t2 = tcg_temp_new_i64();
2612c482cb11SRichard Henderson 
2613c482cb11SRichard Henderson         tcg_gen_ext_i64(t2, cmpv, memop & MO_SIZE);
2614c482cb11SRichard Henderson 
2615c482cb11SRichard Henderson         tcg_gen_qemu_ld_i64(t1, addr, idx, memop & ~MO_SIGN);
2616c482cb11SRichard Henderson         tcg_gen_movcond_i64(TCG_COND_EQ, t2, t1, t2, newv, t1);
2617c482cb11SRichard Henderson         tcg_gen_qemu_st_i64(t2, addr, idx, memop);
2618c482cb11SRichard Henderson         tcg_temp_free_i64(t2);
2619c482cb11SRichard Henderson 
2620c482cb11SRichard Henderson         if (memop & MO_SIGN) {
2621c482cb11SRichard Henderson             tcg_gen_ext_i64(retv, t1, memop);
2622c482cb11SRichard Henderson         } else {
2623c482cb11SRichard Henderson             tcg_gen_mov_i64(retv, t1);
2624c482cb11SRichard Henderson         }
2625c482cb11SRichard Henderson         tcg_temp_free_i64(t1);
2626c482cb11SRichard Henderson     } else if ((memop & MO_SIZE) == MO_64) {
2627df79b996SRichard Henderson #ifdef CONFIG_ATOMIC64
2628c482cb11SRichard Henderson         gen_atomic_cx_i64 gen;
2629c482cb11SRichard Henderson 
2630c482cb11SRichard Henderson         gen = table_cmpxchg[memop & (MO_SIZE | MO_BSWAP)];
2631c482cb11SRichard Henderson         tcg_debug_assert(gen != NULL);
2632c482cb11SRichard Henderson 
2633c482cb11SRichard Henderson #ifdef CONFIG_SOFTMMU
2634c482cb11SRichard Henderson         {
2635c482cb11SRichard Henderson             TCGv_i32 oi = tcg_const_i32(make_memop_idx(memop, idx));
2636c482cb11SRichard Henderson             gen(retv, tcg_ctx.tcg_env, addr, cmpv, newv, oi);
2637c482cb11SRichard Henderson             tcg_temp_free_i32(oi);
2638c482cb11SRichard Henderson         }
2639c482cb11SRichard Henderson #else
2640c482cb11SRichard Henderson         gen(retv, tcg_ctx.tcg_env, addr, cmpv, newv);
2641c482cb11SRichard Henderson #endif
2642df79b996SRichard Henderson #else
2643df79b996SRichard Henderson         gen_helper_exit_atomic(tcg_ctx.tcg_env);
2644df79b996SRichard Henderson #endif /* CONFIG_ATOMIC64 */
2645c482cb11SRichard Henderson     } else {
2646c482cb11SRichard Henderson         TCGv_i32 c32 = tcg_temp_new_i32();
2647c482cb11SRichard Henderson         TCGv_i32 n32 = tcg_temp_new_i32();
2648c482cb11SRichard Henderson         TCGv_i32 r32 = tcg_temp_new_i32();
2649c482cb11SRichard Henderson 
2650c482cb11SRichard Henderson         tcg_gen_extrl_i64_i32(c32, cmpv);
2651c482cb11SRichard Henderson         tcg_gen_extrl_i64_i32(n32, newv);
2652c482cb11SRichard Henderson         tcg_gen_atomic_cmpxchg_i32(r32, addr, c32, n32, idx, memop & ~MO_SIGN);
2653c482cb11SRichard Henderson         tcg_temp_free_i32(c32);
2654c482cb11SRichard Henderson         tcg_temp_free_i32(n32);
2655c482cb11SRichard Henderson 
2656c482cb11SRichard Henderson         tcg_gen_extu_i32_i64(retv, r32);
2657c482cb11SRichard Henderson         tcg_temp_free_i32(r32);
2658c482cb11SRichard Henderson 
2659c482cb11SRichard Henderson         if (memop & MO_SIGN) {
2660c482cb11SRichard Henderson             tcg_gen_ext_i64(retv, retv, memop);
2661c482cb11SRichard Henderson         }
2662c482cb11SRichard Henderson     }
2663c482cb11SRichard Henderson }
2664c482cb11SRichard Henderson 
2665c482cb11SRichard Henderson static void do_nonatomic_op_i32(TCGv_i32 ret, TCGv addr, TCGv_i32 val,
2666c482cb11SRichard Henderson                                 TCGArg idx, TCGMemOp memop, bool new_val,
2667c482cb11SRichard Henderson                                 void (*gen)(TCGv_i32, TCGv_i32, TCGv_i32))
2668c482cb11SRichard Henderson {
2669c482cb11SRichard Henderson     TCGv_i32 t1 = tcg_temp_new_i32();
2670c482cb11SRichard Henderson     TCGv_i32 t2 = tcg_temp_new_i32();
2671c482cb11SRichard Henderson 
2672c482cb11SRichard Henderson     memop = tcg_canonicalize_memop(memop, 0, 0);
2673c482cb11SRichard Henderson 
2674c482cb11SRichard Henderson     tcg_gen_qemu_ld_i32(t1, addr, idx, memop & ~MO_SIGN);
2675c482cb11SRichard Henderson     gen(t2, t1, val);
2676c482cb11SRichard Henderson     tcg_gen_qemu_st_i32(t2, addr, idx, memop);
2677c482cb11SRichard Henderson 
2678c482cb11SRichard Henderson     tcg_gen_ext_i32(ret, (new_val ? t2 : t1), memop);
2679c482cb11SRichard Henderson     tcg_temp_free_i32(t1);
2680c482cb11SRichard Henderson     tcg_temp_free_i32(t2);
2681c482cb11SRichard Henderson }
2682c482cb11SRichard Henderson 
2683c482cb11SRichard Henderson static void do_atomic_op_i32(TCGv_i32 ret, TCGv addr, TCGv_i32 val,
2684c482cb11SRichard Henderson                              TCGArg idx, TCGMemOp memop, void * const table[])
2685c482cb11SRichard Henderson {
2686c482cb11SRichard Henderson     gen_atomic_op_i32 gen;
2687c482cb11SRichard Henderson 
2688c482cb11SRichard Henderson     memop = tcg_canonicalize_memop(memop, 0, 0);
2689c482cb11SRichard Henderson 
2690c482cb11SRichard Henderson     gen = table[memop & (MO_SIZE | MO_BSWAP)];
2691c482cb11SRichard Henderson     tcg_debug_assert(gen != NULL);
2692c482cb11SRichard Henderson 
2693c482cb11SRichard Henderson #ifdef CONFIG_SOFTMMU
2694c482cb11SRichard Henderson     {
2695c482cb11SRichard Henderson         TCGv_i32 oi = tcg_const_i32(make_memop_idx(memop & ~MO_SIGN, idx));
2696c482cb11SRichard Henderson         gen(ret, tcg_ctx.tcg_env, addr, val, oi);
2697c482cb11SRichard Henderson         tcg_temp_free_i32(oi);
2698c482cb11SRichard Henderson     }
2699c482cb11SRichard Henderson #else
2700c482cb11SRichard Henderson     gen(ret, tcg_ctx.tcg_env, addr, val);
2701c482cb11SRichard Henderson #endif
2702c482cb11SRichard Henderson 
2703c482cb11SRichard Henderson     if (memop & MO_SIGN) {
2704c482cb11SRichard Henderson         tcg_gen_ext_i32(ret, ret, memop);
2705c482cb11SRichard Henderson     }
2706c482cb11SRichard Henderson }
2707c482cb11SRichard Henderson 
2708c482cb11SRichard Henderson static void do_nonatomic_op_i64(TCGv_i64 ret, TCGv addr, TCGv_i64 val,
2709c482cb11SRichard Henderson                                 TCGArg idx, TCGMemOp memop, bool new_val,
2710c482cb11SRichard Henderson                                 void (*gen)(TCGv_i64, TCGv_i64, TCGv_i64))
2711c482cb11SRichard Henderson {
2712c482cb11SRichard Henderson     TCGv_i64 t1 = tcg_temp_new_i64();
2713c482cb11SRichard Henderson     TCGv_i64 t2 = tcg_temp_new_i64();
2714c482cb11SRichard Henderson 
2715c482cb11SRichard Henderson     memop = tcg_canonicalize_memop(memop, 1, 0);
2716c482cb11SRichard Henderson 
2717c482cb11SRichard Henderson     tcg_gen_qemu_ld_i64(t1, addr, idx, memop & ~MO_SIGN);
2718c482cb11SRichard Henderson     gen(t2, t1, val);
2719c482cb11SRichard Henderson     tcg_gen_qemu_st_i64(t2, addr, idx, memop);
2720c482cb11SRichard Henderson 
2721c482cb11SRichard Henderson     tcg_gen_ext_i64(ret, (new_val ? t2 : t1), memop);
2722c482cb11SRichard Henderson     tcg_temp_free_i64(t1);
2723c482cb11SRichard Henderson     tcg_temp_free_i64(t2);
2724c482cb11SRichard Henderson }
2725c482cb11SRichard Henderson 
2726c482cb11SRichard Henderson static void do_atomic_op_i64(TCGv_i64 ret, TCGv addr, TCGv_i64 val,
2727c482cb11SRichard Henderson                              TCGArg idx, TCGMemOp memop, void * const table[])
2728c482cb11SRichard Henderson {
2729c482cb11SRichard Henderson     memop = tcg_canonicalize_memop(memop, 1, 0);
2730c482cb11SRichard Henderson 
2731c482cb11SRichard Henderson     if ((memop & MO_SIZE) == MO_64) {
2732df79b996SRichard Henderson #ifdef CONFIG_ATOMIC64
2733c482cb11SRichard Henderson         gen_atomic_op_i64 gen;
2734c482cb11SRichard Henderson 
2735c482cb11SRichard Henderson         gen = table[memop & (MO_SIZE | MO_BSWAP)];
2736c482cb11SRichard Henderson         tcg_debug_assert(gen != NULL);
2737c482cb11SRichard Henderson 
2738c482cb11SRichard Henderson #ifdef CONFIG_SOFTMMU
2739c482cb11SRichard Henderson         {
2740c482cb11SRichard Henderson             TCGv_i32 oi = tcg_const_i32(make_memop_idx(memop & ~MO_SIGN, idx));
2741c482cb11SRichard Henderson             gen(ret, tcg_ctx.tcg_env, addr, val, oi);
2742c482cb11SRichard Henderson             tcg_temp_free_i32(oi);
2743c482cb11SRichard Henderson         }
2744c482cb11SRichard Henderson #else
2745c482cb11SRichard Henderson         gen(ret, tcg_ctx.tcg_env, addr, val);
2746c482cb11SRichard Henderson #endif
2747df79b996SRichard Henderson #else
2748df79b996SRichard Henderson         gen_helper_exit_atomic(tcg_ctx.tcg_env);
2749df79b996SRichard Henderson #endif /* CONFIG_ATOMIC64 */
2750c482cb11SRichard Henderson     } else {
2751c482cb11SRichard Henderson         TCGv_i32 v32 = tcg_temp_new_i32();
2752c482cb11SRichard Henderson         TCGv_i32 r32 = tcg_temp_new_i32();
2753c482cb11SRichard Henderson 
2754c482cb11SRichard Henderson         tcg_gen_extrl_i64_i32(v32, val);
2755c482cb11SRichard Henderson         do_atomic_op_i32(r32, addr, v32, idx, memop & ~MO_SIGN, table);
2756c482cb11SRichard Henderson         tcg_temp_free_i32(v32);
2757c482cb11SRichard Henderson 
2758c482cb11SRichard Henderson         tcg_gen_extu_i32_i64(ret, r32);
2759c482cb11SRichard Henderson         tcg_temp_free_i32(r32);
2760c482cb11SRichard Henderson 
2761c482cb11SRichard Henderson         if (memop & MO_SIGN) {
2762c482cb11SRichard Henderson             tcg_gen_ext_i64(ret, ret, memop);
2763c482cb11SRichard Henderson         }
2764c482cb11SRichard Henderson     }
2765c482cb11SRichard Henderson }
2766c482cb11SRichard Henderson 
2767c482cb11SRichard Henderson #define GEN_ATOMIC_HELPER(NAME, OP, NEW)                                \
2768c482cb11SRichard Henderson static void * const table_##NAME[16] = {                                \
2769c482cb11SRichard Henderson     [MO_8] = gen_helper_atomic_##NAME##b,                               \
2770c482cb11SRichard Henderson     [MO_16 | MO_LE] = gen_helper_atomic_##NAME##w_le,                   \
2771c482cb11SRichard Henderson     [MO_16 | MO_BE] = gen_helper_atomic_##NAME##w_be,                   \
2772c482cb11SRichard Henderson     [MO_32 | MO_LE] = gen_helper_atomic_##NAME##l_le,                   \
2773c482cb11SRichard Henderson     [MO_32 | MO_BE] = gen_helper_atomic_##NAME##l_be,                   \
2774df79b996SRichard Henderson     WITH_ATOMIC64([MO_64 | MO_LE] = gen_helper_atomic_##NAME##q_le)     \
2775df79b996SRichard Henderson     WITH_ATOMIC64([MO_64 | MO_BE] = gen_helper_atomic_##NAME##q_be)     \
2776c482cb11SRichard Henderson };                                                                      \
2777c482cb11SRichard Henderson void tcg_gen_atomic_##NAME##_i32                                        \
2778c482cb11SRichard Henderson     (TCGv_i32 ret, TCGv addr, TCGv_i32 val, TCGArg idx, TCGMemOp memop) \
2779c482cb11SRichard Henderson {                                                                       \
2780c482cb11SRichard Henderson     if (parallel_cpus) {                                                \
2781c482cb11SRichard Henderson         do_atomic_op_i32(ret, addr, val, idx, memop, table_##NAME);     \
2782c482cb11SRichard Henderson     } else {                                                            \
2783c482cb11SRichard Henderson         do_nonatomic_op_i32(ret, addr, val, idx, memop, NEW,            \
2784c482cb11SRichard Henderson                             tcg_gen_##OP##_i32);                        \
2785c482cb11SRichard Henderson     }                                                                   \
2786c482cb11SRichard Henderson }                                                                       \
2787c482cb11SRichard Henderson void tcg_gen_atomic_##NAME##_i64                                        \
2788c482cb11SRichard Henderson     (TCGv_i64 ret, TCGv addr, TCGv_i64 val, TCGArg idx, TCGMemOp memop) \
2789c482cb11SRichard Henderson {                                                                       \
2790c482cb11SRichard Henderson     if (parallel_cpus) {                                                \
2791c482cb11SRichard Henderson         do_atomic_op_i64(ret, addr, val, idx, memop, table_##NAME);     \
2792c482cb11SRichard Henderson     } else {                                                            \
2793c482cb11SRichard Henderson         do_nonatomic_op_i64(ret, addr, val, idx, memop, NEW,            \
2794c482cb11SRichard Henderson                             tcg_gen_##OP##_i64);                        \
2795c482cb11SRichard Henderson     }                                                                   \
2796c482cb11SRichard Henderson }
2797c482cb11SRichard Henderson 
2798c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_add, add, 0)
2799c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_and, and, 0)
2800c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_or, or, 0)
2801c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_xor, xor, 0)
2802c482cb11SRichard Henderson 
2803c482cb11SRichard Henderson GEN_ATOMIC_HELPER(add_fetch, add, 1)
2804c482cb11SRichard Henderson GEN_ATOMIC_HELPER(and_fetch, and, 1)
2805c482cb11SRichard Henderson GEN_ATOMIC_HELPER(or_fetch, or, 1)
2806c482cb11SRichard Henderson GEN_ATOMIC_HELPER(xor_fetch, xor, 1)
2807c482cb11SRichard Henderson 
2808c482cb11SRichard Henderson static void tcg_gen_mov2_i32(TCGv_i32 r, TCGv_i32 a, TCGv_i32 b)
2809c482cb11SRichard Henderson {
2810c482cb11SRichard Henderson     tcg_gen_mov_i32(r, b);
2811c482cb11SRichard Henderson }
2812c482cb11SRichard Henderson 
2813c482cb11SRichard Henderson static void tcg_gen_mov2_i64(TCGv_i64 r, TCGv_i64 a, TCGv_i64 b)
2814c482cb11SRichard Henderson {
2815c482cb11SRichard Henderson     tcg_gen_mov_i64(r, b);
2816c482cb11SRichard Henderson }
2817c482cb11SRichard Henderson 
2818c482cb11SRichard Henderson GEN_ATOMIC_HELPER(xchg, mov2, 0)
2819c482cb11SRichard Henderson 
2820c482cb11SRichard Henderson #undef GEN_ATOMIC_HELPER
2821