xref: /openbmc/qemu/tcg/optimize.c (revision 4ae7d11b70a840eec7aa27269093b15d04ebc84e)
18f2e8c07SKirill Batuzov /*
28f2e8c07SKirill Batuzov  * Optimizations for Tiny Code Generator for QEMU
38f2e8c07SKirill Batuzov  *
48f2e8c07SKirill Batuzov  * Copyright (c) 2010 Samsung Electronics.
58f2e8c07SKirill Batuzov  * Contributed by Kirill Batuzov <batuzovk@ispras.ru>
68f2e8c07SKirill Batuzov  *
78f2e8c07SKirill Batuzov  * Permission is hereby granted, free of charge, to any person obtaining a copy
88f2e8c07SKirill Batuzov  * of this software and associated documentation files (the "Software"), to deal
98f2e8c07SKirill Batuzov  * in the Software without restriction, including without limitation the rights
108f2e8c07SKirill Batuzov  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
118f2e8c07SKirill Batuzov  * copies of the Software, and to permit persons to whom the Software is
128f2e8c07SKirill Batuzov  * furnished to do so, subject to the following conditions:
138f2e8c07SKirill Batuzov  *
148f2e8c07SKirill Batuzov  * The above copyright notice and this permission notice shall be included in
158f2e8c07SKirill Batuzov  * all copies or substantial portions of the Software.
168f2e8c07SKirill Batuzov  *
178f2e8c07SKirill Batuzov  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
188f2e8c07SKirill Batuzov  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
198f2e8c07SKirill Batuzov  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
208f2e8c07SKirill Batuzov  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
218f2e8c07SKirill Batuzov  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
228f2e8c07SKirill Batuzov  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
238f2e8c07SKirill Batuzov  * THE SOFTWARE.
248f2e8c07SKirill Batuzov  */
258f2e8c07SKirill Batuzov 
26757e725bSPeter Maydell #include "qemu/osdep.h"
279531c078SRichard Henderson #include "qemu/int128.h"
28ab84dc39SRichard Henderson #include "qemu/interval-tree.h"
29ad3d0e4dSRichard Henderson #include "tcg/tcg-op-common.h"
3090163900SRichard Henderson #include "tcg-internal.h"
318f2e8c07SKirill Batuzov 
328f2e8c07SKirill Batuzov #define CASE_OP_32_64(x)                        \
338f2e8c07SKirill Batuzov         glue(glue(case INDEX_op_, x), _i32):    \
348f2e8c07SKirill Batuzov         glue(glue(case INDEX_op_, x), _i64)
358f2e8c07SKirill Batuzov 
36170ba88fSRichard Henderson #define CASE_OP_32_64_VEC(x)                    \
37170ba88fSRichard Henderson         glue(glue(case INDEX_op_, x), _i32):    \
38170ba88fSRichard Henderson         glue(glue(case INDEX_op_, x), _i64):    \
39170ba88fSRichard Henderson         glue(glue(case INDEX_op_, x), _vec)
40170ba88fSRichard Henderson 
41ab84dc39SRichard Henderson typedef struct MemCopyInfo {
42ab84dc39SRichard Henderson     IntervalTreeNode itree;
43ab84dc39SRichard Henderson     QSIMPLEQ_ENTRY (MemCopyInfo) next;
44ab84dc39SRichard Henderson     TCGTemp *ts;
45ab84dc39SRichard Henderson     TCGType type;
46ab84dc39SRichard Henderson } MemCopyInfo;
47ab84dc39SRichard Henderson 
486fcb98edSRichard Henderson typedef struct TempOptInfo {
49b41059ddSAurelien Jarno     bool is_const;
506349039dSRichard Henderson     TCGTemp *prev_copy;
516349039dSRichard Henderson     TCGTemp *next_copy;
52ab84dc39SRichard Henderson     QSIMPLEQ_HEAD(, MemCopyInfo) mem_copy;
5354795544SRichard Henderson     uint64_t val;
54b1fde411SRichard Henderson     uint64_t z_mask;  /* mask bit is 0 if and only if value bit is 0 */
5557fe5c6dSRichard Henderson     uint64_t s_mask;  /* a left-aligned mask of clrsb(value) bits. */
566fcb98edSRichard Henderson } TempOptInfo;
5722613af4SKirill Batuzov 
583b3f847dSRichard Henderson typedef struct OptContext {
59dc84988aSRichard Henderson     TCGContext *tcg;
60d0ed5151SRichard Henderson     TCGOp *prev_mb;
613b3f847dSRichard Henderson     TCGTempSet temps_used;
62137f1f44SRichard Henderson 
63ab84dc39SRichard Henderson     IntervalTreeRoot mem_copy;
64ab84dc39SRichard Henderson     QSIMPLEQ_HEAD(, MemCopyInfo) mem_free;
65ab84dc39SRichard Henderson 
66137f1f44SRichard Henderson     /* In flight values from optimization. */
67fae450baSRichard Henderson     uint64_t a_mask;  /* mask bit is 0 iff value identical to first input */
68fae450baSRichard Henderson     uint64_t z_mask;  /* mask bit is 0 iff value bit is 0 */
6957fe5c6dSRichard Henderson     uint64_t s_mask;  /* mask of clrsb(value) bits */
7067f84c96SRichard Henderson     TCGType type;
713b3f847dSRichard Henderson } OptContext;
723b3f847dSRichard Henderson 
7357fe5c6dSRichard Henderson /* Calculate the smask for a specific value. */
smask_from_value(uint64_t value)7457fe5c6dSRichard Henderson static uint64_t smask_from_value(uint64_t value)
7557fe5c6dSRichard Henderson {
7657fe5c6dSRichard Henderson     int rep = clrsb64(value);
7757fe5c6dSRichard Henderson     return ~(~0ull >> rep);
7857fe5c6dSRichard Henderson }
7957fe5c6dSRichard Henderson 
8057fe5c6dSRichard Henderson /*
8157fe5c6dSRichard Henderson  * Calculate the smask for a given set of known-zeros.
8257fe5c6dSRichard Henderson  * If there are lots of zeros on the left, we can consider the remainder
8357fe5c6dSRichard Henderson  * an unsigned field, and thus the corresponding signed field is one bit
8457fe5c6dSRichard Henderson  * larger.
8557fe5c6dSRichard Henderson  */
smask_from_zmask(uint64_t zmask)8657fe5c6dSRichard Henderson static uint64_t smask_from_zmask(uint64_t zmask)
8757fe5c6dSRichard Henderson {
8857fe5c6dSRichard Henderson     /*
8957fe5c6dSRichard Henderson      * Only the 0 bits are significant for zmask, thus the msb itself
9057fe5c6dSRichard Henderson      * must be zero, else we have no sign information.
9157fe5c6dSRichard Henderson      */
9257fe5c6dSRichard Henderson     int rep = clz64(zmask);
9357fe5c6dSRichard Henderson     if (rep == 0) {
9457fe5c6dSRichard Henderson         return 0;
9557fe5c6dSRichard Henderson     }
9657fe5c6dSRichard Henderson     rep -= 1;
9757fe5c6dSRichard Henderson     return ~(~0ull >> rep);
9857fe5c6dSRichard Henderson }
9957fe5c6dSRichard Henderson 
10093a967fbSRichard Henderson /*
10193a967fbSRichard Henderson  * Recreate a properly left-aligned smask after manipulation.
10293a967fbSRichard Henderson  * Some bit-shuffling, particularly shifts and rotates, may
10393a967fbSRichard Henderson  * retain sign bits on the left, but may scatter disconnected
10493a967fbSRichard Henderson  * sign bits on the right.  Retain only what remains to the left.
10593a967fbSRichard Henderson  */
smask_from_smask(int64_t smask)10693a967fbSRichard Henderson static uint64_t smask_from_smask(int64_t smask)
10793a967fbSRichard Henderson {
10893a967fbSRichard Henderson     /* Only the 1 bits are significant for smask */
10993a967fbSRichard Henderson     return smask_from_zmask(~smask);
11093a967fbSRichard Henderson }
11193a967fbSRichard Henderson 
ts_info(TCGTemp * ts)1126fcb98edSRichard Henderson static inline TempOptInfo *ts_info(TCGTemp *ts)
113d9c769c6SAurelien Jarno {
1146349039dSRichard Henderson     return ts->state_ptr;
115d9c769c6SAurelien Jarno }
116d9c769c6SAurelien Jarno 
arg_info(TCGArg arg)1176fcb98edSRichard Henderson static inline TempOptInfo *arg_info(TCGArg arg)
118d9c769c6SAurelien Jarno {
1196349039dSRichard Henderson     return ts_info(arg_temp(arg));
1206349039dSRichard Henderson }
1216349039dSRichard Henderson 
ts_is_const(TCGTemp * ts)1226349039dSRichard Henderson static inline bool ts_is_const(TCGTemp *ts)
1236349039dSRichard Henderson {
1246349039dSRichard Henderson     return ts_info(ts)->is_const;
1256349039dSRichard Henderson }
1266349039dSRichard Henderson 
ts_is_const_val(TCGTemp * ts,uint64_t val)12727cdb85dSRichard Henderson static inline bool ts_is_const_val(TCGTemp *ts, uint64_t val)
12827cdb85dSRichard Henderson {
12927cdb85dSRichard Henderson     TempOptInfo *ti = ts_info(ts);
13027cdb85dSRichard Henderson     return ti->is_const && ti->val == val;
13127cdb85dSRichard Henderson }
13227cdb85dSRichard Henderson 
arg_is_const(TCGArg arg)1336349039dSRichard Henderson static inline bool arg_is_const(TCGArg arg)
1346349039dSRichard Henderson {
1356349039dSRichard Henderson     return ts_is_const(arg_temp(arg));
1366349039dSRichard Henderson }
1376349039dSRichard Henderson 
arg_is_const_val(TCGArg arg,uint64_t val)13827cdb85dSRichard Henderson static inline bool arg_is_const_val(TCGArg arg, uint64_t val)
13927cdb85dSRichard Henderson {
14027cdb85dSRichard Henderson     return ts_is_const_val(arg_temp(arg), val);
14127cdb85dSRichard Henderson }
14227cdb85dSRichard Henderson 
ts_is_copy(TCGTemp * ts)1436349039dSRichard Henderson static inline bool ts_is_copy(TCGTemp *ts)
1446349039dSRichard Henderson {
1456349039dSRichard Henderson     return ts_info(ts)->next_copy != ts;
146d9c769c6SAurelien Jarno }
147d9c769c6SAurelien Jarno 
cmp_better_copy(TCGTemp * a,TCGTemp * b)1489f75e528SRichard Henderson static TCGTemp *cmp_better_copy(TCGTemp *a, TCGTemp *b)
1499f75e528SRichard Henderson {
1509f75e528SRichard Henderson     return a->kind < b->kind ? b : a;
1519f75e528SRichard Henderson }
1529f75e528SRichard Henderson 
1531208d7ddSAurelien Jarno /* Initialize and activate a temporary.  */
init_ts_info(OptContext * ctx,TCGTemp * ts)1543b3f847dSRichard Henderson static void init_ts_info(OptContext *ctx, TCGTemp *ts)
1551208d7ddSAurelien Jarno {
1566349039dSRichard Henderson     size_t idx = temp_idx(ts);
1578f17a975SRichard Henderson     TempOptInfo *ti;
1586349039dSRichard Henderson 
1593b3f847dSRichard Henderson     if (test_bit(idx, ctx->temps_used.l)) {
1608f17a975SRichard Henderson         return;
1618f17a975SRichard Henderson     }
1623b3f847dSRichard Henderson     set_bit(idx, ctx->temps_used.l);
1638f17a975SRichard Henderson 
1648f17a975SRichard Henderson     ti = ts->state_ptr;
1658f17a975SRichard Henderson     if (ti == NULL) {
1668f17a975SRichard Henderson         ti = tcg_malloc(sizeof(TempOptInfo));
1676349039dSRichard Henderson         ts->state_ptr = ti;
1688f17a975SRichard Henderson     }
1698f17a975SRichard Henderson 
1706349039dSRichard Henderson     ti->next_copy = ts;
1716349039dSRichard Henderson     ti->prev_copy = ts;
172ab84dc39SRichard Henderson     QSIMPLEQ_INIT(&ti->mem_copy);
173c0522136SRichard Henderson     if (ts->kind == TEMP_CONST) {
174c0522136SRichard Henderson         ti->is_const = true;
1758f17a975SRichard Henderson         ti->val = ts->val;
176b1fde411SRichard Henderson         ti->z_mask = ts->val;
17757fe5c6dSRichard Henderson         ti->s_mask = smask_from_value(ts->val);
178c0522136SRichard Henderson     } else {
1796349039dSRichard Henderson         ti->is_const = false;
180b1fde411SRichard Henderson         ti->z_mask = -1;
18157fe5c6dSRichard Henderson         ti->s_mask = 0;
182c0522136SRichard Henderson     }
1831208d7ddSAurelien Jarno }
1841208d7ddSAurelien Jarno 
mem_copy_first(OptContext * ctx,intptr_t s,intptr_t l)185ab84dc39SRichard Henderson static MemCopyInfo *mem_copy_first(OptContext *ctx, intptr_t s, intptr_t l)
186ab84dc39SRichard Henderson {
187ab84dc39SRichard Henderson     IntervalTreeNode *r = interval_tree_iter_first(&ctx->mem_copy, s, l);
188ab84dc39SRichard Henderson     return r ? container_of(r, MemCopyInfo, itree) : NULL;
189ab84dc39SRichard Henderson }
190ab84dc39SRichard Henderson 
mem_copy_next(MemCopyInfo * mem,intptr_t s,intptr_t l)191ab84dc39SRichard Henderson static MemCopyInfo *mem_copy_next(MemCopyInfo *mem, intptr_t s, intptr_t l)
192ab84dc39SRichard Henderson {
193ab84dc39SRichard Henderson     IntervalTreeNode *r = interval_tree_iter_next(&mem->itree, s, l);
194ab84dc39SRichard Henderson     return r ? container_of(r, MemCopyInfo, itree) : NULL;
195ab84dc39SRichard Henderson }
196ab84dc39SRichard Henderson 
remove_mem_copy(OptContext * ctx,MemCopyInfo * mc)197ab84dc39SRichard Henderson static void remove_mem_copy(OptContext *ctx, MemCopyInfo *mc)
198ab84dc39SRichard Henderson {
199ab84dc39SRichard Henderson     TCGTemp *ts = mc->ts;
200ab84dc39SRichard Henderson     TempOptInfo *ti = ts_info(ts);
201ab84dc39SRichard Henderson 
202ab84dc39SRichard Henderson     interval_tree_remove(&mc->itree, &ctx->mem_copy);
203ab84dc39SRichard Henderson     QSIMPLEQ_REMOVE(&ti->mem_copy, mc, MemCopyInfo, next);
204ab84dc39SRichard Henderson     QSIMPLEQ_INSERT_TAIL(&ctx->mem_free, mc, next);
205ab84dc39SRichard Henderson }
206ab84dc39SRichard Henderson 
remove_mem_copy_in(OptContext * ctx,intptr_t s,intptr_t l)207ab84dc39SRichard Henderson static void remove_mem_copy_in(OptContext *ctx, intptr_t s, intptr_t l)
208ab84dc39SRichard Henderson {
209ab84dc39SRichard Henderson     while (true) {
210ab84dc39SRichard Henderson         MemCopyInfo *mc = mem_copy_first(ctx, s, l);
211ab84dc39SRichard Henderson         if (!mc) {
212ab84dc39SRichard Henderson             break;
213ab84dc39SRichard Henderson         }
214ab84dc39SRichard Henderson         remove_mem_copy(ctx, mc);
215ab84dc39SRichard Henderson     }
216ab84dc39SRichard Henderson }
217ab84dc39SRichard Henderson 
remove_mem_copy_all(OptContext * ctx)218ab84dc39SRichard Henderson static void remove_mem_copy_all(OptContext *ctx)
219ab84dc39SRichard Henderson {
220ab84dc39SRichard Henderson     remove_mem_copy_in(ctx, 0, -1);
221ab84dc39SRichard Henderson     tcg_debug_assert(interval_tree_is_empty(&ctx->mem_copy));
222ab84dc39SRichard Henderson }
223ab84dc39SRichard Henderson 
find_better_copy(TCGTemp * ts)2249f75e528SRichard Henderson static TCGTemp *find_better_copy(TCGTemp *ts)
225e590d4e6SAurelien Jarno {
2269f75e528SRichard Henderson     TCGTemp *i, *ret;
227e590d4e6SAurelien Jarno 
2284c868ce6SRichard Henderson     /* If this is already readonly, we can't do better. */
2294c868ce6SRichard Henderson     if (temp_readonly(ts)) {
2306349039dSRichard Henderson         return ts;
231e590d4e6SAurelien Jarno     }
232e590d4e6SAurelien Jarno 
2339f75e528SRichard Henderson     ret = ts;
2346349039dSRichard Henderson     for (i = ts_info(ts)->next_copy; i != ts; i = ts_info(i)->next_copy) {
2359f75e528SRichard Henderson         ret = cmp_better_copy(ret, i);
236e590d4e6SAurelien Jarno     }
2379f75e528SRichard Henderson     return ret;
238e590d4e6SAurelien Jarno }
239e590d4e6SAurelien Jarno 
move_mem_copies(TCGTemp * dst_ts,TCGTemp * src_ts)240ab84dc39SRichard Henderson static void move_mem_copies(TCGTemp *dst_ts, TCGTemp *src_ts)
241ab84dc39SRichard Henderson {
242ab84dc39SRichard Henderson     TempOptInfo *si = ts_info(src_ts);
243ab84dc39SRichard Henderson     TempOptInfo *di = ts_info(dst_ts);
244ab84dc39SRichard Henderson     MemCopyInfo *mc;
245ab84dc39SRichard Henderson 
246ab84dc39SRichard Henderson     QSIMPLEQ_FOREACH(mc, &si->mem_copy, next) {
247ab84dc39SRichard Henderson         tcg_debug_assert(mc->ts == src_ts);
248ab84dc39SRichard Henderson         mc->ts = dst_ts;
249ab84dc39SRichard Henderson     }
250ab84dc39SRichard Henderson     QSIMPLEQ_CONCAT(&di->mem_copy, &si->mem_copy);
251ab84dc39SRichard Henderson }
252ab84dc39SRichard Henderson 
253ab84dc39SRichard Henderson /* Reset TEMP's state, possibly removing the temp for the list of copies.  */
reset_ts(OptContext * ctx,TCGTemp * ts)254ab84dc39SRichard Henderson static void reset_ts(OptContext *ctx, TCGTemp *ts)
255ab84dc39SRichard Henderson {
256ab84dc39SRichard Henderson     TempOptInfo *ti = ts_info(ts);
257ab84dc39SRichard Henderson     TCGTemp *pts = ti->prev_copy;
258ab84dc39SRichard Henderson     TCGTemp *nts = ti->next_copy;
259ab84dc39SRichard Henderson     TempOptInfo *pi = ts_info(pts);
260ab84dc39SRichard Henderson     TempOptInfo *ni = ts_info(nts);
261ab84dc39SRichard Henderson 
262ab84dc39SRichard Henderson     ni->prev_copy = ti->prev_copy;
263ab84dc39SRichard Henderson     pi->next_copy = ti->next_copy;
264ab84dc39SRichard Henderson     ti->next_copy = ts;
265ab84dc39SRichard Henderson     ti->prev_copy = ts;
266ab84dc39SRichard Henderson     ti->is_const = false;
267ab84dc39SRichard Henderson     ti->z_mask = -1;
268ab84dc39SRichard Henderson     ti->s_mask = 0;
269ab84dc39SRichard Henderson 
270ab84dc39SRichard Henderson     if (!QSIMPLEQ_EMPTY(&ti->mem_copy)) {
271ab84dc39SRichard Henderson         if (ts == nts) {
272ab84dc39SRichard Henderson             /* Last temp copy being removed, the mem copies die. */
273ab84dc39SRichard Henderson             MemCopyInfo *mc;
274ab84dc39SRichard Henderson             QSIMPLEQ_FOREACH(mc, &ti->mem_copy, next) {
275ab84dc39SRichard Henderson                 interval_tree_remove(&mc->itree, &ctx->mem_copy);
276ab84dc39SRichard Henderson             }
277ab84dc39SRichard Henderson             QSIMPLEQ_CONCAT(&ctx->mem_free, &ti->mem_copy);
278ab84dc39SRichard Henderson         } else {
279ab84dc39SRichard Henderson             move_mem_copies(find_better_copy(nts), ts);
280ab84dc39SRichard Henderson         }
281ab84dc39SRichard Henderson     }
282ab84dc39SRichard Henderson }
283ab84dc39SRichard Henderson 
reset_temp(OptContext * ctx,TCGArg arg)284ab84dc39SRichard Henderson static void reset_temp(OptContext *ctx, TCGArg arg)
285ab84dc39SRichard Henderson {
286ab84dc39SRichard Henderson     reset_ts(ctx, arg_temp(arg));
287ab84dc39SRichard Henderson }
288ab84dc39SRichard Henderson 
record_mem_copy(OptContext * ctx,TCGType type,TCGTemp * ts,intptr_t start,intptr_t last)289ab84dc39SRichard Henderson static void record_mem_copy(OptContext *ctx, TCGType type,
290ab84dc39SRichard Henderson                             TCGTemp *ts, intptr_t start, intptr_t last)
291ab84dc39SRichard Henderson {
292ab84dc39SRichard Henderson     MemCopyInfo *mc;
293ab84dc39SRichard Henderson     TempOptInfo *ti;
294ab84dc39SRichard Henderson 
295ab84dc39SRichard Henderson     mc = QSIMPLEQ_FIRST(&ctx->mem_free);
296ab84dc39SRichard Henderson     if (mc) {
297ab84dc39SRichard Henderson         QSIMPLEQ_REMOVE_HEAD(&ctx->mem_free, next);
298ab84dc39SRichard Henderson     } else {
299ab84dc39SRichard Henderson         mc = tcg_malloc(sizeof(*mc));
300ab84dc39SRichard Henderson     }
301ab84dc39SRichard Henderson 
302ab84dc39SRichard Henderson     memset(mc, 0, sizeof(*mc));
303ab84dc39SRichard Henderson     mc->itree.start = start;
304ab84dc39SRichard Henderson     mc->itree.last = last;
305ab84dc39SRichard Henderson     mc->type = type;
306ab84dc39SRichard Henderson     interval_tree_insert(&mc->itree, &ctx->mem_copy);
307ab84dc39SRichard Henderson 
308ab84dc39SRichard Henderson     ts = find_better_copy(ts);
309ab84dc39SRichard Henderson     ti = ts_info(ts);
310ab84dc39SRichard Henderson     mc->ts = ts;
311ab84dc39SRichard Henderson     QSIMPLEQ_INSERT_TAIL(&ti->mem_copy, mc, next);
312ab84dc39SRichard Henderson }
313ab84dc39SRichard Henderson 
ts_are_copies(TCGTemp * ts1,TCGTemp * ts2)3146349039dSRichard Henderson static bool ts_are_copies(TCGTemp *ts1, TCGTemp *ts2)
315e590d4e6SAurelien Jarno {
3166349039dSRichard Henderson     TCGTemp *i;
317e590d4e6SAurelien Jarno 
3186349039dSRichard Henderson     if (ts1 == ts2) {
319e590d4e6SAurelien Jarno         return true;
320e590d4e6SAurelien Jarno     }
321e590d4e6SAurelien Jarno 
3226349039dSRichard Henderson     if (!ts_is_copy(ts1) || !ts_is_copy(ts2)) {
323e590d4e6SAurelien Jarno         return false;
324e590d4e6SAurelien Jarno     }
325e590d4e6SAurelien Jarno 
3266349039dSRichard Henderson     for (i = ts_info(ts1)->next_copy; i != ts1; i = ts_info(i)->next_copy) {
3276349039dSRichard Henderson         if (i == ts2) {
328e590d4e6SAurelien Jarno             return true;
329e590d4e6SAurelien Jarno         }
330e590d4e6SAurelien Jarno     }
331e590d4e6SAurelien Jarno 
332e590d4e6SAurelien Jarno     return false;
333e590d4e6SAurelien Jarno }
334e590d4e6SAurelien Jarno 
args_are_copies(TCGArg arg1,TCGArg arg2)3356349039dSRichard Henderson static bool args_are_copies(TCGArg arg1, TCGArg arg2)
3366349039dSRichard Henderson {
3376349039dSRichard Henderson     return ts_are_copies(arg_temp(arg1), arg_temp(arg2));
3386349039dSRichard Henderson }
3396349039dSRichard Henderson 
find_mem_copy_for(OptContext * ctx,TCGType type,intptr_t s)340ab84dc39SRichard Henderson static TCGTemp *find_mem_copy_for(OptContext *ctx, TCGType type, intptr_t s)
341ab84dc39SRichard Henderson {
342ab84dc39SRichard Henderson     MemCopyInfo *mc;
343ab84dc39SRichard Henderson 
344ab84dc39SRichard Henderson     for (mc = mem_copy_first(ctx, s, s); mc; mc = mem_copy_next(mc, s, s)) {
345ab84dc39SRichard Henderson         if (mc->itree.start == s && mc->type == type) {
346ab84dc39SRichard Henderson             return find_better_copy(mc->ts);
347ab84dc39SRichard Henderson         }
348ab84dc39SRichard Henderson     }
349ab84dc39SRichard Henderson     return NULL;
350ab84dc39SRichard Henderson }
351ab84dc39SRichard Henderson 
arg_new_constant(OptContext * ctx,uint64_t val)35226aac97cSRichard Henderson static TCGArg arg_new_constant(OptContext *ctx, uint64_t val)
35326aac97cSRichard Henderson {
35426aac97cSRichard Henderson     TCGType type = ctx->type;
35526aac97cSRichard Henderson     TCGTemp *ts;
35626aac97cSRichard Henderson 
35726aac97cSRichard Henderson     if (type == TCG_TYPE_I32) {
35826aac97cSRichard Henderson         val = (int32_t)val;
35926aac97cSRichard Henderson     }
36026aac97cSRichard Henderson 
36126aac97cSRichard Henderson     ts = tcg_constant_internal(type, val);
36226aac97cSRichard Henderson     init_ts_info(ctx, ts);
36326aac97cSRichard Henderson 
36426aac97cSRichard Henderson     return temp_arg(ts);
36526aac97cSRichard Henderson }
36626aac97cSRichard Henderson 
arg_new_temp(OptContext * ctx)367fb04ab7dSRichard Henderson static TCGArg arg_new_temp(OptContext *ctx)
368fb04ab7dSRichard Henderson {
369fb04ab7dSRichard Henderson     TCGTemp *ts = tcg_temp_new_internal(ctx->type, TEMP_EBB);
370fb04ab7dSRichard Henderson     init_ts_info(ctx, ts);
371fb04ab7dSRichard Henderson     return temp_arg(ts);
372fb04ab7dSRichard Henderson }
373fb04ab7dSRichard Henderson 
tcg_opt_gen_mov(OptContext * ctx,TCGOp * op,TCGArg dst,TCGArg src)3746b99d5bfSRichard Henderson static bool tcg_opt_gen_mov(OptContext *ctx, TCGOp *op, TCGArg dst, TCGArg src)
37522613af4SKirill Batuzov {
3766349039dSRichard Henderson     TCGTemp *dst_ts = arg_temp(dst);
3776349039dSRichard Henderson     TCGTemp *src_ts = arg_temp(src);
3786fcb98edSRichard Henderson     TempOptInfo *di;
3796fcb98edSRichard Henderson     TempOptInfo *si;
3806349039dSRichard Henderson     TCGOpcode new_op;
3816349039dSRichard Henderson 
3826349039dSRichard Henderson     if (ts_are_copies(dst_ts, src_ts)) {
383dc84988aSRichard Henderson         tcg_op_remove(ctx->tcg, op);
3846b99d5bfSRichard Henderson         return true;
3855365718aSAurelien Jarno     }
3865365718aSAurelien Jarno 
387986cac1dSRichard Henderson     reset_ts(ctx, dst_ts);
3886349039dSRichard Henderson     di = ts_info(dst_ts);
3896349039dSRichard Henderson     si = ts_info(src_ts);
39067f84c96SRichard Henderson 
39167f84c96SRichard Henderson     switch (ctx->type) {
39267f84c96SRichard Henderson     case TCG_TYPE_I32:
393170ba88fSRichard Henderson         new_op = INDEX_op_mov_i32;
39467f84c96SRichard Henderson         break;
39567f84c96SRichard Henderson     case TCG_TYPE_I64:
39667f84c96SRichard Henderson         new_op = INDEX_op_mov_i64;
39767f84c96SRichard Henderson         break;
39867f84c96SRichard Henderson     case TCG_TYPE_V64:
39967f84c96SRichard Henderson     case TCG_TYPE_V128:
40067f84c96SRichard Henderson     case TCG_TYPE_V256:
40167f84c96SRichard Henderson         /* TCGOP_VECL and TCGOP_VECE remain unchanged.  */
40267f84c96SRichard Henderson         new_op = INDEX_op_mov_vec;
40367f84c96SRichard Henderson         break;
40467f84c96SRichard Henderson     default:
40567f84c96SRichard Henderson         g_assert_not_reached();
406170ba88fSRichard Henderson     }
407c45cb8bbSRichard Henderson     op->opc = new_op;
4086349039dSRichard Henderson     op->args[0] = dst;
4096349039dSRichard Henderson     op->args[1] = src;
410a62f6f56SRichard Henderson 
411faa2e100SRichard Henderson     di->z_mask = si->z_mask;
41257fe5c6dSRichard Henderson     di->s_mask = si->s_mask;
41324666bafSRichard Henderson 
4146349039dSRichard Henderson     if (src_ts->type == dst_ts->type) {
4156fcb98edSRichard Henderson         TempOptInfo *ni = ts_info(si->next_copy);
4166349039dSRichard Henderson 
4176349039dSRichard Henderson         di->next_copy = si->next_copy;
4186349039dSRichard Henderson         di->prev_copy = src_ts;
4196349039dSRichard Henderson         ni->prev_copy = dst_ts;
4206349039dSRichard Henderson         si->next_copy = dst_ts;
4216349039dSRichard Henderson         di->is_const = si->is_const;
4226349039dSRichard Henderson         di->val = si->val;
423ab84dc39SRichard Henderson 
424ab84dc39SRichard Henderson         if (!QSIMPLEQ_EMPTY(&si->mem_copy)
425ab84dc39SRichard Henderson             && cmp_better_copy(src_ts, dst_ts) == dst_ts) {
426ab84dc39SRichard Henderson             move_mem_copies(dst_ts, src_ts);
427ab84dc39SRichard Henderson         }
42822613af4SKirill Batuzov     }
4296b99d5bfSRichard Henderson     return true;
43022613af4SKirill Batuzov }
43122613af4SKirill Batuzov 
tcg_opt_gen_movi(OptContext * ctx,TCGOp * op,TCGArg dst,uint64_t val)4326b99d5bfSRichard Henderson static bool tcg_opt_gen_movi(OptContext *ctx, TCGOp *op,
433dc84988aSRichard Henderson                              TCGArg dst, uint64_t val)
4348fe35e04SRichard Henderson {
435faa2e100SRichard Henderson     /* Convert movi to mov with constant temp. */
43626aac97cSRichard Henderson     return tcg_opt_gen_mov(ctx, op, dst, arg_new_constant(ctx, val));
4378fe35e04SRichard Henderson }
4388fe35e04SRichard Henderson 
do_constant_folding_2(TCGOpcode op,uint64_t x,uint64_t y)43954795544SRichard Henderson static uint64_t do_constant_folding_2(TCGOpcode op, uint64_t x, uint64_t y)
44053108fb5SKirill Batuzov {
44103271524SRichard Henderson     uint64_t l64, h64;
44203271524SRichard Henderson 
44353108fb5SKirill Batuzov     switch (op) {
44453108fb5SKirill Batuzov     CASE_OP_32_64(add):
44553108fb5SKirill Batuzov         return x + y;
44653108fb5SKirill Batuzov 
44753108fb5SKirill Batuzov     CASE_OP_32_64(sub):
44853108fb5SKirill Batuzov         return x - y;
44953108fb5SKirill Batuzov 
45053108fb5SKirill Batuzov     CASE_OP_32_64(mul):
45153108fb5SKirill Batuzov         return x * y;
45253108fb5SKirill Batuzov 
453c578ff18SRichard Henderson     CASE_OP_32_64_VEC(and):
4549a81090bSKirill Batuzov         return x & y;
4559a81090bSKirill Batuzov 
456c578ff18SRichard Henderson     CASE_OP_32_64_VEC(or):
4579a81090bSKirill Batuzov         return x | y;
4589a81090bSKirill Batuzov 
459c578ff18SRichard Henderson     CASE_OP_32_64_VEC(xor):
4609a81090bSKirill Batuzov         return x ^ y;
4619a81090bSKirill Batuzov 
46255c0975cSKirill Batuzov     case INDEX_op_shl_i32:
46350c5c4d1SRichard Henderson         return (uint32_t)x << (y & 31);
46455c0975cSKirill Batuzov 
46555c0975cSKirill Batuzov     case INDEX_op_shl_i64:
46650c5c4d1SRichard Henderson         return (uint64_t)x << (y & 63);
46755c0975cSKirill Batuzov 
46855c0975cSKirill Batuzov     case INDEX_op_shr_i32:
46950c5c4d1SRichard Henderson         return (uint32_t)x >> (y & 31);
47055c0975cSKirill Batuzov 
47155c0975cSKirill Batuzov     case INDEX_op_shr_i64:
47250c5c4d1SRichard Henderson         return (uint64_t)x >> (y & 63);
47355c0975cSKirill Batuzov 
47455c0975cSKirill Batuzov     case INDEX_op_sar_i32:
47550c5c4d1SRichard Henderson         return (int32_t)x >> (y & 31);
47655c0975cSKirill Batuzov 
47755c0975cSKirill Batuzov     case INDEX_op_sar_i64:
47850c5c4d1SRichard Henderson         return (int64_t)x >> (y & 63);
47955c0975cSKirill Batuzov 
48055c0975cSKirill Batuzov     case INDEX_op_rotr_i32:
48150c5c4d1SRichard Henderson         return ror32(x, y & 31);
48255c0975cSKirill Batuzov 
48355c0975cSKirill Batuzov     case INDEX_op_rotr_i64:
48450c5c4d1SRichard Henderson         return ror64(x, y & 63);
48555c0975cSKirill Batuzov 
48655c0975cSKirill Batuzov     case INDEX_op_rotl_i32:
48750c5c4d1SRichard Henderson         return rol32(x, y & 31);
48855c0975cSKirill Batuzov 
48955c0975cSKirill Batuzov     case INDEX_op_rotl_i64:
49050c5c4d1SRichard Henderson         return rol64(x, y & 63);
49155c0975cSKirill Batuzov 
492c578ff18SRichard Henderson     CASE_OP_32_64_VEC(not):
493a640f031SKirill Batuzov         return ~x;
494a640f031SKirill Batuzov 
495cb25c80aSRichard Henderson     CASE_OP_32_64(neg):
496cb25c80aSRichard Henderson         return -x;
497cb25c80aSRichard Henderson 
498c578ff18SRichard Henderson     CASE_OP_32_64_VEC(andc):
499cb25c80aSRichard Henderson         return x & ~y;
500cb25c80aSRichard Henderson 
501c578ff18SRichard Henderson     CASE_OP_32_64_VEC(orc):
502cb25c80aSRichard Henderson         return x | ~y;
503cb25c80aSRichard Henderson 
504ed523473SRichard Henderson     CASE_OP_32_64_VEC(eqv):
505cb25c80aSRichard Henderson         return ~(x ^ y);
506cb25c80aSRichard Henderson 
507ed523473SRichard Henderson     CASE_OP_32_64_VEC(nand):
508cb25c80aSRichard Henderson         return ~(x & y);
509cb25c80aSRichard Henderson 
510ed523473SRichard Henderson     CASE_OP_32_64_VEC(nor):
511cb25c80aSRichard Henderson         return ~(x | y);
512cb25c80aSRichard Henderson 
5130e28d006SRichard Henderson     case INDEX_op_clz_i32:
5140e28d006SRichard Henderson         return (uint32_t)x ? clz32(x) : y;
5150e28d006SRichard Henderson 
5160e28d006SRichard Henderson     case INDEX_op_clz_i64:
5170e28d006SRichard Henderson         return x ? clz64(x) : y;
5180e28d006SRichard Henderson 
5190e28d006SRichard Henderson     case INDEX_op_ctz_i32:
5200e28d006SRichard Henderson         return (uint32_t)x ? ctz32(x) : y;
5210e28d006SRichard Henderson 
5220e28d006SRichard Henderson     case INDEX_op_ctz_i64:
5230e28d006SRichard Henderson         return x ? ctz64(x) : y;
5240e28d006SRichard Henderson 
525a768e4e9SRichard Henderson     case INDEX_op_ctpop_i32:
526a768e4e9SRichard Henderson         return ctpop32(x);
527a768e4e9SRichard Henderson 
528a768e4e9SRichard Henderson     case INDEX_op_ctpop_i64:
529a768e4e9SRichard Henderson         return ctpop64(x);
530a768e4e9SRichard Henderson 
53125c4d9ccSRichard Henderson     CASE_OP_32_64(ext8s):
532a640f031SKirill Batuzov         return (int8_t)x;
533a640f031SKirill Batuzov 
53425c4d9ccSRichard Henderson     CASE_OP_32_64(ext16s):
535a640f031SKirill Batuzov         return (int16_t)x;
536a640f031SKirill Batuzov 
53725c4d9ccSRichard Henderson     CASE_OP_32_64(ext8u):
538a640f031SKirill Batuzov         return (uint8_t)x;
539a640f031SKirill Batuzov 
54025c4d9ccSRichard Henderson     CASE_OP_32_64(ext16u):
541a640f031SKirill Batuzov         return (uint16_t)x;
542a640f031SKirill Batuzov 
5436498594cSRichard Henderson     CASE_OP_32_64(bswap16):
5440b76ff8fSRichard Henderson         x = bswap16(x);
5450b76ff8fSRichard Henderson         return y & TCG_BSWAP_OS ? (int16_t)x : x;
5466498594cSRichard Henderson 
5476498594cSRichard Henderson     CASE_OP_32_64(bswap32):
5480b76ff8fSRichard Henderson         x = bswap32(x);
5490b76ff8fSRichard Henderson         return y & TCG_BSWAP_OS ? (int32_t)x : x;
5506498594cSRichard Henderson 
5516498594cSRichard Henderson     case INDEX_op_bswap64_i64:
5526498594cSRichard Henderson         return bswap64(x);
5536498594cSRichard Henderson 
5548bcb5c8fSAurelien Jarno     case INDEX_op_ext_i32_i64:
555a640f031SKirill Batuzov     case INDEX_op_ext32s_i64:
556a640f031SKirill Batuzov         return (int32_t)x;
557a640f031SKirill Batuzov 
5588bcb5c8fSAurelien Jarno     case INDEX_op_extu_i32_i64:
559609ad705SRichard Henderson     case INDEX_op_extrl_i64_i32:
560a640f031SKirill Batuzov     case INDEX_op_ext32u_i64:
561a640f031SKirill Batuzov         return (uint32_t)x;
562a640f031SKirill Batuzov 
563609ad705SRichard Henderson     case INDEX_op_extrh_i64_i32:
564609ad705SRichard Henderson         return (uint64_t)x >> 32;
565609ad705SRichard Henderson 
56603271524SRichard Henderson     case INDEX_op_muluh_i32:
56703271524SRichard Henderson         return ((uint64_t)(uint32_t)x * (uint32_t)y) >> 32;
56803271524SRichard Henderson     case INDEX_op_mulsh_i32:
56903271524SRichard Henderson         return ((int64_t)(int32_t)x * (int32_t)y) >> 32;
57003271524SRichard Henderson 
57103271524SRichard Henderson     case INDEX_op_muluh_i64:
57203271524SRichard Henderson         mulu64(&l64, &h64, x, y);
57303271524SRichard Henderson         return h64;
57403271524SRichard Henderson     case INDEX_op_mulsh_i64:
57503271524SRichard Henderson         muls64(&l64, &h64, x, y);
57603271524SRichard Henderson         return h64;
57703271524SRichard Henderson 
57801547f7fSRichard Henderson     case INDEX_op_div_i32:
57901547f7fSRichard Henderson         /* Avoid crashing on divide by zero, otherwise undefined.  */
58001547f7fSRichard Henderson         return (int32_t)x / ((int32_t)y ? : 1);
58101547f7fSRichard Henderson     case INDEX_op_divu_i32:
58201547f7fSRichard Henderson         return (uint32_t)x / ((uint32_t)y ? : 1);
58301547f7fSRichard Henderson     case INDEX_op_div_i64:
58401547f7fSRichard Henderson         return (int64_t)x / ((int64_t)y ? : 1);
58501547f7fSRichard Henderson     case INDEX_op_divu_i64:
58601547f7fSRichard Henderson         return (uint64_t)x / ((uint64_t)y ? : 1);
58701547f7fSRichard Henderson 
58801547f7fSRichard Henderson     case INDEX_op_rem_i32:
58901547f7fSRichard Henderson         return (int32_t)x % ((int32_t)y ? : 1);
59001547f7fSRichard Henderson     case INDEX_op_remu_i32:
59101547f7fSRichard Henderson         return (uint32_t)x % ((uint32_t)y ? : 1);
59201547f7fSRichard Henderson     case INDEX_op_rem_i64:
59301547f7fSRichard Henderson         return (int64_t)x % ((int64_t)y ? : 1);
59401547f7fSRichard Henderson     case INDEX_op_remu_i64:
59501547f7fSRichard Henderson         return (uint64_t)x % ((uint64_t)y ? : 1);
59601547f7fSRichard Henderson 
59753108fb5SKirill Batuzov     default:
598732e89f4SRichard Henderson         g_assert_not_reached();
59953108fb5SKirill Batuzov     }
60053108fb5SKirill Batuzov }
60153108fb5SKirill Batuzov 
do_constant_folding(TCGOpcode op,TCGType type,uint64_t x,uint64_t y)60267f84c96SRichard Henderson static uint64_t do_constant_folding(TCGOpcode op, TCGType type,
60367f84c96SRichard Henderson                                     uint64_t x, uint64_t y)
60453108fb5SKirill Batuzov {
60554795544SRichard Henderson     uint64_t res = do_constant_folding_2(op, x, y);
60667f84c96SRichard Henderson     if (type == TCG_TYPE_I32) {
60729f3ff8dSAurelien Jarno         res = (int32_t)res;
60853108fb5SKirill Batuzov     }
60953108fb5SKirill Batuzov     return res;
61053108fb5SKirill Batuzov }
61153108fb5SKirill Batuzov 
do_constant_folding_cond_32(uint32_t x,uint32_t y,TCGCond c)6129519da7eSRichard Henderson static bool do_constant_folding_cond_32(uint32_t x, uint32_t y, TCGCond c)
613f8dd19e5SAurelien Jarno {
614f8dd19e5SAurelien Jarno     switch (c) {
615f8dd19e5SAurelien Jarno     case TCG_COND_EQ:
6169519da7eSRichard Henderson         return x == y;
617f8dd19e5SAurelien Jarno     case TCG_COND_NE:
6189519da7eSRichard Henderson         return x != y;
619f8dd19e5SAurelien Jarno     case TCG_COND_LT:
6209519da7eSRichard Henderson         return (int32_t)x < (int32_t)y;
621f8dd19e5SAurelien Jarno     case TCG_COND_GE:
6229519da7eSRichard Henderson         return (int32_t)x >= (int32_t)y;
623f8dd19e5SAurelien Jarno     case TCG_COND_LE:
6249519da7eSRichard Henderson         return (int32_t)x <= (int32_t)y;
625f8dd19e5SAurelien Jarno     case TCG_COND_GT:
6269519da7eSRichard Henderson         return (int32_t)x > (int32_t)y;
627f8dd19e5SAurelien Jarno     case TCG_COND_LTU:
6289519da7eSRichard Henderson         return x < y;
629f8dd19e5SAurelien Jarno     case TCG_COND_GEU:
6309519da7eSRichard Henderson         return x >= y;
631f8dd19e5SAurelien Jarno     case TCG_COND_LEU:
6329519da7eSRichard Henderson         return x <= y;
633f8dd19e5SAurelien Jarno     case TCG_COND_GTU:
6349519da7eSRichard Henderson         return x > y;
635ceb9ee06SRichard Henderson     case TCG_COND_TSTEQ:
636ceb9ee06SRichard Henderson         return (x & y) == 0;
637ceb9ee06SRichard Henderson     case TCG_COND_TSTNE:
638ceb9ee06SRichard Henderson         return (x & y) != 0;
639ceb9ee06SRichard Henderson     case TCG_COND_ALWAYS:
640ceb9ee06SRichard Henderson     case TCG_COND_NEVER:
641ceb9ee06SRichard Henderson         break;
642f8dd19e5SAurelien Jarno     }
643ceb9ee06SRichard Henderson     g_assert_not_reached();
6449519da7eSRichard Henderson }
6459519da7eSRichard Henderson 
do_constant_folding_cond_64(uint64_t x,uint64_t y,TCGCond c)6469519da7eSRichard Henderson static bool do_constant_folding_cond_64(uint64_t x, uint64_t y, TCGCond c)
6479519da7eSRichard Henderson {
648f8dd19e5SAurelien Jarno     switch (c) {
649f8dd19e5SAurelien Jarno     case TCG_COND_EQ:
6509519da7eSRichard Henderson         return x == y;
651f8dd19e5SAurelien Jarno     case TCG_COND_NE:
6529519da7eSRichard Henderson         return x != y;
653f8dd19e5SAurelien Jarno     case TCG_COND_LT:
6549519da7eSRichard Henderson         return (int64_t)x < (int64_t)y;
655f8dd19e5SAurelien Jarno     case TCG_COND_GE:
6569519da7eSRichard Henderson         return (int64_t)x >= (int64_t)y;
657f8dd19e5SAurelien Jarno     case TCG_COND_LE:
6589519da7eSRichard Henderson         return (int64_t)x <= (int64_t)y;
659f8dd19e5SAurelien Jarno     case TCG_COND_GT:
6609519da7eSRichard Henderson         return (int64_t)x > (int64_t)y;
661f8dd19e5SAurelien Jarno     case TCG_COND_LTU:
6629519da7eSRichard Henderson         return x < y;
663f8dd19e5SAurelien Jarno     case TCG_COND_GEU:
6649519da7eSRichard Henderson         return x >= y;
665f8dd19e5SAurelien Jarno     case TCG_COND_LEU:
6669519da7eSRichard Henderson         return x <= y;
667f8dd19e5SAurelien Jarno     case TCG_COND_GTU:
6689519da7eSRichard Henderson         return x > y;
669ceb9ee06SRichard Henderson     case TCG_COND_TSTEQ:
670ceb9ee06SRichard Henderson         return (x & y) == 0;
671ceb9ee06SRichard Henderson     case TCG_COND_TSTNE:
672ceb9ee06SRichard Henderson         return (x & y) != 0;
673ceb9ee06SRichard Henderson     case TCG_COND_ALWAYS:
674ceb9ee06SRichard Henderson     case TCG_COND_NEVER:
675ceb9ee06SRichard Henderson         break;
676ceb9ee06SRichard Henderson     }
677732e89f4SRichard Henderson     g_assert_not_reached();
678f8dd19e5SAurelien Jarno }
6799519da7eSRichard Henderson 
do_constant_folding_cond_eq(TCGCond c)680ceb9ee06SRichard Henderson static int do_constant_folding_cond_eq(TCGCond c)
6819519da7eSRichard Henderson {
682b336ceb6SAurelien Jarno     switch (c) {
683b336ceb6SAurelien Jarno     case TCG_COND_GT:
684b336ceb6SAurelien Jarno     case TCG_COND_LTU:
685b336ceb6SAurelien Jarno     case TCG_COND_LT:
686b336ceb6SAurelien Jarno     case TCG_COND_GTU:
687b336ceb6SAurelien Jarno     case TCG_COND_NE:
688b336ceb6SAurelien Jarno         return 0;
689b336ceb6SAurelien Jarno     case TCG_COND_GE:
690b336ceb6SAurelien Jarno     case TCG_COND_GEU:
691b336ceb6SAurelien Jarno     case TCG_COND_LE:
692b336ceb6SAurelien Jarno     case TCG_COND_LEU:
693b336ceb6SAurelien Jarno     case TCG_COND_EQ:
694b336ceb6SAurelien Jarno         return 1;
695ceb9ee06SRichard Henderson     case TCG_COND_TSTEQ:
696ceb9ee06SRichard Henderson     case TCG_COND_TSTNE:
697ceb9ee06SRichard Henderson         return -1;
698ceb9ee06SRichard Henderson     case TCG_COND_ALWAYS:
699ceb9ee06SRichard Henderson     case TCG_COND_NEVER:
700ceb9ee06SRichard Henderson         break;
701b336ceb6SAurelien Jarno     }
702ceb9ee06SRichard Henderson     g_assert_not_reached();
7039519da7eSRichard Henderson }
7049519da7eSRichard Henderson 
7058d57bf1eSRichard Henderson /*
7068d57bf1eSRichard Henderson  * Return -1 if the condition can't be simplified,
7078d57bf1eSRichard Henderson  * and the result of the condition (0 or 1) if it can.
7088d57bf1eSRichard Henderson  */
do_constant_folding_cond(TCGType type,TCGArg x,TCGArg y,TCGCond c)70967f84c96SRichard Henderson static int do_constant_folding_cond(TCGType type, TCGArg x,
7109519da7eSRichard Henderson                                     TCGArg y, TCGCond c)
7119519da7eSRichard Henderson {
7129becc36fSAlex Bennée     if (arg_is_const(x) && arg_is_const(y)) {
71354795544SRichard Henderson         uint64_t xv = arg_info(x)->val;
71454795544SRichard Henderson         uint64_t yv = arg_info(y)->val;
71554795544SRichard Henderson 
71667f84c96SRichard Henderson         switch (type) {
71767f84c96SRichard Henderson         case TCG_TYPE_I32:
718170ba88fSRichard Henderson             return do_constant_folding_cond_32(xv, yv, c);
71967f84c96SRichard Henderson         case TCG_TYPE_I64:
72067f84c96SRichard Henderson             return do_constant_folding_cond_64(xv, yv, c);
72167f84c96SRichard Henderson         default:
72267f84c96SRichard Henderson             /* Only scalar comparisons are optimizable */
72367f84c96SRichard Henderson             return -1;
7249519da7eSRichard Henderson         }
7256349039dSRichard Henderson     } else if (args_are_copies(x, y)) {
7269519da7eSRichard Henderson         return do_constant_folding_cond_eq(c);
72727cdb85dSRichard Henderson     } else if (arg_is_const_val(y, 0)) {
728b336ceb6SAurelien Jarno         switch (c) {
729b336ceb6SAurelien Jarno         case TCG_COND_LTU:
730ceb9ee06SRichard Henderson         case TCG_COND_TSTNE:
731b336ceb6SAurelien Jarno             return 0;
732b336ceb6SAurelien Jarno         case TCG_COND_GEU:
733ceb9ee06SRichard Henderson         case TCG_COND_TSTEQ:
734b336ceb6SAurelien Jarno             return 1;
735b336ceb6SAurelien Jarno         default:
7368d57bf1eSRichard Henderson             return -1;
737b336ceb6SAurelien Jarno         }
738b336ceb6SAurelien Jarno     }
7398d57bf1eSRichard Henderson     return -1;
740f8dd19e5SAurelien Jarno }
741f8dd19e5SAurelien Jarno 
7427a2f7084SRichard Henderson /**
7437a2f7084SRichard Henderson  * swap_commutative:
7447a2f7084SRichard Henderson  * @dest: TCGArg of the destination argument, or NO_DEST.
7457a2f7084SRichard Henderson  * @p1: first paired argument
7467a2f7084SRichard Henderson  * @p2: second paired argument
7477a2f7084SRichard Henderson  *
7487a2f7084SRichard Henderson  * If *@p1 is a constant and *@p2 is not, swap.
7497a2f7084SRichard Henderson  * If *@p2 matches @dest, swap.
7507a2f7084SRichard Henderson  * Return true if a swap was performed.
7517a2f7084SRichard Henderson  */
7527a2f7084SRichard Henderson 
7537a2f7084SRichard Henderson #define NO_DEST  temp_arg(NULL)
7547a2f7084SRichard Henderson 
swap_commutative(TCGArg dest,TCGArg * p1,TCGArg * p2)75524c9ae4eSRichard Henderson static bool swap_commutative(TCGArg dest, TCGArg *p1, TCGArg *p2)
75624c9ae4eSRichard Henderson {
75724c9ae4eSRichard Henderson     TCGArg a1 = *p1, a2 = *p2;
75824c9ae4eSRichard Henderson     int sum = 0;
7596349039dSRichard Henderson     sum += arg_is_const(a1);
7606349039dSRichard Henderson     sum -= arg_is_const(a2);
76124c9ae4eSRichard Henderson 
76224c9ae4eSRichard Henderson     /* Prefer the constant in second argument, and then the form
76324c9ae4eSRichard Henderson        op a, a, b, which is better handled on non-RISC hosts. */
76424c9ae4eSRichard Henderson     if (sum > 0 || (sum == 0 && dest == a2)) {
76524c9ae4eSRichard Henderson         *p1 = a2;
76624c9ae4eSRichard Henderson         *p2 = a1;
76724c9ae4eSRichard Henderson         return true;
76824c9ae4eSRichard Henderson     }
76924c9ae4eSRichard Henderson     return false;
77024c9ae4eSRichard Henderson }
77124c9ae4eSRichard Henderson 
swap_commutative2(TCGArg * p1,TCGArg * p2)7720bfcb865SRichard Henderson static bool swap_commutative2(TCGArg *p1, TCGArg *p2)
7730bfcb865SRichard Henderson {
7740bfcb865SRichard Henderson     int sum = 0;
7756349039dSRichard Henderson     sum += arg_is_const(p1[0]);
7766349039dSRichard Henderson     sum += arg_is_const(p1[1]);
7776349039dSRichard Henderson     sum -= arg_is_const(p2[0]);
7786349039dSRichard Henderson     sum -= arg_is_const(p2[1]);
7790bfcb865SRichard Henderson     if (sum > 0) {
7800bfcb865SRichard Henderson         TCGArg t;
7810bfcb865SRichard Henderson         t = p1[0], p1[0] = p2[0], p2[0] = t;
7820bfcb865SRichard Henderson         t = p1[1], p1[1] = p2[1], p2[1] = t;
7830bfcb865SRichard Henderson         return true;
7840bfcb865SRichard Henderson     }
7850bfcb865SRichard Henderson     return false;
7860bfcb865SRichard Henderson }
7870bfcb865SRichard Henderson 
7887e64b114SRichard Henderson /*
7897e64b114SRichard Henderson  * Return -1 if the condition can't be simplified,
7907e64b114SRichard Henderson  * and the result of the condition (0 or 1) if it can.
7917e64b114SRichard Henderson  */
do_constant_folding_cond1(OptContext * ctx,TCGOp * op,TCGArg dest,TCGArg * p1,TCGArg * p2,TCGArg * pcond)792fb04ab7dSRichard Henderson static int do_constant_folding_cond1(OptContext *ctx, TCGOp *op, TCGArg dest,
793246c4b72SRichard Henderson                                      TCGArg *p1, TCGArg *p2, TCGArg *pcond)
794246c4b72SRichard Henderson {
795246c4b72SRichard Henderson     TCGCond cond;
796246c4b72SRichard Henderson     bool swap;
797246c4b72SRichard Henderson     int r;
798246c4b72SRichard Henderson 
799246c4b72SRichard Henderson     swap = swap_commutative(dest, p1, p2);
800246c4b72SRichard Henderson     cond = *pcond;
801246c4b72SRichard Henderson     if (swap) {
802246c4b72SRichard Henderson         *pcond = cond = tcg_swap_cond(cond);
803246c4b72SRichard Henderson     }
804246c4b72SRichard Henderson 
805246c4b72SRichard Henderson     r = do_constant_folding_cond(ctx->type, *p1, *p2, cond);
806ceb9ee06SRichard Henderson     if (r >= 0) {
807246c4b72SRichard Henderson         return r;
808246c4b72SRichard Henderson     }
809ceb9ee06SRichard Henderson     if (!is_tst_cond(cond)) {
810ceb9ee06SRichard Henderson         return -1;
811ceb9ee06SRichard Henderson     }
812ceb9ee06SRichard Henderson 
813ceb9ee06SRichard Henderson     /*
814ceb9ee06SRichard Henderson      * TSTNE x,x -> NE x,0
815ceb9ee06SRichard Henderson      * TSTNE x,-1 -> NE x,0
816ceb9ee06SRichard Henderson      */
817ceb9ee06SRichard Henderson     if (args_are_copies(*p1, *p2) || arg_is_const_val(*p2, -1)) {
818ceb9ee06SRichard Henderson         *p2 = arg_new_constant(ctx, 0);
819ceb9ee06SRichard Henderson         *pcond = tcg_tst_eqne_cond(cond);
820ceb9ee06SRichard Henderson         return -1;
821ceb9ee06SRichard Henderson     }
822ceb9ee06SRichard Henderson 
823ceb9ee06SRichard Henderson     /* TSTNE x,sign -> LT x,0 */
824ceb9ee06SRichard Henderson     if (arg_is_const_val(*p2, (ctx->type == TCG_TYPE_I32
825ceb9ee06SRichard Henderson                                ? INT32_MIN : INT64_MIN))) {
826ceb9ee06SRichard Henderson         *p2 = arg_new_constant(ctx, 0);
827ceb9ee06SRichard Henderson         *pcond = tcg_tst_ltge_cond(cond);
828fb04ab7dSRichard Henderson         return -1;
829fb04ab7dSRichard Henderson     }
830fb04ab7dSRichard Henderson 
831fb04ab7dSRichard Henderson     /* Expand to AND with a temporary if no backend support. */
832fb04ab7dSRichard Henderson     if (!TCG_TARGET_HAS_tst) {
833fb04ab7dSRichard Henderson         TCGOpcode and_opc = (ctx->type == TCG_TYPE_I32
834fb04ab7dSRichard Henderson                              ? INDEX_op_and_i32 : INDEX_op_and_i64);
835fb04ab7dSRichard Henderson         TCGOp *op2 = tcg_op_insert_before(ctx->tcg, op, and_opc, 3);
836fb04ab7dSRichard Henderson         TCGArg tmp = arg_new_temp(ctx);
837fb04ab7dSRichard Henderson 
838fb04ab7dSRichard Henderson         op2->args[0] = tmp;
839fb04ab7dSRichard Henderson         op2->args[1] = *p1;
840fb04ab7dSRichard Henderson         op2->args[2] = *p2;
841fb04ab7dSRichard Henderson 
842fb04ab7dSRichard Henderson         *p1 = tmp;
843fb04ab7dSRichard Henderson         *p2 = arg_new_constant(ctx, 0);
844fb04ab7dSRichard Henderson         *pcond = tcg_tst_eqne_cond(cond);
845ceb9ee06SRichard Henderson     }
846ceb9ee06SRichard Henderson     return -1;
847ceb9ee06SRichard Henderson }
848246c4b72SRichard Henderson 
do_constant_folding_cond2(OptContext * ctx,TCGOp * op,TCGArg * args)849fb04ab7dSRichard Henderson static int do_constant_folding_cond2(OptContext *ctx, TCGOp *op, TCGArg *args)
8507e64b114SRichard Henderson {
8517e64b114SRichard Henderson     TCGArg al, ah, bl, bh;
8527e64b114SRichard Henderson     TCGCond c;
8537e64b114SRichard Henderson     bool swap;
854ceb9ee06SRichard Henderson     int r;
8557e64b114SRichard Henderson 
8567e64b114SRichard Henderson     swap = swap_commutative2(args, args + 2);
8577e64b114SRichard Henderson     c = args[4];
8587e64b114SRichard Henderson     if (swap) {
8597e64b114SRichard Henderson         args[4] = c = tcg_swap_cond(c);
8607e64b114SRichard Henderson     }
8617e64b114SRichard Henderson 
8627e64b114SRichard Henderson     al = args[0];
8637e64b114SRichard Henderson     ah = args[1];
8647e64b114SRichard Henderson     bl = args[2];
8657e64b114SRichard Henderson     bh = args[3];
8667e64b114SRichard Henderson 
8677e64b114SRichard Henderson     if (arg_is_const(bl) && arg_is_const(bh)) {
8687e64b114SRichard Henderson         tcg_target_ulong blv = arg_info(bl)->val;
8697e64b114SRichard Henderson         tcg_target_ulong bhv = arg_info(bh)->val;
8707e64b114SRichard Henderson         uint64_t b = deposit64(blv, 32, 32, bhv);
8717e64b114SRichard Henderson 
8727e64b114SRichard Henderson         if (arg_is_const(al) && arg_is_const(ah)) {
8737e64b114SRichard Henderson             tcg_target_ulong alv = arg_info(al)->val;
8747e64b114SRichard Henderson             tcg_target_ulong ahv = arg_info(ah)->val;
8757e64b114SRichard Henderson             uint64_t a = deposit64(alv, 32, 32, ahv);
876ceb9ee06SRichard Henderson 
877ceb9ee06SRichard Henderson             r = do_constant_folding_cond_64(a, b, c);
878ceb9ee06SRichard Henderson             if (r >= 0) {
879ceb9ee06SRichard Henderson                 return r;
8807e64b114SRichard Henderson             }
881ceb9ee06SRichard Henderson         }
882ceb9ee06SRichard Henderson 
8837e64b114SRichard Henderson         if (b == 0) {
8847e64b114SRichard Henderson             switch (c) {
8857e64b114SRichard Henderson             case TCG_COND_LTU:
886ceb9ee06SRichard Henderson             case TCG_COND_TSTNE:
8877e64b114SRichard Henderson                 return 0;
8887e64b114SRichard Henderson             case TCG_COND_GEU:
889ceb9ee06SRichard Henderson             case TCG_COND_TSTEQ:
8907e64b114SRichard Henderson                 return 1;
8917e64b114SRichard Henderson             default:
8927e64b114SRichard Henderson                 break;
8937e64b114SRichard Henderson             }
8947e64b114SRichard Henderson         }
895ceb9ee06SRichard Henderson 
896ceb9ee06SRichard Henderson         /* TSTNE x,-1 -> NE x,0 */
897ceb9ee06SRichard Henderson         if (b == -1 && is_tst_cond(c)) {
898ceb9ee06SRichard Henderson             args[3] = args[2] = arg_new_constant(ctx, 0);
899ceb9ee06SRichard Henderson             args[4] = tcg_tst_eqne_cond(c);
900ceb9ee06SRichard Henderson             return -1;
9017e64b114SRichard Henderson         }
902ceb9ee06SRichard Henderson 
903ceb9ee06SRichard Henderson         /* TSTNE x,sign -> LT x,0 */
904ceb9ee06SRichard Henderson         if (b == INT64_MIN && is_tst_cond(c)) {
905ceb9ee06SRichard Henderson             /* bl must be 0, so copy that to bh */
906ceb9ee06SRichard Henderson             args[3] = bl;
907ceb9ee06SRichard Henderson             args[4] = tcg_tst_ltge_cond(c);
908ceb9ee06SRichard Henderson             return -1;
909ceb9ee06SRichard Henderson         }
910ceb9ee06SRichard Henderson     }
911ceb9ee06SRichard Henderson 
9127e64b114SRichard Henderson     if (args_are_copies(al, bl) && args_are_copies(ah, bh)) {
913ceb9ee06SRichard Henderson         r = do_constant_folding_cond_eq(c);
914ceb9ee06SRichard Henderson         if (r >= 0) {
915ceb9ee06SRichard Henderson             return r;
916ceb9ee06SRichard Henderson         }
917ceb9ee06SRichard Henderson 
918ceb9ee06SRichard Henderson         /* TSTNE x,x -> NE x,0 */
919ceb9ee06SRichard Henderson         if (is_tst_cond(c)) {
920ceb9ee06SRichard Henderson             args[3] = args[2] = arg_new_constant(ctx, 0);
921ceb9ee06SRichard Henderson             args[4] = tcg_tst_eqne_cond(c);
922ceb9ee06SRichard Henderson             return -1;
923ceb9ee06SRichard Henderson         }
9247e64b114SRichard Henderson     }
925fb04ab7dSRichard Henderson 
926fb04ab7dSRichard Henderson     /* Expand to AND with a temporary if no backend support. */
927fb04ab7dSRichard Henderson     if (!TCG_TARGET_HAS_tst && is_tst_cond(c)) {
928fb04ab7dSRichard Henderson         TCGOp *op1 = tcg_op_insert_before(ctx->tcg, op, INDEX_op_and_i32, 3);
929fb04ab7dSRichard Henderson         TCGOp *op2 = tcg_op_insert_before(ctx->tcg, op, INDEX_op_and_i32, 3);
930fb04ab7dSRichard Henderson         TCGArg t1 = arg_new_temp(ctx);
931fb04ab7dSRichard Henderson         TCGArg t2 = arg_new_temp(ctx);
932fb04ab7dSRichard Henderson 
933fb04ab7dSRichard Henderson         op1->args[0] = t1;
934fb04ab7dSRichard Henderson         op1->args[1] = al;
935fb04ab7dSRichard Henderson         op1->args[2] = bl;
936fb04ab7dSRichard Henderson         op2->args[0] = t2;
937fb04ab7dSRichard Henderson         op2->args[1] = ah;
938fb04ab7dSRichard Henderson         op2->args[2] = bh;
939fb04ab7dSRichard Henderson 
940fb04ab7dSRichard Henderson         args[0] = t1;
941fb04ab7dSRichard Henderson         args[1] = t2;
942fb04ab7dSRichard Henderson         args[3] = args[2] = arg_new_constant(ctx, 0);
943fb04ab7dSRichard Henderson         args[4] = tcg_tst_eqne_cond(c);
944fb04ab7dSRichard Henderson     }
9457e64b114SRichard Henderson     return -1;
9467e64b114SRichard Henderson }
9477e64b114SRichard Henderson 
init_arguments(OptContext * ctx,TCGOp * op,int nb_args)948e2577ea2SRichard Henderson static void init_arguments(OptContext *ctx, TCGOp *op, int nb_args)
949e2577ea2SRichard Henderson {
950e2577ea2SRichard Henderson     for (int i = 0; i < nb_args; i++) {
951e2577ea2SRichard Henderson         TCGTemp *ts = arg_temp(op->args[i]);
952e2577ea2SRichard Henderson         init_ts_info(ctx, ts);
953e2577ea2SRichard Henderson     }
954e2577ea2SRichard Henderson }
955e2577ea2SRichard Henderson 
copy_propagate(OptContext * ctx,TCGOp * op,int nb_oargs,int nb_iargs)9568774ddedSRichard Henderson static void copy_propagate(OptContext *ctx, TCGOp *op,
9578774ddedSRichard Henderson                            int nb_oargs, int nb_iargs)
9588774ddedSRichard Henderson {
9598774ddedSRichard Henderson     for (int i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
9608774ddedSRichard Henderson         TCGTemp *ts = arg_temp(op->args[i]);
96139004a71SRichard Henderson         if (ts_is_copy(ts)) {
9629f75e528SRichard Henderson             op->args[i] = temp_arg(find_better_copy(ts));
9638774ddedSRichard Henderson         }
9648774ddedSRichard Henderson     }
9658774ddedSRichard Henderson }
9668774ddedSRichard Henderson 
finish_folding(OptContext * ctx,TCGOp * op)967137f1f44SRichard Henderson static void finish_folding(OptContext *ctx, TCGOp *op)
968137f1f44SRichard Henderson {
969137f1f44SRichard Henderson     const TCGOpDef *def = &tcg_op_defs[op->opc];
970137f1f44SRichard Henderson     int i, nb_oargs;
971137f1f44SRichard Henderson 
972137f1f44SRichard Henderson     /*
973d97f8f39SRichard Henderson      * We only optimize extended basic blocks.  If the opcode ends a BB
974d97f8f39SRichard Henderson      * and is not a conditional branch, reset all temp data.
975137f1f44SRichard Henderson      */
976137f1f44SRichard Henderson     if (def->flags & TCG_OPF_BB_END) {
977137f1f44SRichard Henderson         ctx->prev_mb = NULL;
978d97f8f39SRichard Henderson         if (!(def->flags & TCG_OPF_COND_BRANCH)) {
979d97f8f39SRichard Henderson             memset(&ctx->temps_used, 0, sizeof(ctx->temps_used));
980ab84dc39SRichard Henderson             remove_mem_copy_all(ctx);
981d97f8f39SRichard Henderson         }
982137f1f44SRichard Henderson         return;
983137f1f44SRichard Henderson     }
984137f1f44SRichard Henderson 
985137f1f44SRichard Henderson     nb_oargs = def->nb_oargs;
986137f1f44SRichard Henderson     for (i = 0; i < nb_oargs; i++) {
98757fe5c6dSRichard Henderson         TCGTemp *ts = arg_temp(op->args[i]);
988986cac1dSRichard Henderson         reset_ts(ctx, ts);
989137f1f44SRichard Henderson         /*
99057fe5c6dSRichard Henderson          * Save the corresponding known-zero/sign bits mask for the
991137f1f44SRichard Henderson          * first output argument (only one supported so far).
992137f1f44SRichard Henderson          */
993137f1f44SRichard Henderson         if (i == 0) {
99457fe5c6dSRichard Henderson             ts_info(ts)->z_mask = ctx->z_mask;
99557fe5c6dSRichard Henderson             ts_info(ts)->s_mask = ctx->s_mask;
996137f1f44SRichard Henderson         }
997137f1f44SRichard Henderson     }
998137f1f44SRichard Henderson }
999137f1f44SRichard Henderson 
10002f9f08baSRichard Henderson /*
10012f9f08baSRichard Henderson  * The fold_* functions return true when processing is complete,
10022f9f08baSRichard Henderson  * usually by folding the operation to a constant or to a copy,
10032f9f08baSRichard Henderson  * and calling tcg_opt_gen_{mov,movi}.  They may do other things,
10042f9f08baSRichard Henderson  * like collect information about the value produced, for use in
10052f9f08baSRichard Henderson  * optimizing a subsequent operation.
10062f9f08baSRichard Henderson  *
10072f9f08baSRichard Henderson  * These first fold_* functions are all helpers, used by other
10082f9f08baSRichard Henderson  * folders for more specific operations.
10092f9f08baSRichard Henderson  */
10102f9f08baSRichard Henderson 
fold_const1(OptContext * ctx,TCGOp * op)10112f9f08baSRichard Henderson static bool fold_const1(OptContext *ctx, TCGOp *op)
10122f9f08baSRichard Henderson {
10132f9f08baSRichard Henderson     if (arg_is_const(op->args[1])) {
10142f9f08baSRichard Henderson         uint64_t t;
10152f9f08baSRichard Henderson 
10162f9f08baSRichard Henderson         t = arg_info(op->args[1])->val;
101767f84c96SRichard Henderson         t = do_constant_folding(op->opc, ctx->type, t, 0);
10182f9f08baSRichard Henderson         return tcg_opt_gen_movi(ctx, op, op->args[0], t);
10192f9f08baSRichard Henderson     }
10202f9f08baSRichard Henderson     return false;
10212f9f08baSRichard Henderson }
10222f9f08baSRichard Henderson 
fold_const2(OptContext * ctx,TCGOp * op)10232f9f08baSRichard Henderson static bool fold_const2(OptContext *ctx, TCGOp *op)
10242f9f08baSRichard Henderson {
10252f9f08baSRichard Henderson     if (arg_is_const(op->args[1]) && arg_is_const(op->args[2])) {
10262f9f08baSRichard Henderson         uint64_t t1 = arg_info(op->args[1])->val;
10272f9f08baSRichard Henderson         uint64_t t2 = arg_info(op->args[2])->val;
10282f9f08baSRichard Henderson 
102967f84c96SRichard Henderson         t1 = do_constant_folding(op->opc, ctx->type, t1, t2);
10302f9f08baSRichard Henderson         return tcg_opt_gen_movi(ctx, op, op->args[0], t1);
10312f9f08baSRichard Henderson     }
10322f9f08baSRichard Henderson     return false;
10332f9f08baSRichard Henderson }
10342f9f08baSRichard Henderson 
fold_commutative(OptContext * ctx,TCGOp * op)1035c578ff18SRichard Henderson static bool fold_commutative(OptContext *ctx, TCGOp *op)
1036c578ff18SRichard Henderson {
1037c578ff18SRichard Henderson     swap_commutative(op->args[0], &op->args[1], &op->args[2]);
1038c578ff18SRichard Henderson     return false;
1039c578ff18SRichard Henderson }
1040c578ff18SRichard Henderson 
fold_const2_commutative(OptContext * ctx,TCGOp * op)10417a2f7084SRichard Henderson static bool fold_const2_commutative(OptContext *ctx, TCGOp *op)
10427a2f7084SRichard Henderson {
10437a2f7084SRichard Henderson     swap_commutative(op->args[0], &op->args[1], &op->args[2]);
10447a2f7084SRichard Henderson     return fold_const2(ctx, op);
10457a2f7084SRichard Henderson }
10467a2f7084SRichard Henderson 
fold_masks(OptContext * ctx,TCGOp * op)1047fae450baSRichard Henderson static bool fold_masks(OptContext *ctx, TCGOp *op)
1048fae450baSRichard Henderson {
1049fae450baSRichard Henderson     uint64_t a_mask = ctx->a_mask;
1050fae450baSRichard Henderson     uint64_t z_mask = ctx->z_mask;
105157fe5c6dSRichard Henderson     uint64_t s_mask = ctx->s_mask;
1052fae450baSRichard Henderson 
1053fae450baSRichard Henderson     /*
1054faa2e100SRichard Henderson      * 32-bit ops generate 32-bit results, which for the purpose of
1055faa2e100SRichard Henderson      * simplifying tcg are sign-extended.  Certainly that's how we
1056faa2e100SRichard Henderson      * represent our constants elsewhere.  Note that the bits will
1057faa2e100SRichard Henderson      * be reset properly for a 64-bit value when encountering the
1058faa2e100SRichard Henderson      * type changing opcodes.
1059fae450baSRichard Henderson      */
1060fae450baSRichard Henderson     if (ctx->type == TCG_TYPE_I32) {
1061faa2e100SRichard Henderson         a_mask = (int32_t)a_mask;
1062faa2e100SRichard Henderson         z_mask = (int32_t)z_mask;
106357fe5c6dSRichard Henderson         s_mask |= MAKE_64BIT_MASK(32, 32);
1064faa2e100SRichard Henderson         ctx->z_mask = z_mask;
106557fe5c6dSRichard Henderson         ctx->s_mask = s_mask;
1066fae450baSRichard Henderson     }
1067fae450baSRichard Henderson 
1068fae450baSRichard Henderson     if (z_mask == 0) {
1069fae450baSRichard Henderson         return tcg_opt_gen_movi(ctx, op, op->args[0], 0);
1070fae450baSRichard Henderson     }
1071fae450baSRichard Henderson     if (a_mask == 0) {
1072fae450baSRichard Henderson         return tcg_opt_gen_mov(ctx, op, op->args[0], op->args[1]);
1073fae450baSRichard Henderson     }
1074fae450baSRichard Henderson     return false;
1075fae450baSRichard Henderson }
1076fae450baSRichard Henderson 
10770e0a32baSRichard Henderson /*
10780e0a32baSRichard Henderson  * Convert @op to NOT, if NOT is supported by the host.
10790e0a32baSRichard Henderson  * Return true f the conversion is successful, which will still
10800e0a32baSRichard Henderson  * indicate that the processing is complete.
10810e0a32baSRichard Henderson  */
10820e0a32baSRichard Henderson static bool fold_not(OptContext *ctx, TCGOp *op);
fold_to_not(OptContext * ctx,TCGOp * op,int idx)10830e0a32baSRichard Henderson static bool fold_to_not(OptContext *ctx, TCGOp *op, int idx)
10840e0a32baSRichard Henderson {
10850e0a32baSRichard Henderson     TCGOpcode not_op;
10860e0a32baSRichard Henderson     bool have_not;
10870e0a32baSRichard Henderson 
10880e0a32baSRichard Henderson     switch (ctx->type) {
10890e0a32baSRichard Henderson     case TCG_TYPE_I32:
10900e0a32baSRichard Henderson         not_op = INDEX_op_not_i32;
10910e0a32baSRichard Henderson         have_not = TCG_TARGET_HAS_not_i32;
10920e0a32baSRichard Henderson         break;
10930e0a32baSRichard Henderson     case TCG_TYPE_I64:
10940e0a32baSRichard Henderson         not_op = INDEX_op_not_i64;
10950e0a32baSRichard Henderson         have_not = TCG_TARGET_HAS_not_i64;
10960e0a32baSRichard Henderson         break;
10970e0a32baSRichard Henderson     case TCG_TYPE_V64:
10980e0a32baSRichard Henderson     case TCG_TYPE_V128:
10990e0a32baSRichard Henderson     case TCG_TYPE_V256:
11000e0a32baSRichard Henderson         not_op = INDEX_op_not_vec;
11010e0a32baSRichard Henderson         have_not = TCG_TARGET_HAS_not_vec;
11020e0a32baSRichard Henderson         break;
11030e0a32baSRichard Henderson     default:
11040e0a32baSRichard Henderson         g_assert_not_reached();
11050e0a32baSRichard Henderson     }
11060e0a32baSRichard Henderson     if (have_not) {
11070e0a32baSRichard Henderson         op->opc = not_op;
11080e0a32baSRichard Henderson         op->args[1] = op->args[idx];
11090e0a32baSRichard Henderson         return fold_not(ctx, op);
11100e0a32baSRichard Henderson     }
11110e0a32baSRichard Henderson     return false;
11120e0a32baSRichard Henderson }
11130e0a32baSRichard Henderson 
1114da48e272SRichard Henderson /* If the binary operation has first argument @i, fold to @i. */
fold_ix_to_i(OptContext * ctx,TCGOp * op,uint64_t i)1115da48e272SRichard Henderson static bool fold_ix_to_i(OptContext *ctx, TCGOp *op, uint64_t i)
1116da48e272SRichard Henderson {
111727cdb85dSRichard Henderson     if (arg_is_const_val(op->args[1], i)) {
1118da48e272SRichard Henderson         return tcg_opt_gen_movi(ctx, op, op->args[0], i);
1119da48e272SRichard Henderson     }
1120da48e272SRichard Henderson     return false;
1121da48e272SRichard Henderson }
1122da48e272SRichard Henderson 
11230e0a32baSRichard Henderson /* If the binary operation has first argument @i, fold to NOT. */
fold_ix_to_not(OptContext * ctx,TCGOp * op,uint64_t i)11240e0a32baSRichard Henderson static bool fold_ix_to_not(OptContext *ctx, TCGOp *op, uint64_t i)
11250e0a32baSRichard Henderson {
112627cdb85dSRichard Henderson     if (arg_is_const_val(op->args[1], i)) {
11270e0a32baSRichard Henderson         return fold_to_not(ctx, op, 2);
11280e0a32baSRichard Henderson     }
11290e0a32baSRichard Henderson     return false;
11300e0a32baSRichard Henderson }
11310e0a32baSRichard Henderson 
1132e8679955SRichard Henderson /* If the binary operation has second argument @i, fold to @i. */
fold_xi_to_i(OptContext * ctx,TCGOp * op,uint64_t i)1133e8679955SRichard Henderson static bool fold_xi_to_i(OptContext *ctx, TCGOp *op, uint64_t i)
1134e8679955SRichard Henderson {
113527cdb85dSRichard Henderson     if (arg_is_const_val(op->args[2], i)) {
1136e8679955SRichard Henderson         return tcg_opt_gen_movi(ctx, op, op->args[0], i);
1137e8679955SRichard Henderson     }
1138e8679955SRichard Henderson     return false;
1139e8679955SRichard Henderson }
1140e8679955SRichard Henderson 
1141a63ce0e9SRichard Henderson /* If the binary operation has second argument @i, fold to identity. */
fold_xi_to_x(OptContext * ctx,TCGOp * op,uint64_t i)1142a63ce0e9SRichard Henderson static bool fold_xi_to_x(OptContext *ctx, TCGOp *op, uint64_t i)
1143a63ce0e9SRichard Henderson {
114427cdb85dSRichard Henderson     if (arg_is_const_val(op->args[2], i)) {
1145a63ce0e9SRichard Henderson         return tcg_opt_gen_mov(ctx, op, op->args[0], op->args[1]);
1146a63ce0e9SRichard Henderson     }
1147a63ce0e9SRichard Henderson     return false;
1148a63ce0e9SRichard Henderson }
1149a63ce0e9SRichard Henderson 
11500e0a32baSRichard Henderson /* If the binary operation has second argument @i, fold to NOT. */
fold_xi_to_not(OptContext * ctx,TCGOp * op,uint64_t i)11510e0a32baSRichard Henderson static bool fold_xi_to_not(OptContext *ctx, TCGOp *op, uint64_t i)
11520e0a32baSRichard Henderson {
115327cdb85dSRichard Henderson     if (arg_is_const_val(op->args[2], i)) {
11540e0a32baSRichard Henderson         return fold_to_not(ctx, op, 1);
11550e0a32baSRichard Henderson     }
11560e0a32baSRichard Henderson     return false;
11570e0a32baSRichard Henderson }
11580e0a32baSRichard Henderson 
1159cbe42fb2SRichard Henderson /* If the binary operation has both arguments equal, fold to @i. */
fold_xx_to_i(OptContext * ctx,TCGOp * op,uint64_t i)1160cbe42fb2SRichard Henderson static bool fold_xx_to_i(OptContext *ctx, TCGOp *op, uint64_t i)
1161cbe42fb2SRichard Henderson {
1162cbe42fb2SRichard Henderson     if (args_are_copies(op->args[1], op->args[2])) {
1163cbe42fb2SRichard Henderson         return tcg_opt_gen_movi(ctx, op, op->args[0], i);
1164cbe42fb2SRichard Henderson     }
1165cbe42fb2SRichard Henderson     return false;
1166cbe42fb2SRichard Henderson }
1167cbe42fb2SRichard Henderson 
1168ca7bb049SRichard Henderson /* If the binary operation has both arguments equal, fold to identity. */
fold_xx_to_x(OptContext * ctx,TCGOp * op)1169ca7bb049SRichard Henderson static bool fold_xx_to_x(OptContext *ctx, TCGOp *op)
1170ca7bb049SRichard Henderson {
1171ca7bb049SRichard Henderson     if (args_are_copies(op->args[1], op->args[2])) {
1172ca7bb049SRichard Henderson         return tcg_opt_gen_mov(ctx, op, op->args[0], op->args[1]);
1173ca7bb049SRichard Henderson     }
1174ca7bb049SRichard Henderson     return false;
1175ca7bb049SRichard Henderson }
1176ca7bb049SRichard Henderson 
11772f9f08baSRichard Henderson /*
11782f9f08baSRichard Henderson  * These outermost fold_<op> functions are sorted alphabetically.
1179ca7bb049SRichard Henderson  *
1180ca7bb049SRichard Henderson  * The ordering of the transformations should be:
1181ca7bb049SRichard Henderson  *   1) those that produce a constant
1182ca7bb049SRichard Henderson  *   2) those that produce a copy
1183ca7bb049SRichard Henderson  *   3) those that produce information about the result value.
11842f9f08baSRichard Henderson  */
11852f9f08baSRichard Henderson 
fold_add(OptContext * ctx,TCGOp * op)11862f9f08baSRichard Henderson static bool fold_add(OptContext *ctx, TCGOp *op)
11872f9f08baSRichard Henderson {
11887a2f7084SRichard Henderson     if (fold_const2_commutative(ctx, op) ||
1189a63ce0e9SRichard Henderson         fold_xi_to_x(ctx, op, 0)) {
1190a63ce0e9SRichard Henderson         return true;
1191a63ce0e9SRichard Henderson     }
1192a63ce0e9SRichard Henderson     return false;
11932f9f08baSRichard Henderson }
11942f9f08baSRichard Henderson 
1195c578ff18SRichard Henderson /* We cannot as yet do_constant_folding with vectors. */
fold_add_vec(OptContext * ctx,TCGOp * op)1196c578ff18SRichard Henderson static bool fold_add_vec(OptContext *ctx, TCGOp *op)
1197c578ff18SRichard Henderson {
1198c578ff18SRichard Henderson     if (fold_commutative(ctx, op) ||
1199c578ff18SRichard Henderson         fold_xi_to_x(ctx, op, 0)) {
1200c578ff18SRichard Henderson         return true;
1201c578ff18SRichard Henderson     }
1202c578ff18SRichard Henderson     return false;
1203c578ff18SRichard Henderson }
1204c578ff18SRichard Henderson 
fold_addsub2(OptContext * ctx,TCGOp * op,bool add)12059531c078SRichard Henderson static bool fold_addsub2(OptContext *ctx, TCGOp *op, bool add)
1206e3f7dc21SRichard Henderson {
1207f2457577SRichard Henderson     bool a_const = arg_is_const(op->args[2]) && arg_is_const(op->args[3]);
1208f2457577SRichard Henderson     bool b_const = arg_is_const(op->args[4]) && arg_is_const(op->args[5]);
1209f2457577SRichard Henderson 
1210f2457577SRichard Henderson     if (a_const && b_const) {
12119531c078SRichard Henderson         uint64_t al = arg_info(op->args[2])->val;
12129531c078SRichard Henderson         uint64_t ah = arg_info(op->args[3])->val;
12139531c078SRichard Henderson         uint64_t bl = arg_info(op->args[4])->val;
12149531c078SRichard Henderson         uint64_t bh = arg_info(op->args[5])->val;
1215e3f7dc21SRichard Henderson         TCGArg rl, rh;
12169531c078SRichard Henderson         TCGOp *op2;
12179531c078SRichard Henderson 
12189531c078SRichard Henderson         if (ctx->type == TCG_TYPE_I32) {
12199531c078SRichard Henderson             uint64_t a = deposit64(al, 32, 32, ah);
12209531c078SRichard Henderson             uint64_t b = deposit64(bl, 32, 32, bh);
1221e3f7dc21SRichard Henderson 
1222e3f7dc21SRichard Henderson             if (add) {
1223e3f7dc21SRichard Henderson                 a += b;
1224e3f7dc21SRichard Henderson             } else {
1225e3f7dc21SRichard Henderson                 a -= b;
1226e3f7dc21SRichard Henderson             }
1227e3f7dc21SRichard Henderson 
12289531c078SRichard Henderson             al = sextract64(a, 0, 32);
12299531c078SRichard Henderson             ah = sextract64(a, 32, 32);
12309531c078SRichard Henderson         } else {
12319531c078SRichard Henderson             Int128 a = int128_make128(al, ah);
12329531c078SRichard Henderson             Int128 b = int128_make128(bl, bh);
12339531c078SRichard Henderson 
12349531c078SRichard Henderson             if (add) {
12359531c078SRichard Henderson                 a = int128_add(a, b);
12369531c078SRichard Henderson             } else {
12379531c078SRichard Henderson                 a = int128_sub(a, b);
12389531c078SRichard Henderson             }
12399531c078SRichard Henderson 
12409531c078SRichard Henderson             al = int128_getlo(a);
12419531c078SRichard Henderson             ah = int128_gethi(a);
12429531c078SRichard Henderson         }
12439531c078SRichard Henderson 
1244e3f7dc21SRichard Henderson         rl = op->args[0];
1245e3f7dc21SRichard Henderson         rh = op->args[1];
12469531c078SRichard Henderson 
12479531c078SRichard Henderson         /* The proper opcode is supplied by tcg_opt_gen_mov. */
1248d4478943SPhilippe Mathieu-Daudé         op2 = tcg_op_insert_before(ctx->tcg, op, 0, 2);
12499531c078SRichard Henderson 
12509531c078SRichard Henderson         tcg_opt_gen_movi(ctx, op, rl, al);
12519531c078SRichard Henderson         tcg_opt_gen_movi(ctx, op2, rh, ah);
1252e3f7dc21SRichard Henderson         return true;
1253e3f7dc21SRichard Henderson     }
1254f2457577SRichard Henderson 
1255f2457577SRichard Henderson     /* Fold sub2 r,x,i to add2 r,x,-i */
1256f2457577SRichard Henderson     if (!add && b_const) {
1257f2457577SRichard Henderson         uint64_t bl = arg_info(op->args[4])->val;
1258f2457577SRichard Henderson         uint64_t bh = arg_info(op->args[5])->val;
1259f2457577SRichard Henderson 
1260f2457577SRichard Henderson         /* Negate the two parts without assembling and disassembling. */
1261f2457577SRichard Henderson         bl = -bl;
1262f2457577SRichard Henderson         bh = ~bh + !bl;
1263f2457577SRichard Henderson 
1264f2457577SRichard Henderson         op->opc = (ctx->type == TCG_TYPE_I32
1265f2457577SRichard Henderson                    ? INDEX_op_add2_i32 : INDEX_op_add2_i64);
1266f2457577SRichard Henderson         op->args[4] = arg_new_constant(ctx, bl);
1267f2457577SRichard Henderson         op->args[5] = arg_new_constant(ctx, bh);
1268f2457577SRichard Henderson     }
1269e3f7dc21SRichard Henderson     return false;
1270e3f7dc21SRichard Henderson }
1271e3f7dc21SRichard Henderson 
fold_add2(OptContext * ctx,TCGOp * op)12729531c078SRichard Henderson static bool fold_add2(OptContext *ctx, TCGOp *op)
1273e3f7dc21SRichard Henderson {
12747a2f7084SRichard Henderson     /* Note that the high and low parts may be independently swapped. */
12757a2f7084SRichard Henderson     swap_commutative(op->args[0], &op->args[2], &op->args[4]);
12767a2f7084SRichard Henderson     swap_commutative(op->args[1], &op->args[3], &op->args[5]);
12777a2f7084SRichard Henderson 
12789531c078SRichard Henderson     return fold_addsub2(ctx, op, true);
1279e3f7dc21SRichard Henderson }
1280e3f7dc21SRichard Henderson 
fold_and(OptContext * ctx,TCGOp * op)12812f9f08baSRichard Henderson static bool fold_and(OptContext *ctx, TCGOp *op)
12822f9f08baSRichard Henderson {
1283fae450baSRichard Henderson     uint64_t z1, z2;
1284fae450baSRichard Henderson 
12857a2f7084SRichard Henderson     if (fold_const2_commutative(ctx, op) ||
1286e8679955SRichard Henderson         fold_xi_to_i(ctx, op, 0) ||
1287a63ce0e9SRichard Henderson         fold_xi_to_x(ctx, op, -1) ||
1288ca7bb049SRichard Henderson         fold_xx_to_x(ctx, op)) {
1289ca7bb049SRichard Henderson         return true;
1290ca7bb049SRichard Henderson     }
1291fae450baSRichard Henderson 
1292fae450baSRichard Henderson     z1 = arg_info(op->args[1])->z_mask;
1293fae450baSRichard Henderson     z2 = arg_info(op->args[2])->z_mask;
1294fae450baSRichard Henderson     ctx->z_mask = z1 & z2;
1295fae450baSRichard Henderson 
1296fae450baSRichard Henderson     /*
12973f2b1f83SRichard Henderson      * Sign repetitions are perforce all identical, whether they are 1 or 0.
12983f2b1f83SRichard Henderson      * Bitwise operations preserve the relative quantity of the repetitions.
12993f2b1f83SRichard Henderson      */
13003f2b1f83SRichard Henderson     ctx->s_mask = arg_info(op->args[1])->s_mask
13013f2b1f83SRichard Henderson                 & arg_info(op->args[2])->s_mask;
13023f2b1f83SRichard Henderson 
13033f2b1f83SRichard Henderson     /*
1304fae450baSRichard Henderson      * Known-zeros does not imply known-ones.  Therefore unless
1305fae450baSRichard Henderson      * arg2 is constant, we can't infer affected bits from it.
1306fae450baSRichard Henderson      */
1307fae450baSRichard Henderson     if (arg_is_const(op->args[2])) {
1308fae450baSRichard Henderson         ctx->a_mask = z1 & ~z2;
1309fae450baSRichard Henderson     }
1310fae450baSRichard Henderson 
1311fae450baSRichard Henderson     return fold_masks(ctx, op);
13122f9f08baSRichard Henderson }
13132f9f08baSRichard Henderson 
fold_andc(OptContext * ctx,TCGOp * op)13142f9f08baSRichard Henderson static bool fold_andc(OptContext *ctx, TCGOp *op)
13152f9f08baSRichard Henderson {
1316fae450baSRichard Henderson     uint64_t z1;
1317fae450baSRichard Henderson 
1318cbe42fb2SRichard Henderson     if (fold_const2(ctx, op) ||
13190e0a32baSRichard Henderson         fold_xx_to_i(ctx, op, 0) ||
1320a63ce0e9SRichard Henderson         fold_xi_to_x(ctx, op, 0) ||
13210e0a32baSRichard Henderson         fold_ix_to_not(ctx, op, -1)) {
1322cbe42fb2SRichard Henderson         return true;
1323cbe42fb2SRichard Henderson     }
1324fae450baSRichard Henderson 
1325fae450baSRichard Henderson     z1 = arg_info(op->args[1])->z_mask;
1326fae450baSRichard Henderson 
1327fae450baSRichard Henderson     /*
1328fae450baSRichard Henderson      * Known-zeros does not imply known-ones.  Therefore unless
1329fae450baSRichard Henderson      * arg2 is constant, we can't infer anything from it.
1330fae450baSRichard Henderson      */
1331fae450baSRichard Henderson     if (arg_is_const(op->args[2])) {
1332fae450baSRichard Henderson         uint64_t z2 = ~arg_info(op->args[2])->z_mask;
1333fae450baSRichard Henderson         ctx->a_mask = z1 & ~z2;
1334fae450baSRichard Henderson         z1 &= z2;
1335fae450baSRichard Henderson     }
1336fae450baSRichard Henderson     ctx->z_mask = z1;
1337fae450baSRichard Henderson 
13383f2b1f83SRichard Henderson     ctx->s_mask = arg_info(op->args[1])->s_mask
13393f2b1f83SRichard Henderson                 & arg_info(op->args[2])->s_mask;
1340fae450baSRichard Henderson     return fold_masks(ctx, op);
13412f9f08baSRichard Henderson }
13422f9f08baSRichard Henderson 
fold_brcond(OptContext * ctx,TCGOp * op)1343079b0804SRichard Henderson static bool fold_brcond(OptContext *ctx, TCGOp *op)
1344079b0804SRichard Henderson {
1345fb04ab7dSRichard Henderson     int i = do_constant_folding_cond1(ctx, op, NO_DEST, &op->args[0],
1346246c4b72SRichard Henderson                                       &op->args[1], &op->args[2]);
1347079b0804SRichard Henderson     if (i == 0) {
1348079b0804SRichard Henderson         tcg_op_remove(ctx->tcg, op);
1349079b0804SRichard Henderson         return true;
1350079b0804SRichard Henderson     }
1351079b0804SRichard Henderson     if (i > 0) {
1352079b0804SRichard Henderson         op->opc = INDEX_op_br;
1353079b0804SRichard Henderson         op->args[0] = op->args[3];
1354079b0804SRichard Henderson     }
1355079b0804SRichard Henderson     return false;
1356079b0804SRichard Henderson }
1357079b0804SRichard Henderson 
fold_brcond2(OptContext * ctx,TCGOp * op)1358764d2abaSRichard Henderson static bool fold_brcond2(OptContext *ctx, TCGOp *op)
1359764d2abaSRichard Henderson {
13607e64b114SRichard Henderson     TCGCond cond;
13617e64b114SRichard Henderson     TCGArg label;
13627a2f7084SRichard Henderson     int i, inv = 0;
1363764d2abaSRichard Henderson 
1364fb04ab7dSRichard Henderson     i = do_constant_folding_cond2(ctx, op, &op->args[0]);
13657e64b114SRichard Henderson     cond = op->args[4];
13667e64b114SRichard Henderson     label = op->args[5];
1367764d2abaSRichard Henderson     if (i >= 0) {
1368764d2abaSRichard Henderson         goto do_brcond_const;
1369764d2abaSRichard Henderson     }
1370764d2abaSRichard Henderson 
1371764d2abaSRichard Henderson     switch (cond) {
1372764d2abaSRichard Henderson     case TCG_COND_LT:
1373764d2abaSRichard Henderson     case TCG_COND_GE:
1374764d2abaSRichard Henderson         /*
1375764d2abaSRichard Henderson          * Simplify LT/GE comparisons vs zero to a single compare
1376764d2abaSRichard Henderson          * vs the high word of the input.
1377764d2abaSRichard Henderson          */
137827cdb85dSRichard Henderson         if (arg_is_const_val(op->args[2], 0) &&
137927cdb85dSRichard Henderson             arg_is_const_val(op->args[3], 0)) {
1380764d2abaSRichard Henderson             goto do_brcond_high;
1381764d2abaSRichard Henderson         }
1382764d2abaSRichard Henderson         break;
1383764d2abaSRichard Henderson 
1384764d2abaSRichard Henderson     case TCG_COND_NE:
1385764d2abaSRichard Henderson         inv = 1;
1386764d2abaSRichard Henderson         QEMU_FALLTHROUGH;
1387764d2abaSRichard Henderson     case TCG_COND_EQ:
1388764d2abaSRichard Henderson         /*
1389764d2abaSRichard Henderson          * Simplify EQ/NE comparisons where one of the pairs
1390764d2abaSRichard Henderson          * can be simplified.
1391764d2abaSRichard Henderson          */
139267f84c96SRichard Henderson         i = do_constant_folding_cond(TCG_TYPE_I32, op->args[0],
1393764d2abaSRichard Henderson                                      op->args[2], cond);
1394764d2abaSRichard Henderson         switch (i ^ inv) {
1395764d2abaSRichard Henderson         case 0:
1396764d2abaSRichard Henderson             goto do_brcond_const;
1397764d2abaSRichard Henderson         case 1:
1398764d2abaSRichard Henderson             goto do_brcond_high;
1399764d2abaSRichard Henderson         }
1400764d2abaSRichard Henderson 
140167f84c96SRichard Henderson         i = do_constant_folding_cond(TCG_TYPE_I32, op->args[1],
1402764d2abaSRichard Henderson                                      op->args[3], cond);
1403764d2abaSRichard Henderson         switch (i ^ inv) {
1404764d2abaSRichard Henderson         case 0:
1405764d2abaSRichard Henderson             goto do_brcond_const;
1406764d2abaSRichard Henderson         case 1:
1407ceb9ee06SRichard Henderson             goto do_brcond_low;
1408ceb9ee06SRichard Henderson         }
1409764d2abaSRichard Henderson         break;
1410ceb9ee06SRichard Henderson 
1411ceb9ee06SRichard Henderson     case TCG_COND_TSTEQ:
1412ceb9ee06SRichard Henderson     case TCG_COND_TSTNE:
1413ceb9ee06SRichard Henderson         if (arg_is_const_val(op->args[2], 0)) {
1414ceb9ee06SRichard Henderson             goto do_brcond_high;
1415ceb9ee06SRichard Henderson         }
1416ceb9ee06SRichard Henderson         if (arg_is_const_val(op->args[3], 0)) {
1417ceb9ee06SRichard Henderson             goto do_brcond_low;
1418764d2abaSRichard Henderson         }
1419764d2abaSRichard Henderson         break;
1420764d2abaSRichard Henderson 
1421764d2abaSRichard Henderson     default:
1422764d2abaSRichard Henderson         break;
1423764d2abaSRichard Henderson 
1424ceb9ee06SRichard Henderson     do_brcond_low:
1425ceb9ee06SRichard Henderson         op->opc = INDEX_op_brcond_i32;
1426ceb9ee06SRichard Henderson         op->args[1] = op->args[2];
1427ceb9ee06SRichard Henderson         op->args[2] = cond;
1428ceb9ee06SRichard Henderson         op->args[3] = label;
1429ceb9ee06SRichard Henderson         return fold_brcond(ctx, op);
1430ceb9ee06SRichard Henderson 
1431764d2abaSRichard Henderson     do_brcond_high:
1432764d2abaSRichard Henderson         op->opc = INDEX_op_brcond_i32;
1433764d2abaSRichard Henderson         op->args[0] = op->args[1];
1434764d2abaSRichard Henderson         op->args[1] = op->args[3];
1435764d2abaSRichard Henderson         op->args[2] = cond;
1436764d2abaSRichard Henderson         op->args[3] = label;
1437ceb9ee06SRichard Henderson         return fold_brcond(ctx, op);
1438764d2abaSRichard Henderson 
1439764d2abaSRichard Henderson     do_brcond_const:
1440764d2abaSRichard Henderson         if (i == 0) {
1441764d2abaSRichard Henderson             tcg_op_remove(ctx->tcg, op);
1442764d2abaSRichard Henderson             return true;
1443764d2abaSRichard Henderson         }
1444764d2abaSRichard Henderson         op->opc = INDEX_op_br;
1445764d2abaSRichard Henderson         op->args[0] = label;
1446764d2abaSRichard Henderson         break;
1447764d2abaSRichard Henderson     }
1448764d2abaSRichard Henderson     return false;
1449764d2abaSRichard Henderson }
1450764d2abaSRichard Henderson 
fold_bswap(OptContext * ctx,TCGOp * op)145109bacdc2SRichard Henderson static bool fold_bswap(OptContext *ctx, TCGOp *op)
145209bacdc2SRichard Henderson {
145357fe5c6dSRichard Henderson     uint64_t z_mask, s_mask, sign;
1454fae450baSRichard Henderson 
145509bacdc2SRichard Henderson     if (arg_is_const(op->args[1])) {
145609bacdc2SRichard Henderson         uint64_t t = arg_info(op->args[1])->val;
145709bacdc2SRichard Henderson 
145867f84c96SRichard Henderson         t = do_constant_folding(op->opc, ctx->type, t, op->args[2]);
145909bacdc2SRichard Henderson         return tcg_opt_gen_movi(ctx, op, op->args[0], t);
146009bacdc2SRichard Henderson     }
1461fae450baSRichard Henderson 
1462fae450baSRichard Henderson     z_mask = arg_info(op->args[1])->z_mask;
146357fe5c6dSRichard Henderson 
1464fae450baSRichard Henderson     switch (op->opc) {
1465fae450baSRichard Henderson     case INDEX_op_bswap16_i32:
1466fae450baSRichard Henderson     case INDEX_op_bswap16_i64:
1467fae450baSRichard Henderson         z_mask = bswap16(z_mask);
1468fae450baSRichard Henderson         sign = INT16_MIN;
1469fae450baSRichard Henderson         break;
1470fae450baSRichard Henderson     case INDEX_op_bswap32_i32:
1471fae450baSRichard Henderson     case INDEX_op_bswap32_i64:
1472fae450baSRichard Henderson         z_mask = bswap32(z_mask);
1473fae450baSRichard Henderson         sign = INT32_MIN;
1474fae450baSRichard Henderson         break;
1475fae450baSRichard Henderson     case INDEX_op_bswap64_i64:
1476fae450baSRichard Henderson         z_mask = bswap64(z_mask);
1477fae450baSRichard Henderson         sign = INT64_MIN;
1478fae450baSRichard Henderson         break;
1479fae450baSRichard Henderson     default:
1480fae450baSRichard Henderson         g_assert_not_reached();
1481fae450baSRichard Henderson     }
148257fe5c6dSRichard Henderson     s_mask = smask_from_zmask(z_mask);
1483fae450baSRichard Henderson 
1484fae450baSRichard Henderson     switch (op->args[2] & (TCG_BSWAP_OZ | TCG_BSWAP_OS)) {
1485fae450baSRichard Henderson     case TCG_BSWAP_OZ:
1486fae450baSRichard Henderson         break;
1487fae450baSRichard Henderson     case TCG_BSWAP_OS:
1488fae450baSRichard Henderson         /* If the sign bit may be 1, force all the bits above to 1. */
1489fae450baSRichard Henderson         if (z_mask & sign) {
1490fae450baSRichard Henderson             z_mask |= sign;
149157fe5c6dSRichard Henderson             s_mask = sign << 1;
1492fae450baSRichard Henderson         }
1493fae450baSRichard Henderson         break;
1494fae450baSRichard Henderson     default:
1495fae450baSRichard Henderson         /* The high bits are undefined: force all bits above the sign to 1. */
1496fae450baSRichard Henderson         z_mask |= sign << 1;
149757fe5c6dSRichard Henderson         s_mask = 0;
1498fae450baSRichard Henderson         break;
1499fae450baSRichard Henderson     }
1500fae450baSRichard Henderson     ctx->z_mask = z_mask;
150157fe5c6dSRichard Henderson     ctx->s_mask = s_mask;
1502fae450baSRichard Henderson 
1503fae450baSRichard Henderson     return fold_masks(ctx, op);
150409bacdc2SRichard Henderson }
150509bacdc2SRichard Henderson 
fold_call(OptContext * ctx,TCGOp * op)15065cf32be7SRichard Henderson static bool fold_call(OptContext *ctx, TCGOp *op)
15075cf32be7SRichard Henderson {
15085cf32be7SRichard Henderson     TCGContext *s = ctx->tcg;
15095cf32be7SRichard Henderson     int nb_oargs = TCGOP_CALLO(op);
15105cf32be7SRichard Henderson     int nb_iargs = TCGOP_CALLI(op);
15115cf32be7SRichard Henderson     int flags, i;
15125cf32be7SRichard Henderson 
15135cf32be7SRichard Henderson     init_arguments(ctx, op, nb_oargs + nb_iargs);
15145cf32be7SRichard Henderson     copy_propagate(ctx, op, nb_oargs, nb_iargs);
15155cf32be7SRichard Henderson 
15165cf32be7SRichard Henderson     /* If the function reads or writes globals, reset temp data. */
15175cf32be7SRichard Henderson     flags = tcg_call_flags(op);
15185cf32be7SRichard Henderson     if (!(flags & (TCG_CALL_NO_READ_GLOBALS | TCG_CALL_NO_WRITE_GLOBALS))) {
15195cf32be7SRichard Henderson         int nb_globals = s->nb_globals;
15205cf32be7SRichard Henderson 
15215cf32be7SRichard Henderson         for (i = 0; i < nb_globals; i++) {
15225cf32be7SRichard Henderson             if (test_bit(i, ctx->temps_used.l)) {
1523986cac1dSRichard Henderson                 reset_ts(ctx, &ctx->tcg->temps[i]);
15245cf32be7SRichard Henderson             }
15255cf32be7SRichard Henderson         }
15265cf32be7SRichard Henderson     }
15275cf32be7SRichard Henderson 
1528ab84dc39SRichard Henderson     /* If the function has side effects, reset mem data. */
1529ab84dc39SRichard Henderson     if (!(flags & TCG_CALL_NO_SIDE_EFFECTS)) {
1530ab84dc39SRichard Henderson         remove_mem_copy_all(ctx);
1531ab84dc39SRichard Henderson     }
1532ab84dc39SRichard Henderson 
15335cf32be7SRichard Henderson     /* Reset temp data for outputs. */
15345cf32be7SRichard Henderson     for (i = 0; i < nb_oargs; i++) {
1535986cac1dSRichard Henderson         reset_temp(ctx, op->args[i]);
15365cf32be7SRichard Henderson     }
15375cf32be7SRichard Henderson 
15385cf32be7SRichard Henderson     /* Stop optimizing MB across calls. */
15395cf32be7SRichard Henderson     ctx->prev_mb = NULL;
15405cf32be7SRichard Henderson     return true;
15415cf32be7SRichard Henderson }
15425cf32be7SRichard Henderson 
fold_count_zeros(OptContext * ctx,TCGOp * op)154330dd0bfeSRichard Henderson static bool fold_count_zeros(OptContext *ctx, TCGOp *op)
154430dd0bfeSRichard Henderson {
1545fae450baSRichard Henderson     uint64_t z_mask;
1546fae450baSRichard Henderson 
154730dd0bfeSRichard Henderson     if (arg_is_const(op->args[1])) {
154830dd0bfeSRichard Henderson         uint64_t t = arg_info(op->args[1])->val;
154930dd0bfeSRichard Henderson 
155030dd0bfeSRichard Henderson         if (t != 0) {
155167f84c96SRichard Henderson             t = do_constant_folding(op->opc, ctx->type, t, 0);
155230dd0bfeSRichard Henderson             return tcg_opt_gen_movi(ctx, op, op->args[0], t);
155330dd0bfeSRichard Henderson         }
155430dd0bfeSRichard Henderson         return tcg_opt_gen_mov(ctx, op, op->args[0], op->args[2]);
155530dd0bfeSRichard Henderson     }
1556fae450baSRichard Henderson 
1557fae450baSRichard Henderson     switch (ctx->type) {
1558fae450baSRichard Henderson     case TCG_TYPE_I32:
1559fae450baSRichard Henderson         z_mask = 31;
1560fae450baSRichard Henderson         break;
1561fae450baSRichard Henderson     case TCG_TYPE_I64:
1562fae450baSRichard Henderson         z_mask = 63;
1563fae450baSRichard Henderson         break;
1564fae450baSRichard Henderson     default:
1565fae450baSRichard Henderson         g_assert_not_reached();
1566fae450baSRichard Henderson     }
1567fae450baSRichard Henderson     ctx->z_mask = arg_info(op->args[2])->z_mask | z_mask;
15682b9d0c59SRichard Henderson     ctx->s_mask = smask_from_zmask(ctx->z_mask);
156930dd0bfeSRichard Henderson     return false;
157030dd0bfeSRichard Henderson }
157130dd0bfeSRichard Henderson 
fold_ctpop(OptContext * ctx,TCGOp * op)15722f9f08baSRichard Henderson static bool fold_ctpop(OptContext *ctx, TCGOp *op)
15732f9f08baSRichard Henderson {
1574fae450baSRichard Henderson     if (fold_const1(ctx, op)) {
1575fae450baSRichard Henderson         return true;
1576fae450baSRichard Henderson     }
1577fae450baSRichard Henderson 
1578fae450baSRichard Henderson     switch (ctx->type) {
1579fae450baSRichard Henderson     case TCG_TYPE_I32:
1580fae450baSRichard Henderson         ctx->z_mask = 32 | 31;
1581fae450baSRichard Henderson         break;
1582fae450baSRichard Henderson     case TCG_TYPE_I64:
1583fae450baSRichard Henderson         ctx->z_mask = 64 | 63;
1584fae450baSRichard Henderson         break;
1585fae450baSRichard Henderson     default:
1586fae450baSRichard Henderson         g_assert_not_reached();
1587fae450baSRichard Henderson     }
15882b9d0c59SRichard Henderson     ctx->s_mask = smask_from_zmask(ctx->z_mask);
1589fae450baSRichard Henderson     return false;
15902f9f08baSRichard Henderson }
15912f9f08baSRichard Henderson 
fold_deposit(OptContext * ctx,TCGOp * op)15921b1907b8SRichard Henderson static bool fold_deposit(OptContext *ctx, TCGOp *op)
15931b1907b8SRichard Henderson {
15948f7a840dSRichard Henderson     TCGOpcode and_opc;
15958f7a840dSRichard Henderson 
15961b1907b8SRichard Henderson     if (arg_is_const(op->args[1]) && arg_is_const(op->args[2])) {
15971b1907b8SRichard Henderson         uint64_t t1 = arg_info(op->args[1])->val;
15981b1907b8SRichard Henderson         uint64_t t2 = arg_info(op->args[2])->val;
15991b1907b8SRichard Henderson 
16001b1907b8SRichard Henderson         t1 = deposit64(t1, op->args[3], op->args[4], t2);
16011b1907b8SRichard Henderson         return tcg_opt_gen_movi(ctx, op, op->args[0], t1);
16021b1907b8SRichard Henderson     }
1603fae450baSRichard Henderson 
16048f7a840dSRichard Henderson     switch (ctx->type) {
16058f7a840dSRichard Henderson     case TCG_TYPE_I32:
16068f7a840dSRichard Henderson         and_opc = INDEX_op_and_i32;
16078f7a840dSRichard Henderson         break;
16088f7a840dSRichard Henderson     case TCG_TYPE_I64:
16098f7a840dSRichard Henderson         and_opc = INDEX_op_and_i64;
16108f7a840dSRichard Henderson         break;
16118f7a840dSRichard Henderson     default:
16128f7a840dSRichard Henderson         g_assert_not_reached();
16138f7a840dSRichard Henderson     }
16148f7a840dSRichard Henderson 
16158f7a840dSRichard Henderson     /* Inserting a value into zero at offset 0. */
161627cdb85dSRichard Henderson     if (arg_is_const_val(op->args[1], 0) && op->args[3] == 0) {
16178f7a840dSRichard Henderson         uint64_t mask = MAKE_64BIT_MASK(0, op->args[4]);
16188f7a840dSRichard Henderson 
16198f7a840dSRichard Henderson         op->opc = and_opc;
16208f7a840dSRichard Henderson         op->args[1] = op->args[2];
162126aac97cSRichard Henderson         op->args[2] = arg_new_constant(ctx, mask);
16228f7a840dSRichard Henderson         ctx->z_mask = mask & arg_info(op->args[1])->z_mask;
16238f7a840dSRichard Henderson         return false;
16248f7a840dSRichard Henderson     }
16258f7a840dSRichard Henderson 
16268f7a840dSRichard Henderson     /* Inserting zero into a value. */
162727cdb85dSRichard Henderson     if (arg_is_const_val(op->args[2], 0)) {
16288f7a840dSRichard Henderson         uint64_t mask = deposit64(-1, op->args[3], op->args[4], 0);
16298f7a840dSRichard Henderson 
16308f7a840dSRichard Henderson         op->opc = and_opc;
163126aac97cSRichard Henderson         op->args[2] = arg_new_constant(ctx, mask);
16328f7a840dSRichard Henderson         ctx->z_mask = mask & arg_info(op->args[1])->z_mask;
16338f7a840dSRichard Henderson         return false;
16348f7a840dSRichard Henderson     }
16358f7a840dSRichard Henderson 
1636fae450baSRichard Henderson     ctx->z_mask = deposit64(arg_info(op->args[1])->z_mask,
1637fae450baSRichard Henderson                             op->args[3], op->args[4],
1638fae450baSRichard Henderson                             arg_info(op->args[2])->z_mask);
16391b1907b8SRichard Henderson     return false;
16401b1907b8SRichard Henderson }
16411b1907b8SRichard Henderson 
fold_divide(OptContext * ctx,TCGOp * op)16422f9f08baSRichard Henderson static bool fold_divide(OptContext *ctx, TCGOp *op)
16432f9f08baSRichard Henderson {
16442f9d9a34SRichard Henderson     if (fold_const2(ctx, op) ||
16452f9d9a34SRichard Henderson         fold_xi_to_x(ctx, op, 1)) {
16462f9d9a34SRichard Henderson         return true;
16472f9d9a34SRichard Henderson     }
16482f9d9a34SRichard Henderson     return false;
16492f9f08baSRichard Henderson }
16502f9f08baSRichard Henderson 
fold_dup(OptContext * ctx,TCGOp * op)16518cdb3fcbSRichard Henderson static bool fold_dup(OptContext *ctx, TCGOp *op)
16528cdb3fcbSRichard Henderson {
16538cdb3fcbSRichard Henderson     if (arg_is_const(op->args[1])) {
16548cdb3fcbSRichard Henderson         uint64_t t = arg_info(op->args[1])->val;
16558cdb3fcbSRichard Henderson         t = dup_const(TCGOP_VECE(op), t);
16568cdb3fcbSRichard Henderson         return tcg_opt_gen_movi(ctx, op, op->args[0], t);
16578cdb3fcbSRichard Henderson     }
16588cdb3fcbSRichard Henderson     return false;
16598cdb3fcbSRichard Henderson }
16608cdb3fcbSRichard Henderson 
fold_dup2(OptContext * ctx,TCGOp * op)16618cdb3fcbSRichard Henderson static bool fold_dup2(OptContext *ctx, TCGOp *op)
16628cdb3fcbSRichard Henderson {
16638cdb3fcbSRichard Henderson     if (arg_is_const(op->args[1]) && arg_is_const(op->args[2])) {
16648cdb3fcbSRichard Henderson         uint64_t t = deposit64(arg_info(op->args[1])->val, 32, 32,
16658cdb3fcbSRichard Henderson                                arg_info(op->args[2])->val);
16668cdb3fcbSRichard Henderson         return tcg_opt_gen_movi(ctx, op, op->args[0], t);
16678cdb3fcbSRichard Henderson     }
16688cdb3fcbSRichard Henderson 
16698cdb3fcbSRichard Henderson     if (args_are_copies(op->args[1], op->args[2])) {
16708cdb3fcbSRichard Henderson         op->opc = INDEX_op_dup_vec;
16718cdb3fcbSRichard Henderson         TCGOP_VECE(op) = MO_32;
16728cdb3fcbSRichard Henderson     }
16738cdb3fcbSRichard Henderson     return false;
16748cdb3fcbSRichard Henderson }
16758cdb3fcbSRichard Henderson 
fold_eqv(OptContext * ctx,TCGOp * op)16762f9f08baSRichard Henderson static bool fold_eqv(OptContext *ctx, TCGOp *op)
16772f9f08baSRichard Henderson {
16787a2f7084SRichard Henderson     if (fold_const2_commutative(ctx, op) ||
1679a63ce0e9SRichard Henderson         fold_xi_to_x(ctx, op, -1) ||
16800e0a32baSRichard Henderson         fold_xi_to_not(ctx, op, 0)) {
16810e0a32baSRichard Henderson         return true;
16820e0a32baSRichard Henderson     }
16833f2b1f83SRichard Henderson 
16843f2b1f83SRichard Henderson     ctx->s_mask = arg_info(op->args[1])->s_mask
16853f2b1f83SRichard Henderson                 & arg_info(op->args[2])->s_mask;
16860e0a32baSRichard Henderson     return false;
16872f9f08baSRichard Henderson }
16882f9f08baSRichard Henderson 
fold_extract(OptContext * ctx,TCGOp * op)1689b6617c88SRichard Henderson static bool fold_extract(OptContext *ctx, TCGOp *op)
1690b6617c88SRichard Henderson {
1691fae450baSRichard Henderson     uint64_t z_mask_old, z_mask;
169257fe5c6dSRichard Henderson     int pos = op->args[2];
169357fe5c6dSRichard Henderson     int len = op->args[3];
1694fae450baSRichard Henderson 
1695b6617c88SRichard Henderson     if (arg_is_const(op->args[1])) {
1696b6617c88SRichard Henderson         uint64_t t;
1697b6617c88SRichard Henderson 
1698b6617c88SRichard Henderson         t = arg_info(op->args[1])->val;
169957fe5c6dSRichard Henderson         t = extract64(t, pos, len);
1700b6617c88SRichard Henderson         return tcg_opt_gen_movi(ctx, op, op->args[0], t);
1701b6617c88SRichard Henderson     }
1702fae450baSRichard Henderson 
1703fae450baSRichard Henderson     z_mask_old = arg_info(op->args[1])->z_mask;
170457fe5c6dSRichard Henderson     z_mask = extract64(z_mask_old, pos, len);
170557fe5c6dSRichard Henderson     if (pos == 0) {
1706fae450baSRichard Henderson         ctx->a_mask = z_mask_old ^ z_mask;
1707fae450baSRichard Henderson     }
1708fae450baSRichard Henderson     ctx->z_mask = z_mask;
170957fe5c6dSRichard Henderson     ctx->s_mask = smask_from_zmask(z_mask);
1710fae450baSRichard Henderson 
1711fae450baSRichard Henderson     return fold_masks(ctx, op);
1712b6617c88SRichard Henderson }
1713b6617c88SRichard Henderson 
fold_extract2(OptContext * ctx,TCGOp * op)1714dcd08996SRichard Henderson static bool fold_extract2(OptContext *ctx, TCGOp *op)
1715dcd08996SRichard Henderson {
1716dcd08996SRichard Henderson     if (arg_is_const(op->args[1]) && arg_is_const(op->args[2])) {
1717dcd08996SRichard Henderson         uint64_t v1 = arg_info(op->args[1])->val;
1718dcd08996SRichard Henderson         uint64_t v2 = arg_info(op->args[2])->val;
1719dcd08996SRichard Henderson         int shr = op->args[3];
1720dcd08996SRichard Henderson 
1721dcd08996SRichard Henderson         if (op->opc == INDEX_op_extract2_i64) {
1722dcd08996SRichard Henderson             v1 >>= shr;
1723dcd08996SRichard Henderson             v2 <<= 64 - shr;
1724dcd08996SRichard Henderson         } else {
1725dcd08996SRichard Henderson             v1 = (uint32_t)v1 >> shr;
1726225bec0cSRichard Henderson             v2 = (uint64_t)((int32_t)v2 << (32 - shr));
1727dcd08996SRichard Henderson         }
1728dcd08996SRichard Henderson         return tcg_opt_gen_movi(ctx, op, op->args[0], v1 | v2);
1729dcd08996SRichard Henderson     }
1730dcd08996SRichard Henderson     return false;
1731dcd08996SRichard Henderson }
1732dcd08996SRichard Henderson 
fold_exts(OptContext * ctx,TCGOp * op)17332f9f08baSRichard Henderson static bool fold_exts(OptContext *ctx, TCGOp *op)
17342f9f08baSRichard Henderson {
173557fe5c6dSRichard Henderson     uint64_t s_mask_old, s_mask, z_mask, sign;
1736fae450baSRichard Henderson     bool type_change = false;
1737fae450baSRichard Henderson 
1738fae450baSRichard Henderson     if (fold_const1(ctx, op)) {
1739fae450baSRichard Henderson         return true;
1740fae450baSRichard Henderson     }
1741fae450baSRichard Henderson 
174257fe5c6dSRichard Henderson     z_mask = arg_info(op->args[1])->z_mask;
174357fe5c6dSRichard Henderson     s_mask = arg_info(op->args[1])->s_mask;
174457fe5c6dSRichard Henderson     s_mask_old = s_mask;
1745fae450baSRichard Henderson 
1746fae450baSRichard Henderson     switch (op->opc) {
1747fae450baSRichard Henderson     CASE_OP_32_64(ext8s):
1748fae450baSRichard Henderson         sign = INT8_MIN;
1749fae450baSRichard Henderson         z_mask = (uint8_t)z_mask;
1750fae450baSRichard Henderson         break;
1751fae450baSRichard Henderson     CASE_OP_32_64(ext16s):
1752fae450baSRichard Henderson         sign = INT16_MIN;
1753fae450baSRichard Henderson         z_mask = (uint16_t)z_mask;
1754fae450baSRichard Henderson         break;
1755fae450baSRichard Henderson     case INDEX_op_ext_i32_i64:
1756fae450baSRichard Henderson         type_change = true;
1757fae450baSRichard Henderson         QEMU_FALLTHROUGH;
1758fae450baSRichard Henderson     case INDEX_op_ext32s_i64:
1759fae450baSRichard Henderson         sign = INT32_MIN;
1760fae450baSRichard Henderson         z_mask = (uint32_t)z_mask;
1761fae450baSRichard Henderson         break;
1762fae450baSRichard Henderson     default:
1763fae450baSRichard Henderson         g_assert_not_reached();
1764fae450baSRichard Henderson     }
1765fae450baSRichard Henderson 
1766fae450baSRichard Henderson     if (z_mask & sign) {
1767fae450baSRichard Henderson         z_mask |= sign;
1768fae450baSRichard Henderson     }
176957fe5c6dSRichard Henderson     s_mask |= sign << 1;
177057fe5c6dSRichard Henderson 
1771fae450baSRichard Henderson     ctx->z_mask = z_mask;
177257fe5c6dSRichard Henderson     ctx->s_mask = s_mask;
177357fe5c6dSRichard Henderson     if (!type_change) {
177457fe5c6dSRichard Henderson         ctx->a_mask = s_mask & ~s_mask_old;
177557fe5c6dSRichard Henderson     }
1776fae450baSRichard Henderson 
1777fae450baSRichard Henderson     return fold_masks(ctx, op);
17782f9f08baSRichard Henderson }
17792f9f08baSRichard Henderson 
fold_extu(OptContext * ctx,TCGOp * op)17802f9f08baSRichard Henderson static bool fold_extu(OptContext *ctx, TCGOp *op)
17812f9f08baSRichard Henderson {
1782fae450baSRichard Henderson     uint64_t z_mask_old, z_mask;
1783fae450baSRichard Henderson     bool type_change = false;
1784fae450baSRichard Henderson 
1785fae450baSRichard Henderson     if (fold_const1(ctx, op)) {
1786fae450baSRichard Henderson         return true;
1787fae450baSRichard Henderson     }
1788fae450baSRichard Henderson 
1789fae450baSRichard Henderson     z_mask_old = z_mask = arg_info(op->args[1])->z_mask;
1790fae450baSRichard Henderson 
1791fae450baSRichard Henderson     switch (op->opc) {
1792fae450baSRichard Henderson     CASE_OP_32_64(ext8u):
1793fae450baSRichard Henderson         z_mask = (uint8_t)z_mask;
1794fae450baSRichard Henderson         break;
1795fae450baSRichard Henderson     CASE_OP_32_64(ext16u):
1796fae450baSRichard Henderson         z_mask = (uint16_t)z_mask;
1797fae450baSRichard Henderson         break;
1798fae450baSRichard Henderson     case INDEX_op_extrl_i64_i32:
1799fae450baSRichard Henderson     case INDEX_op_extu_i32_i64:
1800fae450baSRichard Henderson         type_change = true;
1801fae450baSRichard Henderson         QEMU_FALLTHROUGH;
1802fae450baSRichard Henderson     case INDEX_op_ext32u_i64:
1803fae450baSRichard Henderson         z_mask = (uint32_t)z_mask;
1804fae450baSRichard Henderson         break;
1805fae450baSRichard Henderson     case INDEX_op_extrh_i64_i32:
1806fae450baSRichard Henderson         type_change = true;
1807fae450baSRichard Henderson         z_mask >>= 32;
1808fae450baSRichard Henderson         break;
1809fae450baSRichard Henderson     default:
1810fae450baSRichard Henderson         g_assert_not_reached();
1811fae450baSRichard Henderson     }
1812fae450baSRichard Henderson 
1813fae450baSRichard Henderson     ctx->z_mask = z_mask;
181457fe5c6dSRichard Henderson     ctx->s_mask = smask_from_zmask(z_mask);
1815fae450baSRichard Henderson     if (!type_change) {
1816fae450baSRichard Henderson         ctx->a_mask = z_mask_old ^ z_mask;
1817fae450baSRichard Henderson     }
1818fae450baSRichard Henderson     return fold_masks(ctx, op);
18192f9f08baSRichard Henderson }
18202f9f08baSRichard Henderson 
fold_mb(OptContext * ctx,TCGOp * op)18213eefdf2bSRichard Henderson static bool fold_mb(OptContext *ctx, TCGOp *op)
18223eefdf2bSRichard Henderson {
18233eefdf2bSRichard Henderson     /* Eliminate duplicate and redundant fence instructions.  */
18243eefdf2bSRichard Henderson     if (ctx->prev_mb) {
18253eefdf2bSRichard Henderson         /*
18263eefdf2bSRichard Henderson          * Merge two barriers of the same type into one,
18273eefdf2bSRichard Henderson          * or a weaker barrier into a stronger one,
18283eefdf2bSRichard Henderson          * or two weaker barriers into a stronger one.
18293eefdf2bSRichard Henderson          *   mb X; mb Y => mb X|Y
18303eefdf2bSRichard Henderson          *   mb; strl => mb; st
18313eefdf2bSRichard Henderson          *   ldaq; mb => ld; mb
18323eefdf2bSRichard Henderson          *   ldaq; strl => ld; mb; st
18333eefdf2bSRichard Henderson          * Other combinations are also merged into a strong
18343eefdf2bSRichard Henderson          * barrier.  This is stricter than specified but for
18353eefdf2bSRichard Henderson          * the purposes of TCG is better than not optimizing.
18363eefdf2bSRichard Henderson          */
18373eefdf2bSRichard Henderson         ctx->prev_mb->args[0] |= op->args[0];
18383eefdf2bSRichard Henderson         tcg_op_remove(ctx->tcg, op);
18393eefdf2bSRichard Henderson     } else {
18403eefdf2bSRichard Henderson         ctx->prev_mb = op;
18413eefdf2bSRichard Henderson     }
18423eefdf2bSRichard Henderson     return true;
18433eefdf2bSRichard Henderson }
18443eefdf2bSRichard Henderson 
fold_mov(OptContext * ctx,TCGOp * op)18452cfac7faSRichard Henderson static bool fold_mov(OptContext *ctx, TCGOp *op)
18462cfac7faSRichard Henderson {
18472cfac7faSRichard Henderson     return tcg_opt_gen_mov(ctx, op, op->args[0], op->args[1]);
18482cfac7faSRichard Henderson }
18492cfac7faSRichard Henderson 
fold_movcond(OptContext * ctx,TCGOp * op)18500c310a30SRichard Henderson static bool fold_movcond(OptContext *ctx, TCGOp *op)
18510c310a30SRichard Henderson {
18527a2f7084SRichard Henderson     int i;
18530c310a30SRichard Henderson 
1854141125e0SRichard Henderson     /* If true and false values are the same, eliminate the cmp. */
1855141125e0SRichard Henderson     if (args_are_copies(op->args[3], op->args[4])) {
1856141125e0SRichard Henderson         return tcg_opt_gen_mov(ctx, op, op->args[0], op->args[3]);
1857141125e0SRichard Henderson     }
1858141125e0SRichard Henderson 
18597a2f7084SRichard Henderson     /*
18607a2f7084SRichard Henderson      * Canonicalize the "false" input reg to match the destination reg so
18617a2f7084SRichard Henderson      * that the tcg backend can implement a "move if true" operation.
18627a2f7084SRichard Henderson      */
18637a2f7084SRichard Henderson     if (swap_commutative(op->args[0], &op->args[4], &op->args[3])) {
1864246c4b72SRichard Henderson         op->args[5] = tcg_invert_cond(op->args[5]);
18657a2f7084SRichard Henderson     }
18667a2f7084SRichard Henderson 
1867fb04ab7dSRichard Henderson     i = do_constant_folding_cond1(ctx, op, NO_DEST, &op->args[1],
1868246c4b72SRichard Henderson                                   &op->args[2], &op->args[5]);
18690c310a30SRichard Henderson     if (i >= 0) {
18700c310a30SRichard Henderson         return tcg_opt_gen_mov(ctx, op, op->args[0], op->args[4 - i]);
18710c310a30SRichard Henderson     }
18720c310a30SRichard Henderson 
1873fae450baSRichard Henderson     ctx->z_mask = arg_info(op->args[3])->z_mask
1874fae450baSRichard Henderson                 | arg_info(op->args[4])->z_mask;
18753f2b1f83SRichard Henderson     ctx->s_mask = arg_info(op->args[3])->s_mask
18763f2b1f83SRichard Henderson                 & arg_info(op->args[4])->s_mask;
1877fae450baSRichard Henderson 
18780c310a30SRichard Henderson     if (arg_is_const(op->args[3]) && arg_is_const(op->args[4])) {
18790c310a30SRichard Henderson         uint64_t tv = arg_info(op->args[3])->val;
18800c310a30SRichard Henderson         uint64_t fv = arg_info(op->args[4])->val;
18813635502dSRichard Henderson         TCGOpcode opc, negopc = 0;
1882246c4b72SRichard Henderson         TCGCond cond = op->args[5];
18830c310a30SRichard Henderson 
188467f84c96SRichard Henderson         switch (ctx->type) {
188567f84c96SRichard Henderson         case TCG_TYPE_I32:
188667f84c96SRichard Henderson             opc = INDEX_op_setcond_i32;
18873635502dSRichard Henderson             if (TCG_TARGET_HAS_negsetcond_i32) {
18883635502dSRichard Henderson                 negopc = INDEX_op_negsetcond_i32;
18893635502dSRichard Henderson             }
18903635502dSRichard Henderson             tv = (int32_t)tv;
18913635502dSRichard Henderson             fv = (int32_t)fv;
189267f84c96SRichard Henderson             break;
189367f84c96SRichard Henderson         case TCG_TYPE_I64:
189467f84c96SRichard Henderson             opc = INDEX_op_setcond_i64;
18953635502dSRichard Henderson             if (TCG_TARGET_HAS_negsetcond_i64) {
18963635502dSRichard Henderson                 negopc = INDEX_op_negsetcond_i64;
18973635502dSRichard Henderson             }
189867f84c96SRichard Henderson             break;
189967f84c96SRichard Henderson         default:
190067f84c96SRichard Henderson             g_assert_not_reached();
190167f84c96SRichard Henderson         }
19020c310a30SRichard Henderson 
19030c310a30SRichard Henderson         if (tv == 1 && fv == 0) {
19040c310a30SRichard Henderson             op->opc = opc;
19050c310a30SRichard Henderson             op->args[3] = cond;
19060c310a30SRichard Henderson         } else if (fv == 1 && tv == 0) {
19070c310a30SRichard Henderson             op->opc = opc;
19080c310a30SRichard Henderson             op->args[3] = tcg_invert_cond(cond);
19093635502dSRichard Henderson         } else if (negopc) {
19103635502dSRichard Henderson             if (tv == -1 && fv == 0) {
19113635502dSRichard Henderson                 op->opc = negopc;
19123635502dSRichard Henderson                 op->args[3] = cond;
19133635502dSRichard Henderson             } else if (fv == -1 && tv == 0) {
19143635502dSRichard Henderson                 op->opc = negopc;
19153635502dSRichard Henderson                 op->args[3] = tcg_invert_cond(cond);
19163635502dSRichard Henderson             }
19170c310a30SRichard Henderson         }
19180c310a30SRichard Henderson     }
19190c310a30SRichard Henderson     return false;
19200c310a30SRichard Henderson }
19210c310a30SRichard Henderson 
fold_mul(OptContext * ctx,TCGOp * op)19222f9f08baSRichard Henderson static bool fold_mul(OptContext *ctx, TCGOp *op)
19232f9f08baSRichard Henderson {
1924e8679955SRichard Henderson     if (fold_const2(ctx, op) ||
19255b5cf479SRichard Henderson         fold_xi_to_i(ctx, op, 0) ||
19265b5cf479SRichard Henderson         fold_xi_to_x(ctx, op, 1)) {
1927e8679955SRichard Henderson         return true;
1928e8679955SRichard Henderson     }
1929e8679955SRichard Henderson     return false;
19302f9f08baSRichard Henderson }
19312f9f08baSRichard Henderson 
fold_mul_highpart(OptContext * ctx,TCGOp * op)19322f9f08baSRichard Henderson static bool fold_mul_highpart(OptContext *ctx, TCGOp *op)
19332f9f08baSRichard Henderson {
19347a2f7084SRichard Henderson     if (fold_const2_commutative(ctx, op) ||
1935e8679955SRichard Henderson         fold_xi_to_i(ctx, op, 0)) {
1936e8679955SRichard Henderson         return true;
1937e8679955SRichard Henderson     }
1938e8679955SRichard Henderson     return false;
19392f9f08baSRichard Henderson }
19402f9f08baSRichard Henderson 
fold_multiply2(OptContext * ctx,TCGOp * op)1941407112b0SRichard Henderson static bool fold_multiply2(OptContext *ctx, TCGOp *op)
19426b8ac0d1SRichard Henderson {
19437a2f7084SRichard Henderson     swap_commutative(op->args[0], &op->args[2], &op->args[3]);
19447a2f7084SRichard Henderson 
19456b8ac0d1SRichard Henderson     if (arg_is_const(op->args[2]) && arg_is_const(op->args[3])) {
1946407112b0SRichard Henderson         uint64_t a = arg_info(op->args[2])->val;
1947407112b0SRichard Henderson         uint64_t b = arg_info(op->args[3])->val;
1948407112b0SRichard Henderson         uint64_t h, l;
19496b8ac0d1SRichard Henderson         TCGArg rl, rh;
1950407112b0SRichard Henderson         TCGOp *op2;
1951407112b0SRichard Henderson 
1952407112b0SRichard Henderson         switch (op->opc) {
1953407112b0SRichard Henderson         case INDEX_op_mulu2_i32:
1954407112b0SRichard Henderson             l = (uint64_t)(uint32_t)a * (uint32_t)b;
1955407112b0SRichard Henderson             h = (int32_t)(l >> 32);
1956407112b0SRichard Henderson             l = (int32_t)l;
1957407112b0SRichard Henderson             break;
1958407112b0SRichard Henderson         case INDEX_op_muls2_i32:
1959407112b0SRichard Henderson             l = (int64_t)(int32_t)a * (int32_t)b;
1960407112b0SRichard Henderson             h = l >> 32;
1961407112b0SRichard Henderson             l = (int32_t)l;
1962407112b0SRichard Henderson             break;
1963407112b0SRichard Henderson         case INDEX_op_mulu2_i64:
1964407112b0SRichard Henderson             mulu64(&l, &h, a, b);
1965407112b0SRichard Henderson             break;
1966407112b0SRichard Henderson         case INDEX_op_muls2_i64:
1967407112b0SRichard Henderson             muls64(&l, &h, a, b);
1968407112b0SRichard Henderson             break;
1969407112b0SRichard Henderson         default:
1970407112b0SRichard Henderson             g_assert_not_reached();
1971407112b0SRichard Henderson         }
19726b8ac0d1SRichard Henderson 
19736b8ac0d1SRichard Henderson         rl = op->args[0];
19746b8ac0d1SRichard Henderson         rh = op->args[1];
1975407112b0SRichard Henderson 
1976407112b0SRichard Henderson         /* The proper opcode is supplied by tcg_opt_gen_mov. */
1977d4478943SPhilippe Mathieu-Daudé         op2 = tcg_op_insert_before(ctx->tcg, op, 0, 2);
1978407112b0SRichard Henderson 
1979407112b0SRichard Henderson         tcg_opt_gen_movi(ctx, op, rl, l);
1980407112b0SRichard Henderson         tcg_opt_gen_movi(ctx, op2, rh, h);
19816b8ac0d1SRichard Henderson         return true;
19826b8ac0d1SRichard Henderson     }
19836b8ac0d1SRichard Henderson     return false;
19846b8ac0d1SRichard Henderson }
19856b8ac0d1SRichard Henderson 
fold_nand(OptContext * ctx,TCGOp * op)19862f9f08baSRichard Henderson static bool fold_nand(OptContext *ctx, TCGOp *op)
19872f9f08baSRichard Henderson {
19887a2f7084SRichard Henderson     if (fold_const2_commutative(ctx, op) ||
19890e0a32baSRichard Henderson         fold_xi_to_not(ctx, op, -1)) {
19900e0a32baSRichard Henderson         return true;
19910e0a32baSRichard Henderson     }
19923f2b1f83SRichard Henderson 
19933f2b1f83SRichard Henderson     ctx->s_mask = arg_info(op->args[1])->s_mask
19943f2b1f83SRichard Henderson                 & arg_info(op->args[2])->s_mask;
19950e0a32baSRichard Henderson     return false;
19962f9f08baSRichard Henderson }
19972f9f08baSRichard Henderson 
fold_neg_no_const(OptContext * ctx,TCGOp * op)1998e25fe886SRichard Henderson static bool fold_neg_no_const(OptContext *ctx, TCGOp *op)
19992f9f08baSRichard Henderson {
2000fae450baSRichard Henderson     /* Set to 1 all bits to the left of the rightmost.  */
2001e25fe886SRichard Henderson     uint64_t z_mask = arg_info(op->args[1])->z_mask;
2002fae450baSRichard Henderson     ctx->z_mask = -(z_mask & -z_mask);
2003fae450baSRichard Henderson 
20049caca88aSRichard Henderson     /*
20059caca88aSRichard Henderson      * Because of fold_sub_to_neg, we want to always return true,
20069caca88aSRichard Henderson      * via finish_folding.
20079caca88aSRichard Henderson      */
20089caca88aSRichard Henderson     finish_folding(ctx, op);
20099caca88aSRichard Henderson     return true;
20102f9f08baSRichard Henderson }
20112f9f08baSRichard Henderson 
fold_neg(OptContext * ctx,TCGOp * op)2012e25fe886SRichard Henderson static bool fold_neg(OptContext *ctx, TCGOp *op)
2013e25fe886SRichard Henderson {
2014e25fe886SRichard Henderson     return fold_const1(ctx, op) || fold_neg_no_const(ctx, op);
2015e25fe886SRichard Henderson }
2016e25fe886SRichard Henderson 
fold_nor(OptContext * ctx,TCGOp * op)20172f9f08baSRichard Henderson static bool fold_nor(OptContext *ctx, TCGOp *op)
20182f9f08baSRichard Henderson {
20197a2f7084SRichard Henderson     if (fold_const2_commutative(ctx, op) ||
20200e0a32baSRichard Henderson         fold_xi_to_not(ctx, op, 0)) {
20210e0a32baSRichard Henderson         return true;
20220e0a32baSRichard Henderson     }
20233f2b1f83SRichard Henderson 
20243f2b1f83SRichard Henderson     ctx->s_mask = arg_info(op->args[1])->s_mask
20253f2b1f83SRichard Henderson                 & arg_info(op->args[2])->s_mask;
20260e0a32baSRichard Henderson     return false;
20272f9f08baSRichard Henderson }
20282f9f08baSRichard Henderson 
fold_not(OptContext * ctx,TCGOp * op)20292f9f08baSRichard Henderson static bool fold_not(OptContext *ctx, TCGOp *op)
20302f9f08baSRichard Henderson {
20310e0a32baSRichard Henderson     if (fold_const1(ctx, op)) {
20320e0a32baSRichard Henderson         return true;
20330e0a32baSRichard Henderson     }
20340e0a32baSRichard Henderson 
20353f2b1f83SRichard Henderson     ctx->s_mask = arg_info(op->args[1])->s_mask;
20363f2b1f83SRichard Henderson 
20370e0a32baSRichard Henderson     /* Because of fold_to_not, we want to always return true, via finish. */
20380e0a32baSRichard Henderson     finish_folding(ctx, op);
20390e0a32baSRichard Henderson     return true;
20402f9f08baSRichard Henderson }
20412f9f08baSRichard Henderson 
fold_or(OptContext * ctx,TCGOp * op)20422f9f08baSRichard Henderson static bool fold_or(OptContext *ctx, TCGOp *op)
20432f9f08baSRichard Henderson {
20447a2f7084SRichard Henderson     if (fold_const2_commutative(ctx, op) ||
2045a63ce0e9SRichard Henderson         fold_xi_to_x(ctx, op, 0) ||
2046ca7bb049SRichard Henderson         fold_xx_to_x(ctx, op)) {
2047ca7bb049SRichard Henderson         return true;
2048ca7bb049SRichard Henderson     }
2049fae450baSRichard Henderson 
2050fae450baSRichard Henderson     ctx->z_mask = arg_info(op->args[1])->z_mask
2051fae450baSRichard Henderson                 | arg_info(op->args[2])->z_mask;
20523f2b1f83SRichard Henderson     ctx->s_mask = arg_info(op->args[1])->s_mask
20533f2b1f83SRichard Henderson                 & arg_info(op->args[2])->s_mask;
2054fae450baSRichard Henderson     return fold_masks(ctx, op);
20552f9f08baSRichard Henderson }
20562f9f08baSRichard Henderson 
fold_orc(OptContext * ctx,TCGOp * op)20572f9f08baSRichard Henderson static bool fold_orc(OptContext *ctx, TCGOp *op)
20582f9f08baSRichard Henderson {
20590e0a32baSRichard Henderson     if (fold_const2(ctx, op) ||
20604e858d96SRichard Henderson         fold_xx_to_i(ctx, op, -1) ||
2061a63ce0e9SRichard Henderson         fold_xi_to_x(ctx, op, -1) ||
20620e0a32baSRichard Henderson         fold_ix_to_not(ctx, op, 0)) {
20630e0a32baSRichard Henderson         return true;
20640e0a32baSRichard Henderson     }
20653f2b1f83SRichard Henderson 
20663f2b1f83SRichard Henderson     ctx->s_mask = arg_info(op->args[1])->s_mask
20673f2b1f83SRichard Henderson                 & arg_info(op->args[2])->s_mask;
20680e0a32baSRichard Henderson     return false;
20692f9f08baSRichard Henderson }
20702f9f08baSRichard Henderson 
fold_qemu_ld(OptContext * ctx,TCGOp * op)20713eefdf2bSRichard Henderson static bool fold_qemu_ld(OptContext *ctx, TCGOp *op)
20723eefdf2bSRichard Henderson {
2073fae450baSRichard Henderson     const TCGOpDef *def = &tcg_op_defs[op->opc];
2074fae450baSRichard Henderson     MemOpIdx oi = op->args[def->nb_oargs + def->nb_iargs];
2075fae450baSRichard Henderson     MemOp mop = get_memop(oi);
2076fae450baSRichard Henderson     int width = 8 * memop_size(mop);
2077fae450baSRichard Henderson 
207857fe5c6dSRichard Henderson     if (width < 64) {
207957fe5c6dSRichard Henderson         ctx->s_mask = MAKE_64BIT_MASK(width, 64 - width);
208057fe5c6dSRichard Henderson         if (!(mop & MO_SIGN)) {
2081fae450baSRichard Henderson             ctx->z_mask = MAKE_64BIT_MASK(0, width);
208257fe5c6dSRichard Henderson             ctx->s_mask <<= 1;
208357fe5c6dSRichard Henderson         }
2084fae450baSRichard Henderson     }
2085fae450baSRichard Henderson 
20863eefdf2bSRichard Henderson     /* Opcodes that touch guest memory stop the mb optimization.  */
20873eefdf2bSRichard Henderson     ctx->prev_mb = NULL;
20883eefdf2bSRichard Henderson     return false;
20893eefdf2bSRichard Henderson }
20903eefdf2bSRichard Henderson 
fold_qemu_st(OptContext * ctx,TCGOp * op)20913eefdf2bSRichard Henderson static bool fold_qemu_st(OptContext *ctx, TCGOp *op)
20923eefdf2bSRichard Henderson {
20933eefdf2bSRichard Henderson     /* Opcodes that touch guest memory stop the mb optimization.  */
20943eefdf2bSRichard Henderson     ctx->prev_mb = NULL;
20953eefdf2bSRichard Henderson     return false;
20963eefdf2bSRichard Henderson }
20973eefdf2bSRichard Henderson 
fold_remainder(OptContext * ctx,TCGOp * op)20982f9f08baSRichard Henderson static bool fold_remainder(OptContext *ctx, TCGOp *op)
20992f9f08baSRichard Henderson {
2100267c17e8SRichard Henderson     if (fold_const2(ctx, op) ||
2101267c17e8SRichard Henderson         fold_xx_to_i(ctx, op, 0)) {
2102267c17e8SRichard Henderson         return true;
2103267c17e8SRichard Henderson     }
2104267c17e8SRichard Henderson     return false;
21052f9f08baSRichard Henderson }
21062f9f08baSRichard Henderson 
fold_setcond_zmask(OptContext * ctx,TCGOp * op,bool neg)21078d65cda7SRichard Henderson static bool fold_setcond_zmask(OptContext *ctx, TCGOp *op, bool neg)
21088d65cda7SRichard Henderson {
21098d65cda7SRichard Henderson     uint64_t a_zmask, b_val;
21108d65cda7SRichard Henderson     TCGCond cond;
21118d65cda7SRichard Henderson 
21128d65cda7SRichard Henderson     if (!arg_is_const(op->args[2])) {
21138d65cda7SRichard Henderson         return false;
21148d65cda7SRichard Henderson     }
21158d65cda7SRichard Henderson 
21168d65cda7SRichard Henderson     a_zmask = arg_info(op->args[1])->z_mask;
21178d65cda7SRichard Henderson     b_val = arg_info(op->args[2])->val;
21188d65cda7SRichard Henderson     cond = op->args[3];
21198d65cda7SRichard Henderson 
21208d65cda7SRichard Henderson     if (ctx->type == TCG_TYPE_I32) {
21218d65cda7SRichard Henderson         a_zmask = (uint32_t)a_zmask;
21228d65cda7SRichard Henderson         b_val = (uint32_t)b_val;
21238d65cda7SRichard Henderson     }
21248d65cda7SRichard Henderson 
21258d65cda7SRichard Henderson     /*
21268d65cda7SRichard Henderson      * A with only low bits set vs B with high bits set means that A < B.
21278d65cda7SRichard Henderson      */
21288d65cda7SRichard Henderson     if (a_zmask < b_val) {
21298d65cda7SRichard Henderson         bool inv = false;
21308d65cda7SRichard Henderson 
21318d65cda7SRichard Henderson         switch (cond) {
21328d65cda7SRichard Henderson         case TCG_COND_NE:
21338d65cda7SRichard Henderson         case TCG_COND_LEU:
21348d65cda7SRichard Henderson         case TCG_COND_LTU:
21358d65cda7SRichard Henderson             inv = true;
21368d65cda7SRichard Henderson             /* fall through */
21378d65cda7SRichard Henderson         case TCG_COND_GTU:
21388d65cda7SRichard Henderson         case TCG_COND_GEU:
21398d65cda7SRichard Henderson         case TCG_COND_EQ:
21408d65cda7SRichard Henderson             return tcg_opt_gen_movi(ctx, op, op->args[0], neg ? -inv : inv);
21418d65cda7SRichard Henderson         default:
21428d65cda7SRichard Henderson             break;
21438d65cda7SRichard Henderson         }
21448d65cda7SRichard Henderson     }
21458d65cda7SRichard Henderson 
21468d65cda7SRichard Henderson     /*
21478d65cda7SRichard Henderson      * A with only lsb set is already boolean.
21488d65cda7SRichard Henderson      */
21498d65cda7SRichard Henderson     if (a_zmask <= 1) {
21508d65cda7SRichard Henderson         bool convert = false;
21518d65cda7SRichard Henderson         bool inv = false;
21528d65cda7SRichard Henderson 
21538d65cda7SRichard Henderson         switch (cond) {
21548d65cda7SRichard Henderson         case TCG_COND_EQ:
21558d65cda7SRichard Henderson             inv = true;
21568d65cda7SRichard Henderson             /* fall through */
21578d65cda7SRichard Henderson         case TCG_COND_NE:
21588d65cda7SRichard Henderson             convert = (b_val == 0);
21598d65cda7SRichard Henderson             break;
21608d65cda7SRichard Henderson         case TCG_COND_LTU:
21618d65cda7SRichard Henderson         case TCG_COND_TSTEQ:
21628d65cda7SRichard Henderson             inv = true;
21638d65cda7SRichard Henderson             /* fall through */
21648d65cda7SRichard Henderson         case TCG_COND_GEU:
21658d65cda7SRichard Henderson         case TCG_COND_TSTNE:
21668d65cda7SRichard Henderson             convert = (b_val == 1);
21678d65cda7SRichard Henderson             break;
21688d65cda7SRichard Henderson         default:
21698d65cda7SRichard Henderson             break;
21708d65cda7SRichard Henderson         }
21718d65cda7SRichard Henderson         if (convert) {
21728d65cda7SRichard Henderson             TCGOpcode add_opc, xor_opc, neg_opc;
21738d65cda7SRichard Henderson 
21748d65cda7SRichard Henderson             if (!inv && !neg) {
21758d65cda7SRichard Henderson                 return tcg_opt_gen_mov(ctx, op, op->args[0], op->args[1]);
21768d65cda7SRichard Henderson             }
21778d65cda7SRichard Henderson 
21788d65cda7SRichard Henderson             switch (ctx->type) {
21798d65cda7SRichard Henderson             case TCG_TYPE_I32:
21808d65cda7SRichard Henderson                 add_opc = INDEX_op_add_i32;
21818d65cda7SRichard Henderson                 neg_opc = INDEX_op_neg_i32;
21828d65cda7SRichard Henderson                 xor_opc = INDEX_op_xor_i32;
21838d65cda7SRichard Henderson                 break;
21848d65cda7SRichard Henderson             case TCG_TYPE_I64:
21858d65cda7SRichard Henderson                 add_opc = INDEX_op_add_i64;
21868d65cda7SRichard Henderson                 neg_opc = INDEX_op_neg_i64;
21878d65cda7SRichard Henderson                 xor_opc = INDEX_op_xor_i64;
21888d65cda7SRichard Henderson                 break;
21898d65cda7SRichard Henderson             default:
21908d65cda7SRichard Henderson                 g_assert_not_reached();
21918d65cda7SRichard Henderson             }
21928d65cda7SRichard Henderson 
21938d65cda7SRichard Henderson             if (!inv) {
21948d65cda7SRichard Henderson                 op->opc = neg_opc;
21958d65cda7SRichard Henderson             } else if (neg) {
21968d65cda7SRichard Henderson                 op->opc = add_opc;
21978d65cda7SRichard Henderson                 op->args[2] = arg_new_constant(ctx, -1);
21988d65cda7SRichard Henderson             } else {
21998d65cda7SRichard Henderson                 op->opc = xor_opc;
22008d65cda7SRichard Henderson                 op->args[2] = arg_new_constant(ctx, 1);
22018d65cda7SRichard Henderson             }
22028d65cda7SRichard Henderson             return false;
22038d65cda7SRichard Henderson         }
22048d65cda7SRichard Henderson     }
22058d65cda7SRichard Henderson 
22068d65cda7SRichard Henderson     return false;
22078d65cda7SRichard Henderson }
22088d65cda7SRichard Henderson 
fold_setcond_tst_pow2(OptContext * ctx,TCGOp * op,bool neg)2209ceb9ee06SRichard Henderson static void fold_setcond_tst_pow2(OptContext *ctx, TCGOp *op, bool neg)
2210ceb9ee06SRichard Henderson {
2211ff202817SPaolo Bonzini     TCGOpcode and_opc, sub_opc, xor_opc, neg_opc, shr_opc;
2212ff202817SPaolo Bonzini     TCGOpcode uext_opc = 0, sext_opc = 0;
2213ceb9ee06SRichard Henderson     TCGCond cond = op->args[3];
2214ceb9ee06SRichard Henderson     TCGArg ret, src1, src2;
2215ceb9ee06SRichard Henderson     TCGOp *op2;
2216ceb9ee06SRichard Henderson     uint64_t val;
2217ceb9ee06SRichard Henderson     int sh;
2218ceb9ee06SRichard Henderson     bool inv;
2219ceb9ee06SRichard Henderson 
2220ceb9ee06SRichard Henderson     if (!is_tst_cond(cond) || !arg_is_const(op->args[2])) {
2221ceb9ee06SRichard Henderson         return;
2222ceb9ee06SRichard Henderson     }
2223ceb9ee06SRichard Henderson 
2224ceb9ee06SRichard Henderson     src2 = op->args[2];
2225ceb9ee06SRichard Henderson     val = arg_info(src2)->val;
2226ceb9ee06SRichard Henderson     if (!is_power_of_2(val)) {
2227ceb9ee06SRichard Henderson         return;
2228ceb9ee06SRichard Henderson     }
2229ceb9ee06SRichard Henderson     sh = ctz64(val);
2230ceb9ee06SRichard Henderson 
2231ceb9ee06SRichard Henderson     switch (ctx->type) {
2232ceb9ee06SRichard Henderson     case TCG_TYPE_I32:
2233ceb9ee06SRichard Henderson         and_opc = INDEX_op_and_i32;
2234ceb9ee06SRichard Henderson         sub_opc = INDEX_op_sub_i32;
2235ceb9ee06SRichard Henderson         xor_opc = INDEX_op_xor_i32;
2236ceb9ee06SRichard Henderson         shr_opc = INDEX_op_shr_i32;
2237ceb9ee06SRichard Henderson         neg_opc = INDEX_op_neg_i32;
2238ceb9ee06SRichard Henderson         if (TCG_TARGET_extract_i32_valid(sh, 1)) {
2239ceb9ee06SRichard Henderson             uext_opc = TCG_TARGET_HAS_extract_i32 ? INDEX_op_extract_i32 : 0;
2240ceb9ee06SRichard Henderson             sext_opc = TCG_TARGET_HAS_sextract_i32 ? INDEX_op_sextract_i32 : 0;
2241ceb9ee06SRichard Henderson         }
2242ceb9ee06SRichard Henderson         break;
2243ceb9ee06SRichard Henderson     case TCG_TYPE_I64:
2244ceb9ee06SRichard Henderson         and_opc = INDEX_op_and_i64;
2245ceb9ee06SRichard Henderson         sub_opc = INDEX_op_sub_i64;
2246ceb9ee06SRichard Henderson         xor_opc = INDEX_op_xor_i64;
2247ceb9ee06SRichard Henderson         shr_opc = INDEX_op_shr_i64;
2248ceb9ee06SRichard Henderson         neg_opc = INDEX_op_neg_i64;
2249ceb9ee06SRichard Henderson         if (TCG_TARGET_extract_i64_valid(sh, 1)) {
2250ceb9ee06SRichard Henderson             uext_opc = TCG_TARGET_HAS_extract_i64 ? INDEX_op_extract_i64 : 0;
2251ceb9ee06SRichard Henderson             sext_opc = TCG_TARGET_HAS_sextract_i64 ? INDEX_op_sextract_i64 : 0;
2252ceb9ee06SRichard Henderson         }
2253ceb9ee06SRichard Henderson         break;
2254ceb9ee06SRichard Henderson     default:
2255ceb9ee06SRichard Henderson         g_assert_not_reached();
2256ceb9ee06SRichard Henderson     }
2257ceb9ee06SRichard Henderson 
2258ceb9ee06SRichard Henderson     ret = op->args[0];
2259ceb9ee06SRichard Henderson     src1 = op->args[1];
2260ceb9ee06SRichard Henderson     inv = cond == TCG_COND_TSTEQ;
2261ceb9ee06SRichard Henderson 
2262ceb9ee06SRichard Henderson     if (sh && sext_opc && neg && !inv) {
2263ceb9ee06SRichard Henderson         op->opc = sext_opc;
2264ceb9ee06SRichard Henderson         op->args[1] = src1;
2265ceb9ee06SRichard Henderson         op->args[2] = sh;
2266ceb9ee06SRichard Henderson         op->args[3] = 1;
2267ceb9ee06SRichard Henderson         return;
2268ceb9ee06SRichard Henderson     } else if (sh && uext_opc) {
2269ceb9ee06SRichard Henderson         op->opc = uext_opc;
2270ceb9ee06SRichard Henderson         op->args[1] = src1;
2271ceb9ee06SRichard Henderson         op->args[2] = sh;
2272ceb9ee06SRichard Henderson         op->args[3] = 1;
2273ceb9ee06SRichard Henderson     } else {
2274ceb9ee06SRichard Henderson         if (sh) {
2275ceb9ee06SRichard Henderson             op2 = tcg_op_insert_before(ctx->tcg, op, shr_opc, 3);
2276ceb9ee06SRichard Henderson             op2->args[0] = ret;
2277ceb9ee06SRichard Henderson             op2->args[1] = src1;
2278ceb9ee06SRichard Henderson             op2->args[2] = arg_new_constant(ctx, sh);
2279ceb9ee06SRichard Henderson             src1 = ret;
2280ceb9ee06SRichard Henderson         }
2281ceb9ee06SRichard Henderson         op->opc = and_opc;
2282ceb9ee06SRichard Henderson         op->args[1] = src1;
2283ceb9ee06SRichard Henderson         op->args[2] = arg_new_constant(ctx, 1);
2284ceb9ee06SRichard Henderson     }
2285ceb9ee06SRichard Henderson 
2286ceb9ee06SRichard Henderson     if (neg && inv) {
2287ceb9ee06SRichard Henderson         op2 = tcg_op_insert_after(ctx->tcg, op, sub_opc, 3);
2288ceb9ee06SRichard Henderson         op2->args[0] = ret;
2289ceb9ee06SRichard Henderson         op2->args[1] = ret;
2290ceb9ee06SRichard Henderson         op2->args[2] = arg_new_constant(ctx, 1);
2291ceb9ee06SRichard Henderson     } else if (inv) {
2292ceb9ee06SRichard Henderson         op2 = tcg_op_insert_after(ctx->tcg, op, xor_opc, 3);
2293ceb9ee06SRichard Henderson         op2->args[0] = ret;
2294ceb9ee06SRichard Henderson         op2->args[1] = ret;
2295ceb9ee06SRichard Henderson         op2->args[2] = arg_new_constant(ctx, 1);
2296ceb9ee06SRichard Henderson     } else if (neg) {
2297ceb9ee06SRichard Henderson         op2 = tcg_op_insert_after(ctx->tcg, op, neg_opc, 2);
2298ceb9ee06SRichard Henderson         op2->args[0] = ret;
2299ceb9ee06SRichard Henderson         op2->args[1] = ret;
2300ceb9ee06SRichard Henderson     }
2301ceb9ee06SRichard Henderson }
2302ceb9ee06SRichard Henderson 
fold_setcond(OptContext * ctx,TCGOp * op)2303c63ff55cSRichard Henderson static bool fold_setcond(OptContext *ctx, TCGOp *op)
2304c63ff55cSRichard Henderson {
2305fb04ab7dSRichard Henderson     int i = do_constant_folding_cond1(ctx, op, op->args[0], &op->args[1],
2306246c4b72SRichard Henderson                                       &op->args[2], &op->args[3]);
2307c63ff55cSRichard Henderson     if (i >= 0) {
2308c63ff55cSRichard Henderson         return tcg_opt_gen_movi(ctx, op, op->args[0], i);
2309c63ff55cSRichard Henderson     }
23108d65cda7SRichard Henderson 
23118d65cda7SRichard Henderson     if (fold_setcond_zmask(ctx, op, false)) {
23128d65cda7SRichard Henderson         return true;
23138d65cda7SRichard Henderson     }
2314ceb9ee06SRichard Henderson     fold_setcond_tst_pow2(ctx, op, false);
2315fae450baSRichard Henderson 
2316fae450baSRichard Henderson     ctx->z_mask = 1;
2317275d7d8eSRichard Henderson     ctx->s_mask = smask_from_zmask(1);
2318c63ff55cSRichard Henderson     return false;
2319c63ff55cSRichard Henderson }
2320c63ff55cSRichard Henderson 
fold_negsetcond(OptContext * ctx,TCGOp * op)23213635502dSRichard Henderson static bool fold_negsetcond(OptContext *ctx, TCGOp *op)
23223635502dSRichard Henderson {
2323fb04ab7dSRichard Henderson     int i = do_constant_folding_cond1(ctx, op, op->args[0], &op->args[1],
2324246c4b72SRichard Henderson                                       &op->args[2], &op->args[3]);
23253635502dSRichard Henderson     if (i >= 0) {
23263635502dSRichard Henderson         return tcg_opt_gen_movi(ctx, op, op->args[0], -i);
23273635502dSRichard Henderson     }
23288d65cda7SRichard Henderson 
23298d65cda7SRichard Henderson     if (fold_setcond_zmask(ctx, op, true)) {
23308d65cda7SRichard Henderson         return true;
23318d65cda7SRichard Henderson     }
2332ceb9ee06SRichard Henderson     fold_setcond_tst_pow2(ctx, op, true);
23333635502dSRichard Henderson 
23343635502dSRichard Henderson     /* Value is {0,-1} so all bits are repetitions of the sign. */
23353635502dSRichard Henderson     ctx->s_mask = -1;
23363635502dSRichard Henderson     return false;
23373635502dSRichard Henderson }
23383635502dSRichard Henderson 
fold_setcond2(OptContext * ctx,TCGOp * op)2339bc47b1aaSRichard Henderson static bool fold_setcond2(OptContext *ctx, TCGOp *op)
2340bc47b1aaSRichard Henderson {
23417e64b114SRichard Henderson     TCGCond cond;
23427a2f7084SRichard Henderson     int i, inv = 0;
2343bc47b1aaSRichard Henderson 
2344fb04ab7dSRichard Henderson     i = do_constant_folding_cond2(ctx, op, &op->args[1]);
23457e64b114SRichard Henderson     cond = op->args[5];
2346bc47b1aaSRichard Henderson     if (i >= 0) {
2347bc47b1aaSRichard Henderson         goto do_setcond_const;
2348bc47b1aaSRichard Henderson     }
2349bc47b1aaSRichard Henderson 
2350bc47b1aaSRichard Henderson     switch (cond) {
2351bc47b1aaSRichard Henderson     case TCG_COND_LT:
2352bc47b1aaSRichard Henderson     case TCG_COND_GE:
2353bc47b1aaSRichard Henderson         /*
2354bc47b1aaSRichard Henderson          * Simplify LT/GE comparisons vs zero to a single compare
2355bc47b1aaSRichard Henderson          * vs the high word of the input.
2356bc47b1aaSRichard Henderson          */
235727cdb85dSRichard Henderson         if (arg_is_const_val(op->args[3], 0) &&
235827cdb85dSRichard Henderson             arg_is_const_val(op->args[4], 0)) {
2359bc47b1aaSRichard Henderson             goto do_setcond_high;
2360bc47b1aaSRichard Henderson         }
2361bc47b1aaSRichard Henderson         break;
2362bc47b1aaSRichard Henderson 
2363bc47b1aaSRichard Henderson     case TCG_COND_NE:
2364bc47b1aaSRichard Henderson         inv = 1;
2365bc47b1aaSRichard Henderson         QEMU_FALLTHROUGH;
2366bc47b1aaSRichard Henderson     case TCG_COND_EQ:
2367bc47b1aaSRichard Henderson         /*
2368bc47b1aaSRichard Henderson          * Simplify EQ/NE comparisons where one of the pairs
2369bc47b1aaSRichard Henderson          * can be simplified.
2370bc47b1aaSRichard Henderson          */
237167f84c96SRichard Henderson         i = do_constant_folding_cond(TCG_TYPE_I32, op->args[1],
2372bc47b1aaSRichard Henderson                                      op->args[3], cond);
2373bc47b1aaSRichard Henderson         switch (i ^ inv) {
2374bc47b1aaSRichard Henderson         case 0:
2375bc47b1aaSRichard Henderson             goto do_setcond_const;
2376bc47b1aaSRichard Henderson         case 1:
2377bc47b1aaSRichard Henderson             goto do_setcond_high;
2378bc47b1aaSRichard Henderson         }
2379bc47b1aaSRichard Henderson 
238067f84c96SRichard Henderson         i = do_constant_folding_cond(TCG_TYPE_I32, op->args[2],
2381bc47b1aaSRichard Henderson                                      op->args[4], cond);
2382bc47b1aaSRichard Henderson         switch (i ^ inv) {
2383bc47b1aaSRichard Henderson         case 0:
2384bc47b1aaSRichard Henderson             goto do_setcond_const;
2385bc47b1aaSRichard Henderson         case 1:
2386ceb9ee06SRichard Henderson             goto do_setcond_low;
2387ceb9ee06SRichard Henderson         }
2388bc47b1aaSRichard Henderson         break;
2389ceb9ee06SRichard Henderson 
2390ceb9ee06SRichard Henderson     case TCG_COND_TSTEQ:
2391ceb9ee06SRichard Henderson     case TCG_COND_TSTNE:
2392a71d9dfbSRichard Henderson         if (arg_is_const_val(op->args[3], 0)) {
2393ceb9ee06SRichard Henderson             goto do_setcond_high;
2394ceb9ee06SRichard Henderson         }
2395ceb9ee06SRichard Henderson         if (arg_is_const_val(op->args[4], 0)) {
2396ceb9ee06SRichard Henderson             goto do_setcond_low;
2397bc47b1aaSRichard Henderson         }
2398bc47b1aaSRichard Henderson         break;
2399bc47b1aaSRichard Henderson 
2400bc47b1aaSRichard Henderson     default:
2401bc47b1aaSRichard Henderson         break;
2402bc47b1aaSRichard Henderson 
2403ceb9ee06SRichard Henderson     do_setcond_low:
2404ceb9ee06SRichard Henderson         op->args[2] = op->args[3];
2405ceb9ee06SRichard Henderson         op->args[3] = cond;
2406ceb9ee06SRichard Henderson         op->opc = INDEX_op_setcond_i32;
2407ceb9ee06SRichard Henderson         return fold_setcond(ctx, op);
2408ceb9ee06SRichard Henderson 
2409bc47b1aaSRichard Henderson     do_setcond_high:
2410bc47b1aaSRichard Henderson         op->args[1] = op->args[2];
2411bc47b1aaSRichard Henderson         op->args[2] = op->args[4];
2412bc47b1aaSRichard Henderson         op->args[3] = cond;
2413bc47b1aaSRichard Henderson         op->opc = INDEX_op_setcond_i32;
2414ceb9ee06SRichard Henderson         return fold_setcond(ctx, op);
2415bc47b1aaSRichard Henderson     }
2416fae450baSRichard Henderson 
2417fae450baSRichard Henderson     ctx->z_mask = 1;
2418275d7d8eSRichard Henderson     ctx->s_mask = smask_from_zmask(1);
2419bc47b1aaSRichard Henderson     return false;
2420bc47b1aaSRichard Henderson 
2421bc47b1aaSRichard Henderson  do_setcond_const:
2422bc47b1aaSRichard Henderson     return tcg_opt_gen_movi(ctx, op, op->args[0], i);
2423bc47b1aaSRichard Henderson }
2424bc47b1aaSRichard Henderson 
fold_cmp_vec(OptContext * ctx,TCGOp * op)24251f106544SRichard Henderson static bool fold_cmp_vec(OptContext *ctx, TCGOp *op)
24261f106544SRichard Henderson {
24271f106544SRichard Henderson     /* Canonicalize the comparison to put immediate second. */
24281f106544SRichard Henderson     if (swap_commutative(NO_DEST, &op->args[1], &op->args[2])) {
24291f106544SRichard Henderson         op->args[3] = tcg_swap_cond(op->args[3]);
24301f106544SRichard Henderson     }
24311f106544SRichard Henderson     return false;
24321f106544SRichard Henderson }
24331f106544SRichard Henderson 
fold_cmpsel_vec(OptContext * ctx,TCGOp * op)24341f106544SRichard Henderson static bool fold_cmpsel_vec(OptContext *ctx, TCGOp *op)
24351f106544SRichard Henderson {
24361f106544SRichard Henderson     /* If true and false values are the same, eliminate the cmp. */
24371f106544SRichard Henderson     if (args_are_copies(op->args[3], op->args[4])) {
24381f106544SRichard Henderson         return tcg_opt_gen_mov(ctx, op, op->args[0], op->args[3]);
24391f106544SRichard Henderson     }
24401f106544SRichard Henderson 
24411f106544SRichard Henderson     /* Canonicalize the comparison to put immediate second. */
24421f106544SRichard Henderson     if (swap_commutative(NO_DEST, &op->args[1], &op->args[2])) {
24431f106544SRichard Henderson         op->args[5] = tcg_swap_cond(op->args[5]);
24441f106544SRichard Henderson     }
24451f106544SRichard Henderson     /*
24461f106544SRichard Henderson      * Canonicalize the "false" input reg to match the destination,
24471f106544SRichard Henderson      * so that the tcg backend can implement "move if true".
24481f106544SRichard Henderson      */
24491f106544SRichard Henderson     if (swap_commutative(op->args[0], &op->args[4], &op->args[3])) {
24501f106544SRichard Henderson         op->args[5] = tcg_invert_cond(op->args[5]);
24511f106544SRichard Henderson     }
24521f106544SRichard Henderson     return false;
24531f106544SRichard Henderson }
24541f106544SRichard Henderson 
fold_sextract(OptContext * ctx,TCGOp * op)2455b6617c88SRichard Henderson static bool fold_sextract(OptContext *ctx, TCGOp *op)
2456b6617c88SRichard Henderson {
245757fe5c6dSRichard Henderson     uint64_t z_mask, s_mask, s_mask_old;
245857fe5c6dSRichard Henderson     int pos = op->args[2];
245957fe5c6dSRichard Henderson     int len = op->args[3];
2460fae450baSRichard Henderson 
2461b6617c88SRichard Henderson     if (arg_is_const(op->args[1])) {
2462b6617c88SRichard Henderson         uint64_t t;
2463b6617c88SRichard Henderson 
2464b6617c88SRichard Henderson         t = arg_info(op->args[1])->val;
246557fe5c6dSRichard Henderson         t = sextract64(t, pos, len);
2466b6617c88SRichard Henderson         return tcg_opt_gen_movi(ctx, op, op->args[0], t);
2467b6617c88SRichard Henderson     }
2468fae450baSRichard Henderson 
246957fe5c6dSRichard Henderson     z_mask = arg_info(op->args[1])->z_mask;
247057fe5c6dSRichard Henderson     z_mask = sextract64(z_mask, pos, len);
2471fae450baSRichard Henderson     ctx->z_mask = z_mask;
2472fae450baSRichard Henderson 
247357fe5c6dSRichard Henderson     s_mask_old = arg_info(op->args[1])->s_mask;
247457fe5c6dSRichard Henderson     s_mask = sextract64(s_mask_old, pos, len);
247557fe5c6dSRichard Henderson     s_mask |= MAKE_64BIT_MASK(len, 64 - len);
247657fe5c6dSRichard Henderson     ctx->s_mask = s_mask;
247757fe5c6dSRichard Henderson 
247857fe5c6dSRichard Henderson     if (pos == 0) {
247957fe5c6dSRichard Henderson         ctx->a_mask = s_mask & ~s_mask_old;
248057fe5c6dSRichard Henderson     }
248157fe5c6dSRichard Henderson 
2482fae450baSRichard Henderson     return fold_masks(ctx, op);
2483b6617c88SRichard Henderson }
2484b6617c88SRichard Henderson 
fold_shift(OptContext * ctx,TCGOp * op)24852f9f08baSRichard Henderson static bool fold_shift(OptContext *ctx, TCGOp *op)
24862f9f08baSRichard Henderson {
248793a967fbSRichard Henderson     uint64_t s_mask, z_mask, sign;
248893a967fbSRichard Henderson 
2489a63ce0e9SRichard Henderson     if (fold_const2(ctx, op) ||
2490da48e272SRichard Henderson         fold_ix_to_i(ctx, op, 0) ||
2491a63ce0e9SRichard Henderson         fold_xi_to_x(ctx, op, 0)) {
2492a63ce0e9SRichard Henderson         return true;
2493a63ce0e9SRichard Henderson     }
2494fae450baSRichard Henderson 
249593a967fbSRichard Henderson     s_mask = arg_info(op->args[1])->s_mask;
249693a967fbSRichard Henderson     z_mask = arg_info(op->args[1])->z_mask;
249793a967fbSRichard Henderson 
2498fae450baSRichard Henderson     if (arg_is_const(op->args[2])) {
249993a967fbSRichard Henderson         int sh = arg_info(op->args[2])->val;
250093a967fbSRichard Henderson 
250193a967fbSRichard Henderson         ctx->z_mask = do_constant_folding(op->opc, ctx->type, z_mask, sh);
250293a967fbSRichard Henderson 
250393a967fbSRichard Henderson         s_mask = do_constant_folding(op->opc, ctx->type, s_mask, sh);
250493a967fbSRichard Henderson         ctx->s_mask = smask_from_smask(s_mask);
250593a967fbSRichard Henderson 
2506fae450baSRichard Henderson         return fold_masks(ctx, op);
2507fae450baSRichard Henderson     }
250893a967fbSRichard Henderson 
250993a967fbSRichard Henderson     switch (op->opc) {
251093a967fbSRichard Henderson     CASE_OP_32_64(sar):
251193a967fbSRichard Henderson         /*
251293a967fbSRichard Henderson          * Arithmetic right shift will not reduce the number of
251393a967fbSRichard Henderson          * input sign repetitions.
251493a967fbSRichard Henderson          */
251593a967fbSRichard Henderson         ctx->s_mask = s_mask;
251693a967fbSRichard Henderson         break;
251793a967fbSRichard Henderson     CASE_OP_32_64(shr):
251893a967fbSRichard Henderson         /*
251993a967fbSRichard Henderson          * If the sign bit is known zero, then logical right shift
252093a967fbSRichard Henderson          * will not reduced the number of input sign repetitions.
252193a967fbSRichard Henderson          */
252293a967fbSRichard Henderson         sign = (s_mask & -s_mask) >> 1;
25232911e9b9SRichard Henderson         if (sign && !(z_mask & sign)) {
252493a967fbSRichard Henderson             ctx->s_mask = s_mask;
252593a967fbSRichard Henderson         }
252693a967fbSRichard Henderson         break;
252793a967fbSRichard Henderson     default:
252893a967fbSRichard Henderson         break;
252993a967fbSRichard Henderson     }
253093a967fbSRichard Henderson 
2531a63ce0e9SRichard Henderson     return false;
25322f9f08baSRichard Henderson }
25332f9f08baSRichard Henderson 
fold_sub_to_neg(OptContext * ctx,TCGOp * op)25349caca88aSRichard Henderson static bool fold_sub_to_neg(OptContext *ctx, TCGOp *op)
25359caca88aSRichard Henderson {
25369caca88aSRichard Henderson     TCGOpcode neg_op;
25379caca88aSRichard Henderson     bool have_neg;
25389caca88aSRichard Henderson 
25399caca88aSRichard Henderson     if (!arg_is_const(op->args[1]) || arg_info(op->args[1])->val != 0) {
25409caca88aSRichard Henderson         return false;
25419caca88aSRichard Henderson     }
25429caca88aSRichard Henderson 
25439caca88aSRichard Henderson     switch (ctx->type) {
25449caca88aSRichard Henderson     case TCG_TYPE_I32:
25459caca88aSRichard Henderson         neg_op = INDEX_op_neg_i32;
2546b701f195SRichard Henderson         have_neg = true;
25479caca88aSRichard Henderson         break;
25489caca88aSRichard Henderson     case TCG_TYPE_I64:
25499caca88aSRichard Henderson         neg_op = INDEX_op_neg_i64;
2550b701f195SRichard Henderson         have_neg = true;
25519caca88aSRichard Henderson         break;
25529caca88aSRichard Henderson     case TCG_TYPE_V64:
25539caca88aSRichard Henderson     case TCG_TYPE_V128:
25549caca88aSRichard Henderson     case TCG_TYPE_V256:
25559caca88aSRichard Henderson         neg_op = INDEX_op_neg_vec;
25569caca88aSRichard Henderson         have_neg = (TCG_TARGET_HAS_neg_vec &&
25579caca88aSRichard Henderson                     tcg_can_emit_vec_op(neg_op, ctx->type, TCGOP_VECE(op)) > 0);
25589caca88aSRichard Henderson         break;
25599caca88aSRichard Henderson     default:
25609caca88aSRichard Henderson         g_assert_not_reached();
25619caca88aSRichard Henderson     }
25629caca88aSRichard Henderson     if (have_neg) {
25639caca88aSRichard Henderson         op->opc = neg_op;
25649caca88aSRichard Henderson         op->args[1] = op->args[2];
2565e25fe886SRichard Henderson         return fold_neg_no_const(ctx, op);
25669caca88aSRichard Henderson     }
25679caca88aSRichard Henderson     return false;
25689caca88aSRichard Henderson }
25699caca88aSRichard Henderson 
2570c578ff18SRichard Henderson /* We cannot as yet do_constant_folding with vectors. */
fold_sub_vec(OptContext * ctx,TCGOp * op)2571c578ff18SRichard Henderson static bool fold_sub_vec(OptContext *ctx, TCGOp *op)
25722f9f08baSRichard Henderson {
2573c578ff18SRichard Henderson     if (fold_xx_to_i(ctx, op, 0) ||
2574a63ce0e9SRichard Henderson         fold_xi_to_x(ctx, op, 0) ||
25759caca88aSRichard Henderson         fold_sub_to_neg(ctx, op)) {
2576cbe42fb2SRichard Henderson         return true;
2577cbe42fb2SRichard Henderson     }
2578cbe42fb2SRichard Henderson     return false;
25792f9f08baSRichard Henderson }
25802f9f08baSRichard Henderson 
fold_sub(OptContext * ctx,TCGOp * op)2581c578ff18SRichard Henderson static bool fold_sub(OptContext *ctx, TCGOp *op)
2582c578ff18SRichard Henderson {
25836334a968SRichard Henderson     if (fold_const2(ctx, op) || fold_sub_vec(ctx, op)) {
25846334a968SRichard Henderson         return true;
25856334a968SRichard Henderson     }
25866334a968SRichard Henderson 
25876334a968SRichard Henderson     /* Fold sub r,x,i to add r,x,-i */
25886334a968SRichard Henderson     if (arg_is_const(op->args[2])) {
25896334a968SRichard Henderson         uint64_t val = arg_info(op->args[2])->val;
25906334a968SRichard Henderson 
25916334a968SRichard Henderson         op->opc = (ctx->type == TCG_TYPE_I32
25926334a968SRichard Henderson                    ? INDEX_op_add_i32 : INDEX_op_add_i64);
25936334a968SRichard Henderson         op->args[2] = arg_new_constant(ctx, -val);
25946334a968SRichard Henderson     }
25956334a968SRichard Henderson     return false;
2596c578ff18SRichard Henderson }
2597c578ff18SRichard Henderson 
fold_sub2(OptContext * ctx,TCGOp * op)25989531c078SRichard Henderson static bool fold_sub2(OptContext *ctx, TCGOp *op)
2599e3f7dc21SRichard Henderson {
26009531c078SRichard Henderson     return fold_addsub2(ctx, op, false);
2601e3f7dc21SRichard Henderson }
2602e3f7dc21SRichard Henderson 
fold_tcg_ld(OptContext * ctx,TCGOp * op)2603fae450baSRichard Henderson static bool fold_tcg_ld(OptContext *ctx, TCGOp *op)
2604fae450baSRichard Henderson {
2605fae450baSRichard Henderson     /* We can't do any folding with a load, but we can record bits. */
2606fae450baSRichard Henderson     switch (op->opc) {
260757fe5c6dSRichard Henderson     CASE_OP_32_64(ld8s):
260857fe5c6dSRichard Henderson         ctx->s_mask = MAKE_64BIT_MASK(8, 56);
260957fe5c6dSRichard Henderson         break;
2610fae450baSRichard Henderson     CASE_OP_32_64(ld8u):
2611fae450baSRichard Henderson         ctx->z_mask = MAKE_64BIT_MASK(0, 8);
261257fe5c6dSRichard Henderson         ctx->s_mask = MAKE_64BIT_MASK(9, 55);
261357fe5c6dSRichard Henderson         break;
261457fe5c6dSRichard Henderson     CASE_OP_32_64(ld16s):
261557fe5c6dSRichard Henderson         ctx->s_mask = MAKE_64BIT_MASK(16, 48);
2616fae450baSRichard Henderson         break;
2617fae450baSRichard Henderson     CASE_OP_32_64(ld16u):
2618fae450baSRichard Henderson         ctx->z_mask = MAKE_64BIT_MASK(0, 16);
261957fe5c6dSRichard Henderson         ctx->s_mask = MAKE_64BIT_MASK(17, 47);
262057fe5c6dSRichard Henderson         break;
262157fe5c6dSRichard Henderson     case INDEX_op_ld32s_i64:
262257fe5c6dSRichard Henderson         ctx->s_mask = MAKE_64BIT_MASK(32, 32);
2623fae450baSRichard Henderson         break;
2624fae450baSRichard Henderson     case INDEX_op_ld32u_i64:
2625fae450baSRichard Henderson         ctx->z_mask = MAKE_64BIT_MASK(0, 32);
262657fe5c6dSRichard Henderson         ctx->s_mask = MAKE_64BIT_MASK(33, 31);
2627fae450baSRichard Henderson         break;
2628fae450baSRichard Henderson     default:
2629fae450baSRichard Henderson         g_assert_not_reached();
2630fae450baSRichard Henderson     }
2631fae450baSRichard Henderson     return false;
2632fae450baSRichard Henderson }
2633fae450baSRichard Henderson 
fold_tcg_ld_memcopy(OptContext * ctx,TCGOp * op)2634ab84dc39SRichard Henderson static bool fold_tcg_ld_memcopy(OptContext *ctx, TCGOp *op)
2635ab84dc39SRichard Henderson {
2636ab84dc39SRichard Henderson     TCGTemp *dst, *src;
2637ab84dc39SRichard Henderson     intptr_t ofs;
2638ab84dc39SRichard Henderson     TCGType type;
2639ab84dc39SRichard Henderson 
2640ab84dc39SRichard Henderson     if (op->args[1] != tcgv_ptr_arg(tcg_env)) {
2641ab84dc39SRichard Henderson         return false;
2642ab84dc39SRichard Henderson     }
2643ab84dc39SRichard Henderson 
2644ab84dc39SRichard Henderson     type = ctx->type;
2645ab84dc39SRichard Henderson     ofs = op->args[2];
2646ab84dc39SRichard Henderson     dst = arg_temp(op->args[0]);
2647ab84dc39SRichard Henderson     src = find_mem_copy_for(ctx, type, ofs);
2648ab84dc39SRichard Henderson     if (src && src->base_type == type) {
2649ab84dc39SRichard Henderson         return tcg_opt_gen_mov(ctx, op, temp_arg(dst), temp_arg(src));
2650ab84dc39SRichard Henderson     }
2651ab84dc39SRichard Henderson 
2652ab84dc39SRichard Henderson     reset_ts(ctx, dst);
2653ab84dc39SRichard Henderson     record_mem_copy(ctx, type, dst, ofs, ofs + tcg_type_size(type) - 1);
2654ab84dc39SRichard Henderson     return true;
2655ab84dc39SRichard Henderson }
2656ab84dc39SRichard Henderson 
fold_tcg_st(OptContext * ctx,TCGOp * op)2657ab84dc39SRichard Henderson static bool fold_tcg_st(OptContext *ctx, TCGOp *op)
2658ab84dc39SRichard Henderson {
2659ab84dc39SRichard Henderson     intptr_t ofs = op->args[2];
2660ab84dc39SRichard Henderson     intptr_t lm1;
2661ab84dc39SRichard Henderson 
2662ab84dc39SRichard Henderson     if (op->args[1] != tcgv_ptr_arg(tcg_env)) {
2663ab84dc39SRichard Henderson         remove_mem_copy_all(ctx);
2664ab84dc39SRichard Henderson         return false;
2665ab84dc39SRichard Henderson     }
2666ab84dc39SRichard Henderson 
2667ab84dc39SRichard Henderson     switch (op->opc) {
2668ab84dc39SRichard Henderson     CASE_OP_32_64(st8):
2669ab84dc39SRichard Henderson         lm1 = 0;
2670ab84dc39SRichard Henderson         break;
2671ab84dc39SRichard Henderson     CASE_OP_32_64(st16):
2672ab84dc39SRichard Henderson         lm1 = 1;
2673ab84dc39SRichard Henderson         break;
2674ab84dc39SRichard Henderson     case INDEX_op_st32_i64:
2675ab84dc39SRichard Henderson     case INDEX_op_st_i32:
2676ab84dc39SRichard Henderson         lm1 = 3;
2677ab84dc39SRichard Henderson         break;
2678ab84dc39SRichard Henderson     case INDEX_op_st_i64:
2679ab84dc39SRichard Henderson         lm1 = 7;
2680ab84dc39SRichard Henderson         break;
2681ab84dc39SRichard Henderson     case INDEX_op_st_vec:
2682ab84dc39SRichard Henderson         lm1 = tcg_type_size(ctx->type) - 1;
2683ab84dc39SRichard Henderson         break;
2684ab84dc39SRichard Henderson     default:
2685ab84dc39SRichard Henderson         g_assert_not_reached();
2686ab84dc39SRichard Henderson     }
2687ab84dc39SRichard Henderson     remove_mem_copy_in(ctx, ofs, ofs + lm1);
2688ab84dc39SRichard Henderson     return false;
2689ab84dc39SRichard Henderson }
2690ab84dc39SRichard Henderson 
fold_tcg_st_memcopy(OptContext * ctx,TCGOp * op)2691ab84dc39SRichard Henderson static bool fold_tcg_st_memcopy(OptContext *ctx, TCGOp *op)
2692ab84dc39SRichard Henderson {
2693ab84dc39SRichard Henderson     TCGTemp *src;
2694ab84dc39SRichard Henderson     intptr_t ofs, last;
2695ab84dc39SRichard Henderson     TCGType type;
2696ab84dc39SRichard Henderson 
2697ab84dc39SRichard Henderson     if (op->args[1] != tcgv_ptr_arg(tcg_env)) {
2698ab84dc39SRichard Henderson         fold_tcg_st(ctx, op);
2699ab84dc39SRichard Henderson         return false;
2700ab84dc39SRichard Henderson     }
2701ab84dc39SRichard Henderson 
2702ab84dc39SRichard Henderson     src = arg_temp(op->args[0]);
2703ab84dc39SRichard Henderson     ofs = op->args[2];
2704ab84dc39SRichard Henderson     type = ctx->type;
27053eaadaebSRichard Henderson 
27063eaadaebSRichard Henderson     /*
27073eaadaebSRichard Henderson      * Eliminate duplicate stores of a constant.
27083eaadaebSRichard Henderson      * This happens frequently when the target ISA zero-extends.
27093eaadaebSRichard Henderson      */
27103eaadaebSRichard Henderson     if (ts_is_const(src)) {
27113eaadaebSRichard Henderson         TCGTemp *prev = find_mem_copy_for(ctx, type, ofs);
27123eaadaebSRichard Henderson         if (src == prev) {
27133eaadaebSRichard Henderson             tcg_op_remove(ctx->tcg, op);
27143eaadaebSRichard Henderson             return true;
27153eaadaebSRichard Henderson         }
27163eaadaebSRichard Henderson     }
27173eaadaebSRichard Henderson 
2718ab84dc39SRichard Henderson     last = ofs + tcg_type_size(type) - 1;
2719ab84dc39SRichard Henderson     remove_mem_copy_in(ctx, ofs, last);
2720ab84dc39SRichard Henderson     record_mem_copy(ctx, type, src, ofs, last);
2721ab84dc39SRichard Henderson     return false;
2722ab84dc39SRichard Henderson }
2723ab84dc39SRichard Henderson 
fold_xor(OptContext * ctx,TCGOp * op)27242f9f08baSRichard Henderson static bool fold_xor(OptContext *ctx, TCGOp *op)
27252f9f08baSRichard Henderson {
27267a2f7084SRichard Henderson     if (fold_const2_commutative(ctx, op) ||
27270e0a32baSRichard Henderson         fold_xx_to_i(ctx, op, 0) ||
2728a63ce0e9SRichard Henderson         fold_xi_to_x(ctx, op, 0) ||
27290e0a32baSRichard Henderson         fold_xi_to_not(ctx, op, -1)) {
2730cbe42fb2SRichard Henderson         return true;
2731cbe42fb2SRichard Henderson     }
2732fae450baSRichard Henderson 
2733fae450baSRichard Henderson     ctx->z_mask = arg_info(op->args[1])->z_mask
2734fae450baSRichard Henderson                 | arg_info(op->args[2])->z_mask;
27353f2b1f83SRichard Henderson     ctx->s_mask = arg_info(op->args[1])->s_mask
27363f2b1f83SRichard Henderson                 & arg_info(op->args[2])->s_mask;
2737fae450baSRichard Henderson     return fold_masks(ctx, op);
27382f9f08baSRichard Henderson }
27392f9f08baSRichard Henderson 
fold_bitsel_vec(OptContext * ctx,TCGOp * op)2740*e58b9772SRichard Henderson static bool fold_bitsel_vec(OptContext *ctx, TCGOp *op)
2741*e58b9772SRichard Henderson {
2742*e58b9772SRichard Henderson     /* If true and false values are the same, eliminate the cmp. */
2743*e58b9772SRichard Henderson     if (args_are_copies(op->args[2], op->args[3])) {
2744*e58b9772SRichard Henderson         return tcg_opt_gen_mov(ctx, op, op->args[0], op->args[2]);
2745*e58b9772SRichard Henderson     }
2746*e58b9772SRichard Henderson 
2747*e58b9772SRichard Henderson     if (arg_is_const(op->args[2]) && arg_is_const(op->args[3])) {
2748*e58b9772SRichard Henderson         uint64_t tv = arg_info(op->args[2])->val;
2749*e58b9772SRichard Henderson         uint64_t fv = arg_info(op->args[3])->val;
2750*e58b9772SRichard Henderson 
2751*e58b9772SRichard Henderson         if (tv == -1 && fv == 0) {
2752*e58b9772SRichard Henderson             return tcg_opt_gen_mov(ctx, op, op->args[0], op->args[1]);
2753*e58b9772SRichard Henderson         }
2754*e58b9772SRichard Henderson         if (tv == 0 && fv == -1) {
2755*e58b9772SRichard Henderson             if (TCG_TARGET_HAS_not_vec) {
2756*e58b9772SRichard Henderson                 op->opc = INDEX_op_not_vec;
2757*e58b9772SRichard Henderson                 return fold_not(ctx, op);
2758*e58b9772SRichard Henderson             } else {
2759*e58b9772SRichard Henderson                 op->opc = INDEX_op_xor_vec;
2760*e58b9772SRichard Henderson                 op->args[2] = arg_new_constant(ctx, -1);
2761*e58b9772SRichard Henderson                 return fold_xor(ctx, op);
2762*e58b9772SRichard Henderson             }
2763*e58b9772SRichard Henderson         }
2764*e58b9772SRichard Henderson     }
2765*e58b9772SRichard Henderson     if (arg_is_const(op->args[2])) {
2766*e58b9772SRichard Henderson         uint64_t tv = arg_info(op->args[2])->val;
2767*e58b9772SRichard Henderson         if (tv == -1) {
2768*e58b9772SRichard Henderson             op->opc = INDEX_op_or_vec;
2769*e58b9772SRichard Henderson             op->args[2] = op->args[3];
2770*e58b9772SRichard Henderson             return fold_or(ctx, op);
2771*e58b9772SRichard Henderson         }
2772*e58b9772SRichard Henderson         if (tv == 0 && TCG_TARGET_HAS_andc_vec) {
2773*e58b9772SRichard Henderson             op->opc = INDEX_op_andc_vec;
2774*e58b9772SRichard Henderson             op->args[2] = op->args[1];
2775*e58b9772SRichard Henderson             op->args[1] = op->args[3];
2776*e58b9772SRichard Henderson             return fold_andc(ctx, op);
2777*e58b9772SRichard Henderson         }
2778*e58b9772SRichard Henderson     }
2779*e58b9772SRichard Henderson     if (arg_is_const(op->args[3])) {
2780*e58b9772SRichard Henderson         uint64_t fv = arg_info(op->args[3])->val;
2781*e58b9772SRichard Henderson         if (fv == 0) {
2782*e58b9772SRichard Henderson             op->opc = INDEX_op_and_vec;
2783*e58b9772SRichard Henderson             return fold_and(ctx, op);
2784*e58b9772SRichard Henderson         }
2785*e58b9772SRichard Henderson         if (fv == -1 && TCG_TARGET_HAS_orc_vec) {
2786*e58b9772SRichard Henderson             op->opc = INDEX_op_orc_vec;
2787*e58b9772SRichard Henderson             op->args[2] = op->args[1];
2788*e58b9772SRichard Henderson             op->args[1] = op->args[3];
2789*e58b9772SRichard Henderson             return fold_orc(ctx, op);
2790*e58b9772SRichard Henderson         }
2791*e58b9772SRichard Henderson     }
2792*e58b9772SRichard Henderson     return false;
2793*e58b9772SRichard Henderson }
2794*e58b9772SRichard Henderson 
279522613af4SKirill Batuzov /* Propagate constants and copies, fold constant expressions. */
tcg_optimize(TCGContext * s)279636e60ef6SAurelien Jarno void tcg_optimize(TCGContext *s)
27978f2e8c07SKirill Batuzov {
27985cf32be7SRichard Henderson     int nb_temps, i;
2799d0ed5151SRichard Henderson     TCGOp *op, *op_next;
2800dc84988aSRichard Henderson     OptContext ctx = { .tcg = s };
28015d8f5363SRichard Henderson 
2802ab84dc39SRichard Henderson     QSIMPLEQ_INIT(&ctx.mem_free);
2803ab84dc39SRichard Henderson 
280422613af4SKirill Batuzov     /* Array VALS has an element for each temp.
280522613af4SKirill Batuzov        If this temp holds a constant then its value is kept in VALS' element.
2806e590d4e6SAurelien Jarno        If this temp is a copy of other ones then the other copies are
2807e590d4e6SAurelien Jarno        available through the doubly linked circular list. */
28088f2e8c07SKirill Batuzov 
28098f2e8c07SKirill Batuzov     nb_temps = s->nb_temps;
28108f17a975SRichard Henderson     for (i = 0; i < nb_temps; ++i) {
28118f17a975SRichard Henderson         s->temps[i].state_ptr = NULL;
28128f17a975SRichard Henderson     }
28138f2e8c07SKirill Batuzov 
281415fa08f8SRichard Henderson     QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
2815c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
28165cf32be7SRichard Henderson         const TCGOpDef *def;
2817404a148dSRichard Henderson         bool done = false;
2818c45cb8bbSRichard Henderson 
28195cf32be7SRichard Henderson         /* Calls are special. */
2820c45cb8bbSRichard Henderson         if (opc == INDEX_op_call) {
28215cf32be7SRichard Henderson             fold_call(&ctx, op);
28225cf32be7SRichard Henderson             continue;
28235cf32be7SRichard Henderson         }
28245cf32be7SRichard Henderson 
28255cf32be7SRichard Henderson         def = &tcg_op_defs[opc];
2826ec5d4cbeSRichard Henderson         init_arguments(&ctx, op, def->nb_oargs + def->nb_iargs);
2827ec5d4cbeSRichard Henderson         copy_propagate(&ctx, op, def->nb_oargs, def->nb_iargs);
282822613af4SKirill Batuzov 
282967f84c96SRichard Henderson         /* Pre-compute the type of the operation. */
283067f84c96SRichard Henderson         if (def->flags & TCG_OPF_VECTOR) {
283167f84c96SRichard Henderson             ctx.type = TCG_TYPE_V64 + TCGOP_VECL(op);
283267f84c96SRichard Henderson         } else if (def->flags & TCG_OPF_64BIT) {
283367f84c96SRichard Henderson             ctx.type = TCG_TYPE_I64;
283467f84c96SRichard Henderson         } else {
283567f84c96SRichard Henderson             ctx.type = TCG_TYPE_I32;
283667f84c96SRichard Henderson         }
283767f84c96SRichard Henderson 
283857fe5c6dSRichard Henderson         /* Assume all bits affected, no bits known zero, no sign reps. */
2839fae450baSRichard Henderson         ctx.a_mask = -1;
2840fae450baSRichard Henderson         ctx.z_mask = -1;
284157fe5c6dSRichard Henderson         ctx.s_mask = 0;
2842633f6502SPaolo Bonzini 
28432cfac7faSRichard Henderson         /*
28442cfac7faSRichard Henderson          * Process each opcode.
28452cfac7faSRichard Henderson          * Sorted alphabetically by opcode as much as possible.
28462cfac7faSRichard Henderson          */
2847c45cb8bbSRichard Henderson         switch (opc) {
2848c578ff18SRichard Henderson         CASE_OP_32_64(add):
28492f9f08baSRichard Henderson             done = fold_add(&ctx, op);
28502f9f08baSRichard Henderson             break;
2851c578ff18SRichard Henderson         case INDEX_op_add_vec:
2852c578ff18SRichard Henderson             done = fold_add_vec(&ctx, op);
2853c578ff18SRichard Henderson             break;
28549531c078SRichard Henderson         CASE_OP_32_64(add2):
28559531c078SRichard Henderson             done = fold_add2(&ctx, op);
2856e3f7dc21SRichard Henderson             break;
28572f9f08baSRichard Henderson         CASE_OP_32_64_VEC(and):
28582f9f08baSRichard Henderson             done = fold_and(&ctx, op);
28592f9f08baSRichard Henderson             break;
28602f9f08baSRichard Henderson         CASE_OP_32_64_VEC(andc):
28612f9f08baSRichard Henderson             done = fold_andc(&ctx, op);
28622f9f08baSRichard Henderson             break;
2863079b0804SRichard Henderson         CASE_OP_32_64(brcond):
2864079b0804SRichard Henderson             done = fold_brcond(&ctx, op);
2865079b0804SRichard Henderson             break;
2866764d2abaSRichard Henderson         case INDEX_op_brcond2_i32:
2867764d2abaSRichard Henderson             done = fold_brcond2(&ctx, op);
2868764d2abaSRichard Henderson             break;
286909bacdc2SRichard Henderson         CASE_OP_32_64(bswap16):
287009bacdc2SRichard Henderson         CASE_OP_32_64(bswap32):
287109bacdc2SRichard Henderson         case INDEX_op_bswap64_i64:
287209bacdc2SRichard Henderson             done = fold_bswap(&ctx, op);
287309bacdc2SRichard Henderson             break;
287430dd0bfeSRichard Henderson         CASE_OP_32_64(clz):
287530dd0bfeSRichard Henderson         CASE_OP_32_64(ctz):
287630dd0bfeSRichard Henderson             done = fold_count_zeros(&ctx, op);
287730dd0bfeSRichard Henderson             break;
28782f9f08baSRichard Henderson         CASE_OP_32_64(ctpop):
28792f9f08baSRichard Henderson             done = fold_ctpop(&ctx, op);
28802f9f08baSRichard Henderson             break;
28811b1907b8SRichard Henderson         CASE_OP_32_64(deposit):
28821b1907b8SRichard Henderson             done = fold_deposit(&ctx, op);
28831b1907b8SRichard Henderson             break;
28842f9f08baSRichard Henderson         CASE_OP_32_64(div):
28852f9f08baSRichard Henderson         CASE_OP_32_64(divu):
28862f9f08baSRichard Henderson             done = fold_divide(&ctx, op);
28872f9f08baSRichard Henderson             break;
28888cdb3fcbSRichard Henderson         case INDEX_op_dup_vec:
28898cdb3fcbSRichard Henderson             done = fold_dup(&ctx, op);
28908cdb3fcbSRichard Henderson             break;
28918cdb3fcbSRichard Henderson         case INDEX_op_dup2_vec:
28928cdb3fcbSRichard Henderson             done = fold_dup2(&ctx, op);
28938cdb3fcbSRichard Henderson             break;
2894ed523473SRichard Henderson         CASE_OP_32_64_VEC(eqv):
28952f9f08baSRichard Henderson             done = fold_eqv(&ctx, op);
28962f9f08baSRichard Henderson             break;
2897b6617c88SRichard Henderson         CASE_OP_32_64(extract):
2898b6617c88SRichard Henderson             done = fold_extract(&ctx, op);
2899b6617c88SRichard Henderson             break;
2900dcd08996SRichard Henderson         CASE_OP_32_64(extract2):
2901dcd08996SRichard Henderson             done = fold_extract2(&ctx, op);
2902dcd08996SRichard Henderson             break;
29032f9f08baSRichard Henderson         CASE_OP_32_64(ext8s):
29042f9f08baSRichard Henderson         CASE_OP_32_64(ext16s):
29052f9f08baSRichard Henderson         case INDEX_op_ext32s_i64:
29062f9f08baSRichard Henderson         case INDEX_op_ext_i32_i64:
29072f9f08baSRichard Henderson             done = fold_exts(&ctx, op);
29082f9f08baSRichard Henderson             break;
29092f9f08baSRichard Henderson         CASE_OP_32_64(ext8u):
29102f9f08baSRichard Henderson         CASE_OP_32_64(ext16u):
29112f9f08baSRichard Henderson         case INDEX_op_ext32u_i64:
29122f9f08baSRichard Henderson         case INDEX_op_extu_i32_i64:
29132f9f08baSRichard Henderson         case INDEX_op_extrl_i64_i32:
29142f9f08baSRichard Henderson         case INDEX_op_extrh_i64_i32:
29152f9f08baSRichard Henderson             done = fold_extu(&ctx, op);
29162f9f08baSRichard Henderson             break;
291757fe5c6dSRichard Henderson         CASE_OP_32_64(ld8s):
2918fae450baSRichard Henderson         CASE_OP_32_64(ld8u):
291957fe5c6dSRichard Henderson         CASE_OP_32_64(ld16s):
2920fae450baSRichard Henderson         CASE_OP_32_64(ld16u):
292157fe5c6dSRichard Henderson         case INDEX_op_ld32s_i64:
2922fae450baSRichard Henderson         case INDEX_op_ld32u_i64:
2923fae450baSRichard Henderson             done = fold_tcg_ld(&ctx, op);
2924fae450baSRichard Henderson             break;
2925ab84dc39SRichard Henderson         case INDEX_op_ld_i32:
2926ab84dc39SRichard Henderson         case INDEX_op_ld_i64:
2927ab84dc39SRichard Henderson         case INDEX_op_ld_vec:
2928ab84dc39SRichard Henderson             done = fold_tcg_ld_memcopy(&ctx, op);
2929ab84dc39SRichard Henderson             break;
2930ab84dc39SRichard Henderson         CASE_OP_32_64(st8):
2931ab84dc39SRichard Henderson         CASE_OP_32_64(st16):
2932ab84dc39SRichard Henderson         case INDEX_op_st32_i64:
2933ab84dc39SRichard Henderson             done = fold_tcg_st(&ctx, op);
2934ab84dc39SRichard Henderson             break;
2935ab84dc39SRichard Henderson         case INDEX_op_st_i32:
2936ab84dc39SRichard Henderson         case INDEX_op_st_i64:
2937ab84dc39SRichard Henderson         case INDEX_op_st_vec:
2938ab84dc39SRichard Henderson             done = fold_tcg_st_memcopy(&ctx, op);
2939ab84dc39SRichard Henderson             break;
29403eefdf2bSRichard Henderson         case INDEX_op_mb:
29413eefdf2bSRichard Henderson             done = fold_mb(&ctx, op);
29423eefdf2bSRichard Henderson             break;
29432cfac7faSRichard Henderson         CASE_OP_32_64_VEC(mov):
29442cfac7faSRichard Henderson             done = fold_mov(&ctx, op);
29452cfac7faSRichard Henderson             break;
29460c310a30SRichard Henderson         CASE_OP_32_64(movcond):
29470c310a30SRichard Henderson             done = fold_movcond(&ctx, op);
29480c310a30SRichard Henderson             break;
29492f9f08baSRichard Henderson         CASE_OP_32_64(mul):
29502f9f08baSRichard Henderson             done = fold_mul(&ctx, op);
29512f9f08baSRichard Henderson             break;
29522f9f08baSRichard Henderson         CASE_OP_32_64(mulsh):
29532f9f08baSRichard Henderson         CASE_OP_32_64(muluh):
29542f9f08baSRichard Henderson             done = fold_mul_highpart(&ctx, op);
29552f9f08baSRichard Henderson             break;
2956407112b0SRichard Henderson         CASE_OP_32_64(muls2):
2957407112b0SRichard Henderson         CASE_OP_32_64(mulu2):
2958407112b0SRichard Henderson             done = fold_multiply2(&ctx, op);
29596b8ac0d1SRichard Henderson             break;
2960ed523473SRichard Henderson         CASE_OP_32_64_VEC(nand):
29612f9f08baSRichard Henderson             done = fold_nand(&ctx, op);
29622f9f08baSRichard Henderson             break;
29632f9f08baSRichard Henderson         CASE_OP_32_64(neg):
29642f9f08baSRichard Henderson             done = fold_neg(&ctx, op);
29652f9f08baSRichard Henderson             break;
2966ed523473SRichard Henderson         CASE_OP_32_64_VEC(nor):
29672f9f08baSRichard Henderson             done = fold_nor(&ctx, op);
29682f9f08baSRichard Henderson             break;
29692f9f08baSRichard Henderson         CASE_OP_32_64_VEC(not):
29702f9f08baSRichard Henderson             done = fold_not(&ctx, op);
29712f9f08baSRichard Henderson             break;
29722f9f08baSRichard Henderson         CASE_OP_32_64_VEC(or):
29732f9f08baSRichard Henderson             done = fold_or(&ctx, op);
29742f9f08baSRichard Henderson             break;
29752f9f08baSRichard Henderson         CASE_OP_32_64_VEC(orc):
29762f9f08baSRichard Henderson             done = fold_orc(&ctx, op);
29772f9f08baSRichard Henderson             break;
2978fecccfccSRichard Henderson         case INDEX_op_qemu_ld_a32_i32:
2979fecccfccSRichard Henderson         case INDEX_op_qemu_ld_a64_i32:
2980fecccfccSRichard Henderson         case INDEX_op_qemu_ld_a32_i64:
2981fecccfccSRichard Henderson         case INDEX_op_qemu_ld_a64_i64:
2982fecccfccSRichard Henderson         case INDEX_op_qemu_ld_a32_i128:
2983fecccfccSRichard Henderson         case INDEX_op_qemu_ld_a64_i128:
29843eefdf2bSRichard Henderson             done = fold_qemu_ld(&ctx, op);
29853eefdf2bSRichard Henderson             break;
2986fecccfccSRichard Henderson         case INDEX_op_qemu_st8_a32_i32:
2987fecccfccSRichard Henderson         case INDEX_op_qemu_st8_a64_i32:
2988fecccfccSRichard Henderson         case INDEX_op_qemu_st_a32_i32:
2989fecccfccSRichard Henderson         case INDEX_op_qemu_st_a64_i32:
2990fecccfccSRichard Henderson         case INDEX_op_qemu_st_a32_i64:
2991fecccfccSRichard Henderson         case INDEX_op_qemu_st_a64_i64:
2992fecccfccSRichard Henderson         case INDEX_op_qemu_st_a32_i128:
2993fecccfccSRichard Henderson         case INDEX_op_qemu_st_a64_i128:
29943eefdf2bSRichard Henderson             done = fold_qemu_st(&ctx, op);
29953eefdf2bSRichard Henderson             break;
29962f9f08baSRichard Henderson         CASE_OP_32_64(rem):
29972f9f08baSRichard Henderson         CASE_OP_32_64(remu):
29982f9f08baSRichard Henderson             done = fold_remainder(&ctx, op);
29992f9f08baSRichard Henderson             break;
30002f9f08baSRichard Henderson         CASE_OP_32_64(rotl):
30012f9f08baSRichard Henderson         CASE_OP_32_64(rotr):
30022f9f08baSRichard Henderson         CASE_OP_32_64(sar):
30032f9f08baSRichard Henderson         CASE_OP_32_64(shl):
30042f9f08baSRichard Henderson         CASE_OP_32_64(shr):
30052f9f08baSRichard Henderson             done = fold_shift(&ctx, op);
30062f9f08baSRichard Henderson             break;
3007c63ff55cSRichard Henderson         CASE_OP_32_64(setcond):
3008c63ff55cSRichard Henderson             done = fold_setcond(&ctx, op);
3009c63ff55cSRichard Henderson             break;
30103635502dSRichard Henderson         CASE_OP_32_64(negsetcond):
30113635502dSRichard Henderson             done = fold_negsetcond(&ctx, op);
30123635502dSRichard Henderson             break;
3013bc47b1aaSRichard Henderson         case INDEX_op_setcond2_i32:
3014bc47b1aaSRichard Henderson             done = fold_setcond2(&ctx, op);
3015bc47b1aaSRichard Henderson             break;
30161f106544SRichard Henderson         case INDEX_op_cmp_vec:
30171f106544SRichard Henderson             done = fold_cmp_vec(&ctx, op);
30181f106544SRichard Henderson             break;
30191f106544SRichard Henderson         case INDEX_op_cmpsel_vec:
30201f106544SRichard Henderson             done = fold_cmpsel_vec(&ctx, op);
30211f106544SRichard Henderson             break;
3022*e58b9772SRichard Henderson         case INDEX_op_bitsel_vec:
3023*e58b9772SRichard Henderson             done = fold_bitsel_vec(&ctx, op);
3024*e58b9772SRichard Henderson             break;
3025b6617c88SRichard Henderson         CASE_OP_32_64(sextract):
3026b6617c88SRichard Henderson             done = fold_sextract(&ctx, op);
3027b6617c88SRichard Henderson             break;
3028c578ff18SRichard Henderson         CASE_OP_32_64(sub):
30292f9f08baSRichard Henderson             done = fold_sub(&ctx, op);
30302f9f08baSRichard Henderson             break;
3031c578ff18SRichard Henderson         case INDEX_op_sub_vec:
3032c578ff18SRichard Henderson             done = fold_sub_vec(&ctx, op);
3033c578ff18SRichard Henderson             break;
30349531c078SRichard Henderson         CASE_OP_32_64(sub2):
30359531c078SRichard Henderson             done = fold_sub2(&ctx, op);
3036e3f7dc21SRichard Henderson             break;
30372f9f08baSRichard Henderson         CASE_OP_32_64_VEC(xor):
30382f9f08baSRichard Henderson             done = fold_xor(&ctx, op);
3039b10f3833SRichard Henderson             break;
30402cfac7faSRichard Henderson         default:
30412cfac7faSRichard Henderson             break;
3042b10f3833SRichard Henderson         }
3043b10f3833SRichard Henderson 
3044404a148dSRichard Henderson         if (!done) {
3045137f1f44SRichard Henderson             finish_folding(&ctx, op);
3046404a148dSRichard Henderson         }
30478f2e8c07SKirill Batuzov     }
30488f2e8c07SKirill Batuzov }
3049