xref: /openbmc/qemu/tcg/optimize.c (revision 404a148d)
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"
27dcb32f1dSPhilippe Mathieu-Daudé #include "tcg/tcg-op.h"
2890163900SRichard Henderson #include "tcg-internal.h"
298f2e8c07SKirill Batuzov 
308f2e8c07SKirill Batuzov #define CASE_OP_32_64(x)                        \
318f2e8c07SKirill Batuzov         glue(glue(case INDEX_op_, x), _i32):    \
328f2e8c07SKirill Batuzov         glue(glue(case INDEX_op_, x), _i64)
338f2e8c07SKirill Batuzov 
34170ba88fSRichard Henderson #define CASE_OP_32_64_VEC(x)                    \
35170ba88fSRichard Henderson         glue(glue(case INDEX_op_, x), _i32):    \
36170ba88fSRichard Henderson         glue(glue(case INDEX_op_, x), _i64):    \
37170ba88fSRichard Henderson         glue(glue(case INDEX_op_, x), _vec)
38170ba88fSRichard Henderson 
396fcb98edSRichard Henderson typedef struct TempOptInfo {
40b41059ddSAurelien Jarno     bool is_const;
416349039dSRichard Henderson     TCGTemp *prev_copy;
426349039dSRichard Henderson     TCGTemp *next_copy;
4354795544SRichard Henderson     uint64_t val;
44b1fde411SRichard Henderson     uint64_t z_mask;  /* mask bit is 0 if and only if value bit is 0 */
456fcb98edSRichard Henderson } TempOptInfo;
4622613af4SKirill Batuzov 
473b3f847dSRichard Henderson typedef struct OptContext {
48dc84988aSRichard Henderson     TCGContext *tcg;
49d0ed5151SRichard Henderson     TCGOp *prev_mb;
503b3f847dSRichard Henderson     TCGTempSet temps_used;
51137f1f44SRichard Henderson 
52137f1f44SRichard Henderson     /* In flight values from optimization. */
53137f1f44SRichard Henderson     uint64_t z_mask;
543b3f847dSRichard Henderson } OptContext;
553b3f847dSRichard Henderson 
566fcb98edSRichard Henderson static inline TempOptInfo *ts_info(TCGTemp *ts)
57d9c769c6SAurelien Jarno {
586349039dSRichard Henderson     return ts->state_ptr;
59d9c769c6SAurelien Jarno }
60d9c769c6SAurelien Jarno 
616fcb98edSRichard Henderson static inline TempOptInfo *arg_info(TCGArg arg)
62d9c769c6SAurelien Jarno {
636349039dSRichard Henderson     return ts_info(arg_temp(arg));
646349039dSRichard Henderson }
656349039dSRichard Henderson 
666349039dSRichard Henderson static inline bool ts_is_const(TCGTemp *ts)
676349039dSRichard Henderson {
686349039dSRichard Henderson     return ts_info(ts)->is_const;
696349039dSRichard Henderson }
706349039dSRichard Henderson 
716349039dSRichard Henderson static inline bool arg_is_const(TCGArg arg)
726349039dSRichard Henderson {
736349039dSRichard Henderson     return ts_is_const(arg_temp(arg));
746349039dSRichard Henderson }
756349039dSRichard Henderson 
766349039dSRichard Henderson static inline bool ts_is_copy(TCGTemp *ts)
776349039dSRichard Henderson {
786349039dSRichard Henderson     return ts_info(ts)->next_copy != ts;
79d9c769c6SAurelien Jarno }
80d9c769c6SAurelien Jarno 
81b41059ddSAurelien Jarno /* Reset TEMP's state, possibly removing the temp for the list of copies.  */
826349039dSRichard Henderson static void reset_ts(TCGTemp *ts)
8322613af4SKirill Batuzov {
846fcb98edSRichard Henderson     TempOptInfo *ti = ts_info(ts);
856fcb98edSRichard Henderson     TempOptInfo *pi = ts_info(ti->prev_copy);
866fcb98edSRichard Henderson     TempOptInfo *ni = ts_info(ti->next_copy);
876349039dSRichard Henderson 
886349039dSRichard Henderson     ni->prev_copy = ti->prev_copy;
896349039dSRichard Henderson     pi->next_copy = ti->next_copy;
906349039dSRichard Henderson     ti->next_copy = ts;
916349039dSRichard Henderson     ti->prev_copy = ts;
926349039dSRichard Henderson     ti->is_const = false;
93b1fde411SRichard Henderson     ti->z_mask = -1;
946349039dSRichard Henderson }
956349039dSRichard Henderson 
966349039dSRichard Henderson static void reset_temp(TCGArg arg)
976349039dSRichard Henderson {
986349039dSRichard Henderson     reset_ts(arg_temp(arg));
9922613af4SKirill Batuzov }
10022613af4SKirill Batuzov 
1011208d7ddSAurelien Jarno /* Initialize and activate a temporary.  */
1023b3f847dSRichard Henderson static void init_ts_info(OptContext *ctx, TCGTemp *ts)
1031208d7ddSAurelien Jarno {
1046349039dSRichard Henderson     size_t idx = temp_idx(ts);
1058f17a975SRichard Henderson     TempOptInfo *ti;
1066349039dSRichard Henderson 
1073b3f847dSRichard Henderson     if (test_bit(idx, ctx->temps_used.l)) {
1088f17a975SRichard Henderson         return;
1098f17a975SRichard Henderson     }
1103b3f847dSRichard Henderson     set_bit(idx, ctx->temps_used.l);
1118f17a975SRichard Henderson 
1128f17a975SRichard Henderson     ti = ts->state_ptr;
1138f17a975SRichard Henderson     if (ti == NULL) {
1148f17a975SRichard Henderson         ti = tcg_malloc(sizeof(TempOptInfo));
1156349039dSRichard Henderson         ts->state_ptr = ti;
1168f17a975SRichard Henderson     }
1178f17a975SRichard Henderson 
1186349039dSRichard Henderson     ti->next_copy = ts;
1196349039dSRichard Henderson     ti->prev_copy = ts;
120c0522136SRichard Henderson     if (ts->kind == TEMP_CONST) {
121c0522136SRichard Henderson         ti->is_const = true;
1228f17a975SRichard Henderson         ti->val = ts->val;
123b1fde411SRichard Henderson         ti->z_mask = ts->val;
124c0522136SRichard Henderson         if (TCG_TARGET_REG_BITS > 32 && ts->type == TCG_TYPE_I32) {
125c0522136SRichard Henderson             /* High bits of a 32-bit quantity are garbage.  */
126b1fde411SRichard Henderson             ti->z_mask |= ~0xffffffffull;
127c0522136SRichard Henderson         }
128c0522136SRichard Henderson     } else {
1296349039dSRichard Henderson         ti->is_const = false;
130b1fde411SRichard Henderson         ti->z_mask = -1;
131c0522136SRichard Henderson     }
1321208d7ddSAurelien Jarno }
1331208d7ddSAurelien Jarno 
1346349039dSRichard Henderson static TCGTemp *find_better_copy(TCGContext *s, TCGTemp *ts)
135e590d4e6SAurelien Jarno {
1364c868ce6SRichard Henderson     TCGTemp *i, *g, *l;
137e590d4e6SAurelien Jarno 
1384c868ce6SRichard Henderson     /* If this is already readonly, we can't do better. */
1394c868ce6SRichard Henderson     if (temp_readonly(ts)) {
1406349039dSRichard Henderson         return ts;
141e590d4e6SAurelien Jarno     }
142e590d4e6SAurelien Jarno 
1434c868ce6SRichard Henderson     g = l = NULL;
1446349039dSRichard Henderson     for (i = ts_info(ts)->next_copy; i != ts; i = ts_info(i)->next_copy) {
1454c868ce6SRichard Henderson         if (temp_readonly(i)) {
146e590d4e6SAurelien Jarno             return i;
1474c868ce6SRichard Henderson         } else if (i->kind > ts->kind) {
1484c868ce6SRichard Henderson             if (i->kind == TEMP_GLOBAL) {
1494c868ce6SRichard Henderson                 g = i;
1504c868ce6SRichard Henderson             } else if (i->kind == TEMP_LOCAL) {
1514c868ce6SRichard Henderson                 l = i;
152e590d4e6SAurelien Jarno             }
153e590d4e6SAurelien Jarno         }
154e590d4e6SAurelien Jarno     }
155e590d4e6SAurelien Jarno 
1564c868ce6SRichard Henderson     /* If we didn't find a better representation, return the same temp. */
1574c868ce6SRichard Henderson     return g ? g : l ? l : ts;
158e590d4e6SAurelien Jarno }
159e590d4e6SAurelien Jarno 
1606349039dSRichard Henderson static bool ts_are_copies(TCGTemp *ts1, TCGTemp *ts2)
161e590d4e6SAurelien Jarno {
1626349039dSRichard Henderson     TCGTemp *i;
163e590d4e6SAurelien Jarno 
1646349039dSRichard Henderson     if (ts1 == ts2) {
165e590d4e6SAurelien Jarno         return true;
166e590d4e6SAurelien Jarno     }
167e590d4e6SAurelien Jarno 
1686349039dSRichard Henderson     if (!ts_is_copy(ts1) || !ts_is_copy(ts2)) {
169e590d4e6SAurelien Jarno         return false;
170e590d4e6SAurelien Jarno     }
171e590d4e6SAurelien Jarno 
1726349039dSRichard Henderson     for (i = ts_info(ts1)->next_copy; i != ts1; i = ts_info(i)->next_copy) {
1736349039dSRichard Henderson         if (i == ts2) {
174e590d4e6SAurelien Jarno             return true;
175e590d4e6SAurelien Jarno         }
176e590d4e6SAurelien Jarno     }
177e590d4e6SAurelien Jarno 
178e590d4e6SAurelien Jarno     return false;
179e590d4e6SAurelien Jarno }
180e590d4e6SAurelien Jarno 
1816349039dSRichard Henderson static bool args_are_copies(TCGArg arg1, TCGArg arg2)
1826349039dSRichard Henderson {
1836349039dSRichard Henderson     return ts_are_copies(arg_temp(arg1), arg_temp(arg2));
1846349039dSRichard Henderson }
1856349039dSRichard Henderson 
1866b99d5bfSRichard Henderson static bool tcg_opt_gen_mov(OptContext *ctx, TCGOp *op, TCGArg dst, TCGArg src)
18722613af4SKirill Batuzov {
1886349039dSRichard Henderson     TCGTemp *dst_ts = arg_temp(dst);
1896349039dSRichard Henderson     TCGTemp *src_ts = arg_temp(src);
190170ba88fSRichard Henderson     const TCGOpDef *def;
1916fcb98edSRichard Henderson     TempOptInfo *di;
1926fcb98edSRichard Henderson     TempOptInfo *si;
193b1fde411SRichard Henderson     uint64_t z_mask;
1946349039dSRichard Henderson     TCGOpcode new_op;
1956349039dSRichard Henderson 
1966349039dSRichard Henderson     if (ts_are_copies(dst_ts, src_ts)) {
197dc84988aSRichard Henderson         tcg_op_remove(ctx->tcg, op);
1986b99d5bfSRichard Henderson         return true;
1995365718aSAurelien Jarno     }
2005365718aSAurelien Jarno 
2016349039dSRichard Henderson     reset_ts(dst_ts);
2026349039dSRichard Henderson     di = ts_info(dst_ts);
2036349039dSRichard Henderson     si = ts_info(src_ts);
204170ba88fSRichard Henderson     def = &tcg_op_defs[op->opc];
205170ba88fSRichard Henderson     if (def->flags & TCG_OPF_VECTOR) {
206170ba88fSRichard Henderson         new_op = INDEX_op_mov_vec;
207170ba88fSRichard Henderson     } else if (def->flags & TCG_OPF_64BIT) {
208170ba88fSRichard Henderson         new_op = INDEX_op_mov_i64;
209170ba88fSRichard Henderson     } else {
210170ba88fSRichard Henderson         new_op = INDEX_op_mov_i32;
211170ba88fSRichard Henderson     }
212c45cb8bbSRichard Henderson     op->opc = new_op;
213170ba88fSRichard Henderson     /* TCGOP_VECL and TCGOP_VECE remain unchanged.  */
2146349039dSRichard Henderson     op->args[0] = dst;
2156349039dSRichard Henderson     op->args[1] = src;
216a62f6f56SRichard Henderson 
217b1fde411SRichard Henderson     z_mask = si->z_mask;
21824666bafSRichard Henderson     if (TCG_TARGET_REG_BITS > 32 && new_op == INDEX_op_mov_i32) {
21924666bafSRichard Henderson         /* High bits of the destination are now garbage.  */
220b1fde411SRichard Henderson         z_mask |= ~0xffffffffull;
22124666bafSRichard Henderson     }
222b1fde411SRichard Henderson     di->z_mask = z_mask;
22324666bafSRichard Henderson 
2246349039dSRichard Henderson     if (src_ts->type == dst_ts->type) {
2256fcb98edSRichard Henderson         TempOptInfo *ni = ts_info(si->next_copy);
2266349039dSRichard Henderson 
2276349039dSRichard Henderson         di->next_copy = si->next_copy;
2286349039dSRichard Henderson         di->prev_copy = src_ts;
2296349039dSRichard Henderson         ni->prev_copy = dst_ts;
2306349039dSRichard Henderson         si->next_copy = dst_ts;
2316349039dSRichard Henderson         di->is_const = si->is_const;
2326349039dSRichard Henderson         di->val = si->val;
23322613af4SKirill Batuzov     }
2346b99d5bfSRichard Henderson     return true;
23522613af4SKirill Batuzov }
23622613af4SKirill Batuzov 
2376b99d5bfSRichard Henderson static bool tcg_opt_gen_movi(OptContext *ctx, TCGOp *op,
238dc84988aSRichard Henderson                              TCGArg dst, uint64_t val)
2398fe35e04SRichard Henderson {
2408fe35e04SRichard Henderson     const TCGOpDef *def = &tcg_op_defs[op->opc];
2418fe35e04SRichard Henderson     TCGType type;
2428fe35e04SRichard Henderson     TCGTemp *tv;
2438fe35e04SRichard Henderson 
2448fe35e04SRichard Henderson     if (def->flags & TCG_OPF_VECTOR) {
2458fe35e04SRichard Henderson         type = TCGOP_VECL(op) + TCG_TYPE_V64;
2468fe35e04SRichard Henderson     } else if (def->flags & TCG_OPF_64BIT) {
2478fe35e04SRichard Henderson         type = TCG_TYPE_I64;
2488fe35e04SRichard Henderson     } else {
2498fe35e04SRichard Henderson         type = TCG_TYPE_I32;
2508fe35e04SRichard Henderson     }
2518fe35e04SRichard Henderson 
2528fe35e04SRichard Henderson     /* Convert movi to mov with constant temp. */
2538fe35e04SRichard Henderson     tv = tcg_constant_internal(type, val);
2543b3f847dSRichard Henderson     init_ts_info(ctx, tv);
2556b99d5bfSRichard Henderson     return tcg_opt_gen_mov(ctx, op, dst, temp_arg(tv));
2568fe35e04SRichard Henderson }
2578fe35e04SRichard Henderson 
25854795544SRichard Henderson static uint64_t do_constant_folding_2(TCGOpcode op, uint64_t x, uint64_t y)
25953108fb5SKirill Batuzov {
26003271524SRichard Henderson     uint64_t l64, h64;
26103271524SRichard Henderson 
26253108fb5SKirill Batuzov     switch (op) {
26353108fb5SKirill Batuzov     CASE_OP_32_64(add):
26453108fb5SKirill Batuzov         return x + y;
26553108fb5SKirill Batuzov 
26653108fb5SKirill Batuzov     CASE_OP_32_64(sub):
26753108fb5SKirill Batuzov         return x - y;
26853108fb5SKirill Batuzov 
26953108fb5SKirill Batuzov     CASE_OP_32_64(mul):
27053108fb5SKirill Batuzov         return x * y;
27153108fb5SKirill Batuzov 
2729a81090bSKirill Batuzov     CASE_OP_32_64(and):
2739a81090bSKirill Batuzov         return x & y;
2749a81090bSKirill Batuzov 
2759a81090bSKirill Batuzov     CASE_OP_32_64(or):
2769a81090bSKirill Batuzov         return x | y;
2779a81090bSKirill Batuzov 
2789a81090bSKirill Batuzov     CASE_OP_32_64(xor):
2799a81090bSKirill Batuzov         return x ^ y;
2809a81090bSKirill Batuzov 
28155c0975cSKirill Batuzov     case INDEX_op_shl_i32:
28250c5c4d1SRichard Henderson         return (uint32_t)x << (y & 31);
28355c0975cSKirill Batuzov 
28455c0975cSKirill Batuzov     case INDEX_op_shl_i64:
28550c5c4d1SRichard Henderson         return (uint64_t)x << (y & 63);
28655c0975cSKirill Batuzov 
28755c0975cSKirill Batuzov     case INDEX_op_shr_i32:
28850c5c4d1SRichard Henderson         return (uint32_t)x >> (y & 31);
28955c0975cSKirill Batuzov 
29055c0975cSKirill Batuzov     case INDEX_op_shr_i64:
29150c5c4d1SRichard Henderson         return (uint64_t)x >> (y & 63);
29255c0975cSKirill Batuzov 
29355c0975cSKirill Batuzov     case INDEX_op_sar_i32:
29450c5c4d1SRichard Henderson         return (int32_t)x >> (y & 31);
29555c0975cSKirill Batuzov 
29655c0975cSKirill Batuzov     case INDEX_op_sar_i64:
29750c5c4d1SRichard Henderson         return (int64_t)x >> (y & 63);
29855c0975cSKirill Batuzov 
29955c0975cSKirill Batuzov     case INDEX_op_rotr_i32:
30050c5c4d1SRichard Henderson         return ror32(x, y & 31);
30155c0975cSKirill Batuzov 
30255c0975cSKirill Batuzov     case INDEX_op_rotr_i64:
30350c5c4d1SRichard Henderson         return ror64(x, y & 63);
30455c0975cSKirill Batuzov 
30555c0975cSKirill Batuzov     case INDEX_op_rotl_i32:
30650c5c4d1SRichard Henderson         return rol32(x, y & 31);
30755c0975cSKirill Batuzov 
30855c0975cSKirill Batuzov     case INDEX_op_rotl_i64:
30950c5c4d1SRichard Henderson         return rol64(x, y & 63);
31055c0975cSKirill Batuzov 
31125c4d9ccSRichard Henderson     CASE_OP_32_64(not):
312a640f031SKirill Batuzov         return ~x;
313a640f031SKirill Batuzov 
314cb25c80aSRichard Henderson     CASE_OP_32_64(neg):
315cb25c80aSRichard Henderson         return -x;
316cb25c80aSRichard Henderson 
317cb25c80aSRichard Henderson     CASE_OP_32_64(andc):
318cb25c80aSRichard Henderson         return x & ~y;
319cb25c80aSRichard Henderson 
320cb25c80aSRichard Henderson     CASE_OP_32_64(orc):
321cb25c80aSRichard Henderson         return x | ~y;
322cb25c80aSRichard Henderson 
323cb25c80aSRichard Henderson     CASE_OP_32_64(eqv):
324cb25c80aSRichard Henderson         return ~(x ^ y);
325cb25c80aSRichard Henderson 
326cb25c80aSRichard Henderson     CASE_OP_32_64(nand):
327cb25c80aSRichard Henderson         return ~(x & y);
328cb25c80aSRichard Henderson 
329cb25c80aSRichard Henderson     CASE_OP_32_64(nor):
330cb25c80aSRichard Henderson         return ~(x | y);
331cb25c80aSRichard Henderson 
3320e28d006SRichard Henderson     case INDEX_op_clz_i32:
3330e28d006SRichard Henderson         return (uint32_t)x ? clz32(x) : y;
3340e28d006SRichard Henderson 
3350e28d006SRichard Henderson     case INDEX_op_clz_i64:
3360e28d006SRichard Henderson         return x ? clz64(x) : y;
3370e28d006SRichard Henderson 
3380e28d006SRichard Henderson     case INDEX_op_ctz_i32:
3390e28d006SRichard Henderson         return (uint32_t)x ? ctz32(x) : y;
3400e28d006SRichard Henderson 
3410e28d006SRichard Henderson     case INDEX_op_ctz_i64:
3420e28d006SRichard Henderson         return x ? ctz64(x) : y;
3430e28d006SRichard Henderson 
344a768e4e9SRichard Henderson     case INDEX_op_ctpop_i32:
345a768e4e9SRichard Henderson         return ctpop32(x);
346a768e4e9SRichard Henderson 
347a768e4e9SRichard Henderson     case INDEX_op_ctpop_i64:
348a768e4e9SRichard Henderson         return ctpop64(x);
349a768e4e9SRichard Henderson 
35025c4d9ccSRichard Henderson     CASE_OP_32_64(ext8s):
351a640f031SKirill Batuzov         return (int8_t)x;
352a640f031SKirill Batuzov 
35325c4d9ccSRichard Henderson     CASE_OP_32_64(ext16s):
354a640f031SKirill Batuzov         return (int16_t)x;
355a640f031SKirill Batuzov 
35625c4d9ccSRichard Henderson     CASE_OP_32_64(ext8u):
357a640f031SKirill Batuzov         return (uint8_t)x;
358a640f031SKirill Batuzov 
35925c4d9ccSRichard Henderson     CASE_OP_32_64(ext16u):
360a640f031SKirill Batuzov         return (uint16_t)x;
361a640f031SKirill Batuzov 
3626498594cSRichard Henderson     CASE_OP_32_64(bswap16):
3630b76ff8fSRichard Henderson         x = bswap16(x);
3640b76ff8fSRichard Henderson         return y & TCG_BSWAP_OS ? (int16_t)x : x;
3656498594cSRichard Henderson 
3666498594cSRichard Henderson     CASE_OP_32_64(bswap32):
3670b76ff8fSRichard Henderson         x = bswap32(x);
3680b76ff8fSRichard Henderson         return y & TCG_BSWAP_OS ? (int32_t)x : x;
3696498594cSRichard Henderson 
3706498594cSRichard Henderson     case INDEX_op_bswap64_i64:
3716498594cSRichard Henderson         return bswap64(x);
3726498594cSRichard Henderson 
3738bcb5c8fSAurelien Jarno     case INDEX_op_ext_i32_i64:
374a640f031SKirill Batuzov     case INDEX_op_ext32s_i64:
375a640f031SKirill Batuzov         return (int32_t)x;
376a640f031SKirill Batuzov 
3778bcb5c8fSAurelien Jarno     case INDEX_op_extu_i32_i64:
378609ad705SRichard Henderson     case INDEX_op_extrl_i64_i32:
379a640f031SKirill Batuzov     case INDEX_op_ext32u_i64:
380a640f031SKirill Batuzov         return (uint32_t)x;
381a640f031SKirill Batuzov 
382609ad705SRichard Henderson     case INDEX_op_extrh_i64_i32:
383609ad705SRichard Henderson         return (uint64_t)x >> 32;
384609ad705SRichard Henderson 
38503271524SRichard Henderson     case INDEX_op_muluh_i32:
38603271524SRichard Henderson         return ((uint64_t)(uint32_t)x * (uint32_t)y) >> 32;
38703271524SRichard Henderson     case INDEX_op_mulsh_i32:
38803271524SRichard Henderson         return ((int64_t)(int32_t)x * (int32_t)y) >> 32;
38903271524SRichard Henderson 
39003271524SRichard Henderson     case INDEX_op_muluh_i64:
39103271524SRichard Henderson         mulu64(&l64, &h64, x, y);
39203271524SRichard Henderson         return h64;
39303271524SRichard Henderson     case INDEX_op_mulsh_i64:
39403271524SRichard Henderson         muls64(&l64, &h64, x, y);
39503271524SRichard Henderson         return h64;
39603271524SRichard Henderson 
39701547f7fSRichard Henderson     case INDEX_op_div_i32:
39801547f7fSRichard Henderson         /* Avoid crashing on divide by zero, otherwise undefined.  */
39901547f7fSRichard Henderson         return (int32_t)x / ((int32_t)y ? : 1);
40001547f7fSRichard Henderson     case INDEX_op_divu_i32:
40101547f7fSRichard Henderson         return (uint32_t)x / ((uint32_t)y ? : 1);
40201547f7fSRichard Henderson     case INDEX_op_div_i64:
40301547f7fSRichard Henderson         return (int64_t)x / ((int64_t)y ? : 1);
40401547f7fSRichard Henderson     case INDEX_op_divu_i64:
40501547f7fSRichard Henderson         return (uint64_t)x / ((uint64_t)y ? : 1);
40601547f7fSRichard Henderson 
40701547f7fSRichard Henderson     case INDEX_op_rem_i32:
40801547f7fSRichard Henderson         return (int32_t)x % ((int32_t)y ? : 1);
40901547f7fSRichard Henderson     case INDEX_op_remu_i32:
41001547f7fSRichard Henderson         return (uint32_t)x % ((uint32_t)y ? : 1);
41101547f7fSRichard Henderson     case INDEX_op_rem_i64:
41201547f7fSRichard Henderson         return (int64_t)x % ((int64_t)y ? : 1);
41301547f7fSRichard Henderson     case INDEX_op_remu_i64:
41401547f7fSRichard Henderson         return (uint64_t)x % ((uint64_t)y ? : 1);
41501547f7fSRichard Henderson 
41653108fb5SKirill Batuzov     default:
41753108fb5SKirill Batuzov         fprintf(stderr,
41853108fb5SKirill Batuzov                 "Unrecognized operation %d in do_constant_folding.\n", op);
41953108fb5SKirill Batuzov         tcg_abort();
42053108fb5SKirill Batuzov     }
42153108fb5SKirill Batuzov }
42253108fb5SKirill Batuzov 
42354795544SRichard Henderson static uint64_t do_constant_folding(TCGOpcode op, uint64_t x, uint64_t y)
42453108fb5SKirill Batuzov {
425170ba88fSRichard Henderson     const TCGOpDef *def = &tcg_op_defs[op];
42654795544SRichard Henderson     uint64_t res = do_constant_folding_2(op, x, y);
427170ba88fSRichard Henderson     if (!(def->flags & TCG_OPF_64BIT)) {
42829f3ff8dSAurelien Jarno         res = (int32_t)res;
42953108fb5SKirill Batuzov     }
43053108fb5SKirill Batuzov     return res;
43153108fb5SKirill Batuzov }
43253108fb5SKirill Batuzov 
4339519da7eSRichard Henderson static bool do_constant_folding_cond_32(uint32_t x, uint32_t y, TCGCond c)
434f8dd19e5SAurelien Jarno {
435f8dd19e5SAurelien Jarno     switch (c) {
436f8dd19e5SAurelien Jarno     case TCG_COND_EQ:
4379519da7eSRichard Henderson         return x == y;
438f8dd19e5SAurelien Jarno     case TCG_COND_NE:
4399519da7eSRichard Henderson         return x != y;
440f8dd19e5SAurelien Jarno     case TCG_COND_LT:
4419519da7eSRichard Henderson         return (int32_t)x < (int32_t)y;
442f8dd19e5SAurelien Jarno     case TCG_COND_GE:
4439519da7eSRichard Henderson         return (int32_t)x >= (int32_t)y;
444f8dd19e5SAurelien Jarno     case TCG_COND_LE:
4459519da7eSRichard Henderson         return (int32_t)x <= (int32_t)y;
446f8dd19e5SAurelien Jarno     case TCG_COND_GT:
4479519da7eSRichard Henderson         return (int32_t)x > (int32_t)y;
448f8dd19e5SAurelien Jarno     case TCG_COND_LTU:
4499519da7eSRichard Henderson         return x < y;
450f8dd19e5SAurelien Jarno     case TCG_COND_GEU:
4519519da7eSRichard Henderson         return x >= y;
452f8dd19e5SAurelien Jarno     case TCG_COND_LEU:
4539519da7eSRichard Henderson         return x <= y;
454f8dd19e5SAurelien Jarno     case TCG_COND_GTU:
4559519da7eSRichard Henderson         return x > y;
4560aed257fSRichard Henderson     default:
4579519da7eSRichard Henderson         tcg_abort();
458f8dd19e5SAurelien Jarno     }
4599519da7eSRichard Henderson }
4609519da7eSRichard Henderson 
4619519da7eSRichard Henderson static bool do_constant_folding_cond_64(uint64_t x, uint64_t y, TCGCond c)
4629519da7eSRichard Henderson {
463f8dd19e5SAurelien Jarno     switch (c) {
464f8dd19e5SAurelien Jarno     case TCG_COND_EQ:
4659519da7eSRichard Henderson         return x == y;
466f8dd19e5SAurelien Jarno     case TCG_COND_NE:
4679519da7eSRichard Henderson         return x != y;
468f8dd19e5SAurelien Jarno     case TCG_COND_LT:
4699519da7eSRichard Henderson         return (int64_t)x < (int64_t)y;
470f8dd19e5SAurelien Jarno     case TCG_COND_GE:
4719519da7eSRichard Henderson         return (int64_t)x >= (int64_t)y;
472f8dd19e5SAurelien Jarno     case TCG_COND_LE:
4739519da7eSRichard Henderson         return (int64_t)x <= (int64_t)y;
474f8dd19e5SAurelien Jarno     case TCG_COND_GT:
4759519da7eSRichard Henderson         return (int64_t)x > (int64_t)y;
476f8dd19e5SAurelien Jarno     case TCG_COND_LTU:
4779519da7eSRichard Henderson         return x < y;
478f8dd19e5SAurelien Jarno     case TCG_COND_GEU:
4799519da7eSRichard Henderson         return x >= y;
480f8dd19e5SAurelien Jarno     case TCG_COND_LEU:
4819519da7eSRichard Henderson         return x <= y;
482f8dd19e5SAurelien Jarno     case TCG_COND_GTU:
4839519da7eSRichard Henderson         return x > y;
4840aed257fSRichard Henderson     default:
4859519da7eSRichard Henderson         tcg_abort();
486f8dd19e5SAurelien Jarno     }
487f8dd19e5SAurelien Jarno }
4889519da7eSRichard Henderson 
4899519da7eSRichard Henderson static bool do_constant_folding_cond_eq(TCGCond c)
4909519da7eSRichard Henderson {
491b336ceb6SAurelien Jarno     switch (c) {
492b336ceb6SAurelien Jarno     case TCG_COND_GT:
493b336ceb6SAurelien Jarno     case TCG_COND_LTU:
494b336ceb6SAurelien Jarno     case TCG_COND_LT:
495b336ceb6SAurelien Jarno     case TCG_COND_GTU:
496b336ceb6SAurelien Jarno     case TCG_COND_NE:
497b336ceb6SAurelien Jarno         return 0;
498b336ceb6SAurelien Jarno     case TCG_COND_GE:
499b336ceb6SAurelien Jarno     case TCG_COND_GEU:
500b336ceb6SAurelien Jarno     case TCG_COND_LE:
501b336ceb6SAurelien Jarno     case TCG_COND_LEU:
502b336ceb6SAurelien Jarno     case TCG_COND_EQ:
503b336ceb6SAurelien Jarno         return 1;
5040aed257fSRichard Henderson     default:
5059519da7eSRichard Henderson         tcg_abort();
506b336ceb6SAurelien Jarno     }
5079519da7eSRichard Henderson }
5089519da7eSRichard Henderson 
5098d57bf1eSRichard Henderson /*
5108d57bf1eSRichard Henderson  * Return -1 if the condition can't be simplified,
5118d57bf1eSRichard Henderson  * and the result of the condition (0 or 1) if it can.
5128d57bf1eSRichard Henderson  */
5138d57bf1eSRichard Henderson static int do_constant_folding_cond(TCGOpcode op, TCGArg x,
5149519da7eSRichard Henderson                                     TCGArg y, TCGCond c)
5159519da7eSRichard Henderson {
51654795544SRichard Henderson     uint64_t xv = arg_info(x)->val;
51754795544SRichard Henderson     uint64_t yv = arg_info(y)->val;
51854795544SRichard Henderson 
5196349039dSRichard Henderson     if (arg_is_const(x) && arg_is_const(y)) {
520170ba88fSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[op];
521170ba88fSRichard Henderson         tcg_debug_assert(!(def->flags & TCG_OPF_VECTOR));
522170ba88fSRichard Henderson         if (def->flags & TCG_OPF_64BIT) {
5236349039dSRichard Henderson             return do_constant_folding_cond_64(xv, yv, c);
524170ba88fSRichard Henderson         } else {
525170ba88fSRichard Henderson             return do_constant_folding_cond_32(xv, yv, c);
5269519da7eSRichard Henderson         }
5276349039dSRichard Henderson     } else if (args_are_copies(x, y)) {
5289519da7eSRichard Henderson         return do_constant_folding_cond_eq(c);
5296349039dSRichard Henderson     } else if (arg_is_const(y) && yv == 0) {
530b336ceb6SAurelien Jarno         switch (c) {
531b336ceb6SAurelien Jarno         case TCG_COND_LTU:
532b336ceb6SAurelien Jarno             return 0;
533b336ceb6SAurelien Jarno         case TCG_COND_GEU:
534b336ceb6SAurelien Jarno             return 1;
535b336ceb6SAurelien Jarno         default:
5368d57bf1eSRichard Henderson             return -1;
537b336ceb6SAurelien Jarno         }
538b336ceb6SAurelien Jarno     }
5398d57bf1eSRichard Henderson     return -1;
540f8dd19e5SAurelien Jarno }
541f8dd19e5SAurelien Jarno 
5428d57bf1eSRichard Henderson /*
5438d57bf1eSRichard Henderson  * Return -1 if the condition can't be simplified,
5448d57bf1eSRichard Henderson  * and the result of the condition (0 or 1) if it can.
5458d57bf1eSRichard Henderson  */
5468d57bf1eSRichard Henderson static int do_constant_folding_cond2(TCGArg *p1, TCGArg *p2, TCGCond c)
5476c4382f8SRichard Henderson {
5486c4382f8SRichard Henderson     TCGArg al = p1[0], ah = p1[1];
5496c4382f8SRichard Henderson     TCGArg bl = p2[0], bh = p2[1];
5506c4382f8SRichard Henderson 
5516349039dSRichard Henderson     if (arg_is_const(bl) && arg_is_const(bh)) {
5526349039dSRichard Henderson         tcg_target_ulong blv = arg_info(bl)->val;
5536349039dSRichard Henderson         tcg_target_ulong bhv = arg_info(bh)->val;
5546349039dSRichard Henderson         uint64_t b = deposit64(blv, 32, 32, bhv);
5556c4382f8SRichard Henderson 
5566349039dSRichard Henderson         if (arg_is_const(al) && arg_is_const(ah)) {
5576349039dSRichard Henderson             tcg_target_ulong alv = arg_info(al)->val;
5586349039dSRichard Henderson             tcg_target_ulong ahv = arg_info(ah)->val;
5596349039dSRichard Henderson             uint64_t a = deposit64(alv, 32, 32, ahv);
5606c4382f8SRichard Henderson             return do_constant_folding_cond_64(a, b, c);
5616c4382f8SRichard Henderson         }
5626c4382f8SRichard Henderson         if (b == 0) {
5636c4382f8SRichard Henderson             switch (c) {
5646c4382f8SRichard Henderson             case TCG_COND_LTU:
5656c4382f8SRichard Henderson                 return 0;
5666c4382f8SRichard Henderson             case TCG_COND_GEU:
5676c4382f8SRichard Henderson                 return 1;
5686c4382f8SRichard Henderson             default:
5696c4382f8SRichard Henderson                 break;
5706c4382f8SRichard Henderson             }
5716c4382f8SRichard Henderson         }
5726c4382f8SRichard Henderson     }
5736349039dSRichard Henderson     if (args_are_copies(al, bl) && args_are_copies(ah, bh)) {
5746c4382f8SRichard Henderson         return do_constant_folding_cond_eq(c);
5756c4382f8SRichard Henderson     }
5768d57bf1eSRichard Henderson     return -1;
5776c4382f8SRichard Henderson }
5786c4382f8SRichard Henderson 
57924c9ae4eSRichard Henderson static bool swap_commutative(TCGArg dest, TCGArg *p1, TCGArg *p2)
58024c9ae4eSRichard Henderson {
58124c9ae4eSRichard Henderson     TCGArg a1 = *p1, a2 = *p2;
58224c9ae4eSRichard Henderson     int sum = 0;
5836349039dSRichard Henderson     sum += arg_is_const(a1);
5846349039dSRichard Henderson     sum -= arg_is_const(a2);
58524c9ae4eSRichard Henderson 
58624c9ae4eSRichard Henderson     /* Prefer the constant in second argument, and then the form
58724c9ae4eSRichard Henderson        op a, a, b, which is better handled on non-RISC hosts. */
58824c9ae4eSRichard Henderson     if (sum > 0 || (sum == 0 && dest == a2)) {
58924c9ae4eSRichard Henderson         *p1 = a2;
59024c9ae4eSRichard Henderson         *p2 = a1;
59124c9ae4eSRichard Henderson         return true;
59224c9ae4eSRichard Henderson     }
59324c9ae4eSRichard Henderson     return false;
59424c9ae4eSRichard Henderson }
59524c9ae4eSRichard Henderson 
5960bfcb865SRichard Henderson static bool swap_commutative2(TCGArg *p1, TCGArg *p2)
5970bfcb865SRichard Henderson {
5980bfcb865SRichard Henderson     int sum = 0;
5996349039dSRichard Henderson     sum += arg_is_const(p1[0]);
6006349039dSRichard Henderson     sum += arg_is_const(p1[1]);
6016349039dSRichard Henderson     sum -= arg_is_const(p2[0]);
6026349039dSRichard Henderson     sum -= arg_is_const(p2[1]);
6030bfcb865SRichard Henderson     if (sum > 0) {
6040bfcb865SRichard Henderson         TCGArg t;
6050bfcb865SRichard Henderson         t = p1[0], p1[0] = p2[0], p2[0] = t;
6060bfcb865SRichard Henderson         t = p1[1], p1[1] = p2[1], p2[1] = t;
6070bfcb865SRichard Henderson         return true;
6080bfcb865SRichard Henderson     }
6090bfcb865SRichard Henderson     return false;
6100bfcb865SRichard Henderson }
6110bfcb865SRichard Henderson 
612e2577ea2SRichard Henderson static void init_arguments(OptContext *ctx, TCGOp *op, int nb_args)
613e2577ea2SRichard Henderson {
614e2577ea2SRichard Henderson     for (int i = 0; i < nb_args; i++) {
615e2577ea2SRichard Henderson         TCGTemp *ts = arg_temp(op->args[i]);
616e2577ea2SRichard Henderson         if (ts) {
617e2577ea2SRichard Henderson             init_ts_info(ctx, ts);
618e2577ea2SRichard Henderson         }
619e2577ea2SRichard Henderson     }
620e2577ea2SRichard Henderson }
621e2577ea2SRichard Henderson 
6228774ddedSRichard Henderson static void copy_propagate(OptContext *ctx, TCGOp *op,
6238774ddedSRichard Henderson                            int nb_oargs, int nb_iargs)
6248774ddedSRichard Henderson {
6258774ddedSRichard Henderson     TCGContext *s = ctx->tcg;
6268774ddedSRichard Henderson 
6278774ddedSRichard Henderson     for (int i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
6288774ddedSRichard Henderson         TCGTemp *ts = arg_temp(op->args[i]);
6298774ddedSRichard Henderson         if (ts && ts_is_copy(ts)) {
6308774ddedSRichard Henderson             op->args[i] = temp_arg(find_better_copy(s, ts));
6318774ddedSRichard Henderson         }
6328774ddedSRichard Henderson     }
6338774ddedSRichard Henderson }
6348774ddedSRichard Henderson 
635137f1f44SRichard Henderson static void finish_folding(OptContext *ctx, TCGOp *op)
636137f1f44SRichard Henderson {
637137f1f44SRichard Henderson     const TCGOpDef *def = &tcg_op_defs[op->opc];
638137f1f44SRichard Henderson     int i, nb_oargs;
639137f1f44SRichard Henderson 
640137f1f44SRichard Henderson     /*
641137f1f44SRichard Henderson      * For an opcode that ends a BB, reset all temp data.
642137f1f44SRichard Henderson      * We do no cross-BB optimization.
643137f1f44SRichard Henderson      */
644137f1f44SRichard Henderson     if (def->flags & TCG_OPF_BB_END) {
645137f1f44SRichard Henderson         memset(&ctx->temps_used, 0, sizeof(ctx->temps_used));
646137f1f44SRichard Henderson         ctx->prev_mb = NULL;
647137f1f44SRichard Henderson         return;
648137f1f44SRichard Henderson     }
649137f1f44SRichard Henderson 
650137f1f44SRichard Henderson     nb_oargs = def->nb_oargs;
651137f1f44SRichard Henderson     for (i = 0; i < nb_oargs; i++) {
652137f1f44SRichard Henderson         reset_temp(op->args[i]);
653137f1f44SRichard Henderson         /*
654137f1f44SRichard Henderson          * Save the corresponding known-zero bits mask for the
655137f1f44SRichard Henderson          * first output argument (only one supported so far).
656137f1f44SRichard Henderson          */
657137f1f44SRichard Henderson         if (i == 0) {
658137f1f44SRichard Henderson             arg_info(op->args[i])->z_mask = ctx->z_mask;
659137f1f44SRichard Henderson         }
660137f1f44SRichard Henderson     }
661137f1f44SRichard Henderson }
662137f1f44SRichard Henderson 
6635cf32be7SRichard Henderson static bool fold_call(OptContext *ctx, TCGOp *op)
6645cf32be7SRichard Henderson {
6655cf32be7SRichard Henderson     TCGContext *s = ctx->tcg;
6665cf32be7SRichard Henderson     int nb_oargs = TCGOP_CALLO(op);
6675cf32be7SRichard Henderson     int nb_iargs = TCGOP_CALLI(op);
6685cf32be7SRichard Henderson     int flags, i;
6695cf32be7SRichard Henderson 
6705cf32be7SRichard Henderson     init_arguments(ctx, op, nb_oargs + nb_iargs);
6715cf32be7SRichard Henderson     copy_propagate(ctx, op, nb_oargs, nb_iargs);
6725cf32be7SRichard Henderson 
6735cf32be7SRichard Henderson     /* If the function reads or writes globals, reset temp data. */
6745cf32be7SRichard Henderson     flags = tcg_call_flags(op);
6755cf32be7SRichard Henderson     if (!(flags & (TCG_CALL_NO_READ_GLOBALS | TCG_CALL_NO_WRITE_GLOBALS))) {
6765cf32be7SRichard Henderson         int nb_globals = s->nb_globals;
6775cf32be7SRichard Henderson 
6785cf32be7SRichard Henderson         for (i = 0; i < nb_globals; i++) {
6795cf32be7SRichard Henderson             if (test_bit(i, ctx->temps_used.l)) {
6805cf32be7SRichard Henderson                 reset_ts(&ctx->tcg->temps[i]);
6815cf32be7SRichard Henderson             }
6825cf32be7SRichard Henderson         }
6835cf32be7SRichard Henderson     }
6845cf32be7SRichard Henderson 
6855cf32be7SRichard Henderson     /* Reset temp data for outputs. */
6865cf32be7SRichard Henderson     for (i = 0; i < nb_oargs; i++) {
6875cf32be7SRichard Henderson         reset_temp(op->args[i]);
6885cf32be7SRichard Henderson     }
6895cf32be7SRichard Henderson 
6905cf32be7SRichard Henderson     /* Stop optimizing MB across calls. */
6915cf32be7SRichard Henderson     ctx->prev_mb = NULL;
6925cf32be7SRichard Henderson     return true;
6935cf32be7SRichard Henderson }
6945cf32be7SRichard Henderson 
69522613af4SKirill Batuzov /* Propagate constants and copies, fold constant expressions. */
69636e60ef6SAurelien Jarno void tcg_optimize(TCGContext *s)
6978f2e8c07SKirill Batuzov {
6985cf32be7SRichard Henderson     int nb_temps, i;
699d0ed5151SRichard Henderson     TCGOp *op, *op_next;
700dc84988aSRichard Henderson     OptContext ctx = { .tcg = s };
7015d8f5363SRichard Henderson 
70222613af4SKirill Batuzov     /* Array VALS has an element for each temp.
70322613af4SKirill Batuzov        If this temp holds a constant then its value is kept in VALS' element.
704e590d4e6SAurelien Jarno        If this temp is a copy of other ones then the other copies are
705e590d4e6SAurelien Jarno        available through the doubly linked circular list. */
7068f2e8c07SKirill Batuzov 
7078f2e8c07SKirill Batuzov     nb_temps = s->nb_temps;
7088f17a975SRichard Henderson     for (i = 0; i < nb_temps; ++i) {
7098f17a975SRichard Henderson         s->temps[i].state_ptr = NULL;
7108f17a975SRichard Henderson     }
7118f2e8c07SKirill Batuzov 
71215fa08f8SRichard Henderson     QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
713b1fde411SRichard Henderson         uint64_t z_mask, partmask, affected, tmp;
714c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
7155cf32be7SRichard Henderson         const TCGOpDef *def;
716*404a148dSRichard Henderson         bool done = false;
717c45cb8bbSRichard Henderson 
7185cf32be7SRichard Henderson         /* Calls are special. */
719c45cb8bbSRichard Henderson         if (opc == INDEX_op_call) {
7205cf32be7SRichard Henderson             fold_call(&ctx, op);
7215cf32be7SRichard Henderson             continue;
7225cf32be7SRichard Henderson         }
7235cf32be7SRichard Henderson 
7245cf32be7SRichard Henderson         def = &tcg_op_defs[opc];
725ec5d4cbeSRichard Henderson         init_arguments(&ctx, op, def->nb_oargs + def->nb_iargs);
726ec5d4cbeSRichard Henderson         copy_propagate(&ctx, op, def->nb_oargs, def->nb_iargs);
72722613af4SKirill Batuzov 
72853108fb5SKirill Batuzov         /* For commutative operations make constant second argument */
729c45cb8bbSRichard Henderson         switch (opc) {
730170ba88fSRichard Henderson         CASE_OP_32_64_VEC(add):
731170ba88fSRichard Henderson         CASE_OP_32_64_VEC(mul):
732170ba88fSRichard Henderson         CASE_OP_32_64_VEC(and):
733170ba88fSRichard Henderson         CASE_OP_32_64_VEC(or):
734170ba88fSRichard Henderson         CASE_OP_32_64_VEC(xor):
735cb25c80aSRichard Henderson         CASE_OP_32_64(eqv):
736cb25c80aSRichard Henderson         CASE_OP_32_64(nand):
737cb25c80aSRichard Henderson         CASE_OP_32_64(nor):
73803271524SRichard Henderson         CASE_OP_32_64(muluh):
73903271524SRichard Henderson         CASE_OP_32_64(mulsh):
740acd93701SRichard Henderson             swap_commutative(op->args[0], &op->args[1], &op->args[2]);
74153108fb5SKirill Batuzov             break;
74265a7cce1SAurelien Jarno         CASE_OP_32_64(brcond):
743acd93701SRichard Henderson             if (swap_commutative(-1, &op->args[0], &op->args[1])) {
744acd93701SRichard Henderson                 op->args[2] = tcg_swap_cond(op->args[2]);
74565a7cce1SAurelien Jarno             }
74665a7cce1SAurelien Jarno             break;
74765a7cce1SAurelien Jarno         CASE_OP_32_64(setcond):
748acd93701SRichard Henderson             if (swap_commutative(op->args[0], &op->args[1], &op->args[2])) {
749acd93701SRichard Henderson                 op->args[3] = tcg_swap_cond(op->args[3]);
75065a7cce1SAurelien Jarno             }
75165a7cce1SAurelien Jarno             break;
752fa01a208SRichard Henderson         CASE_OP_32_64(movcond):
753acd93701SRichard Henderson             if (swap_commutative(-1, &op->args[1], &op->args[2])) {
754acd93701SRichard Henderson                 op->args[5] = tcg_swap_cond(op->args[5]);
755fa01a208SRichard Henderson             }
7565d8f5363SRichard Henderson             /* For movcond, we canonicalize the "false" input reg to match
7575d8f5363SRichard Henderson                the destination reg so that the tcg backend can implement
7585d8f5363SRichard Henderson                a "move if true" operation.  */
759acd93701SRichard Henderson             if (swap_commutative(op->args[0], &op->args[4], &op->args[3])) {
760acd93701SRichard Henderson                 op->args[5] = tcg_invert_cond(op->args[5]);
7615d8f5363SRichard Henderson             }
7621e484e61SRichard Henderson             break;
763d7156f7cSRichard Henderson         CASE_OP_32_64(add2):
764acd93701SRichard Henderson             swap_commutative(op->args[0], &op->args[2], &op->args[4]);
765acd93701SRichard Henderson             swap_commutative(op->args[1], &op->args[3], &op->args[5]);
7661e484e61SRichard Henderson             break;
767d7156f7cSRichard Henderson         CASE_OP_32_64(mulu2):
7684d3203fdSRichard Henderson         CASE_OP_32_64(muls2):
769acd93701SRichard Henderson             swap_commutative(op->args[0], &op->args[2], &op->args[3]);
7701414968aSRichard Henderson             break;
7710bfcb865SRichard Henderson         case INDEX_op_brcond2_i32:
772acd93701SRichard Henderson             if (swap_commutative2(&op->args[0], &op->args[2])) {
773acd93701SRichard Henderson                 op->args[4] = tcg_swap_cond(op->args[4]);
7740bfcb865SRichard Henderson             }
7750bfcb865SRichard Henderson             break;
7760bfcb865SRichard Henderson         case INDEX_op_setcond2_i32:
777acd93701SRichard Henderson             if (swap_commutative2(&op->args[1], &op->args[3])) {
778acd93701SRichard Henderson                 op->args[5] = tcg_swap_cond(op->args[5]);
7790bfcb865SRichard Henderson             }
7800bfcb865SRichard Henderson             break;
78153108fb5SKirill Batuzov         default:
78253108fb5SKirill Batuzov             break;
78353108fb5SKirill Batuzov         }
78453108fb5SKirill Batuzov 
7852d497542SRichard Henderson         /* Simplify expressions for "shift/rot r, 0, a => movi r, 0",
7862d497542SRichard Henderson            and "sub r, 0, a => neg r, a" case.  */
787c45cb8bbSRichard Henderson         switch (opc) {
78801ee5282SAurelien Jarno         CASE_OP_32_64(shl):
78901ee5282SAurelien Jarno         CASE_OP_32_64(shr):
79001ee5282SAurelien Jarno         CASE_OP_32_64(sar):
79101ee5282SAurelien Jarno         CASE_OP_32_64(rotl):
79201ee5282SAurelien Jarno         CASE_OP_32_64(rotr):
7936349039dSRichard Henderson             if (arg_is_const(op->args[1])
7946349039dSRichard Henderson                 && arg_info(op->args[1])->val == 0) {
795dc84988aSRichard Henderson                 tcg_opt_gen_movi(&ctx, op, op->args[0], 0);
79601ee5282SAurelien Jarno                 continue;
79701ee5282SAurelien Jarno             }
79801ee5282SAurelien Jarno             break;
799170ba88fSRichard Henderson         CASE_OP_32_64_VEC(sub):
8002d497542SRichard Henderson             {
8012d497542SRichard Henderson                 TCGOpcode neg_op;
8022d497542SRichard Henderson                 bool have_neg;
8032d497542SRichard Henderson 
8046349039dSRichard Henderson                 if (arg_is_const(op->args[2])) {
8052d497542SRichard Henderson                     /* Proceed with possible constant folding. */
8062d497542SRichard Henderson                     break;
8072d497542SRichard Henderson                 }
808c45cb8bbSRichard Henderson                 if (opc == INDEX_op_sub_i32) {
8092d497542SRichard Henderson                     neg_op = INDEX_op_neg_i32;
8102d497542SRichard Henderson                     have_neg = TCG_TARGET_HAS_neg_i32;
811170ba88fSRichard Henderson                 } else if (opc == INDEX_op_sub_i64) {
8122d497542SRichard Henderson                     neg_op = INDEX_op_neg_i64;
8132d497542SRichard Henderson                     have_neg = TCG_TARGET_HAS_neg_i64;
814ac383ddeSRichard Henderson                 } else if (TCG_TARGET_HAS_neg_vec) {
815ac383ddeSRichard Henderson                     TCGType type = TCGOP_VECL(op) + TCG_TYPE_V64;
816ac383ddeSRichard Henderson                     unsigned vece = TCGOP_VECE(op);
817170ba88fSRichard Henderson                     neg_op = INDEX_op_neg_vec;
818ac383ddeSRichard Henderson                     have_neg = tcg_can_emit_vec_op(neg_op, type, vece) > 0;
819ac383ddeSRichard Henderson                 } else {
820ac383ddeSRichard Henderson                     break;
8212d497542SRichard Henderson                 }
8222d497542SRichard Henderson                 if (!have_neg) {
8232d497542SRichard Henderson                     break;
8242d497542SRichard Henderson                 }
8256349039dSRichard Henderson                 if (arg_is_const(op->args[1])
8266349039dSRichard Henderson                     && arg_info(op->args[1])->val == 0) {
827c45cb8bbSRichard Henderson                     op->opc = neg_op;
828acd93701SRichard Henderson                     reset_temp(op->args[0]);
829acd93701SRichard Henderson                     op->args[1] = op->args[2];
8302d497542SRichard Henderson                     continue;
8312d497542SRichard Henderson                 }
8322d497542SRichard Henderson             }
8332d497542SRichard Henderson             break;
834170ba88fSRichard Henderson         CASE_OP_32_64_VEC(xor):
835e201b564SRichard Henderson         CASE_OP_32_64(nand):
8366349039dSRichard Henderson             if (!arg_is_const(op->args[1])
8376349039dSRichard Henderson                 && arg_is_const(op->args[2])
8386349039dSRichard Henderson                 && arg_info(op->args[2])->val == -1) {
839e201b564SRichard Henderson                 i = 1;
840e201b564SRichard Henderson                 goto try_not;
841e201b564SRichard Henderson             }
842e201b564SRichard Henderson             break;
843e201b564SRichard Henderson         CASE_OP_32_64(nor):
8446349039dSRichard Henderson             if (!arg_is_const(op->args[1])
8456349039dSRichard Henderson                 && arg_is_const(op->args[2])
8466349039dSRichard Henderson                 && arg_info(op->args[2])->val == 0) {
847e201b564SRichard Henderson                 i = 1;
848e201b564SRichard Henderson                 goto try_not;
849e201b564SRichard Henderson             }
850e201b564SRichard Henderson             break;
851170ba88fSRichard Henderson         CASE_OP_32_64_VEC(andc):
8526349039dSRichard Henderson             if (!arg_is_const(op->args[2])
8536349039dSRichard Henderson                 && arg_is_const(op->args[1])
8546349039dSRichard Henderson                 && arg_info(op->args[1])->val == -1) {
855e201b564SRichard Henderson                 i = 2;
856e201b564SRichard Henderson                 goto try_not;
857e201b564SRichard Henderson             }
858e201b564SRichard Henderson             break;
859170ba88fSRichard Henderson         CASE_OP_32_64_VEC(orc):
860e201b564SRichard Henderson         CASE_OP_32_64(eqv):
8616349039dSRichard Henderson             if (!arg_is_const(op->args[2])
8626349039dSRichard Henderson                 && arg_is_const(op->args[1])
8636349039dSRichard Henderson                 && arg_info(op->args[1])->val == 0) {
864e201b564SRichard Henderson                 i = 2;
865e201b564SRichard Henderson                 goto try_not;
866e201b564SRichard Henderson             }
867e201b564SRichard Henderson             break;
868e201b564SRichard Henderson         try_not:
869e201b564SRichard Henderson             {
870e201b564SRichard Henderson                 TCGOpcode not_op;
871e201b564SRichard Henderson                 bool have_not;
872e201b564SRichard Henderson 
873170ba88fSRichard Henderson                 if (def->flags & TCG_OPF_VECTOR) {
874170ba88fSRichard Henderson                     not_op = INDEX_op_not_vec;
875170ba88fSRichard Henderson                     have_not = TCG_TARGET_HAS_not_vec;
876170ba88fSRichard Henderson                 } else if (def->flags & TCG_OPF_64BIT) {
877e201b564SRichard Henderson                     not_op = INDEX_op_not_i64;
878e201b564SRichard Henderson                     have_not = TCG_TARGET_HAS_not_i64;
879e201b564SRichard Henderson                 } else {
880e201b564SRichard Henderson                     not_op = INDEX_op_not_i32;
881e201b564SRichard Henderson                     have_not = TCG_TARGET_HAS_not_i32;
882e201b564SRichard Henderson                 }
883e201b564SRichard Henderson                 if (!have_not) {
884e201b564SRichard Henderson                     break;
885e201b564SRichard Henderson                 }
886c45cb8bbSRichard Henderson                 op->opc = not_op;
887acd93701SRichard Henderson                 reset_temp(op->args[0]);
888acd93701SRichard Henderson                 op->args[1] = op->args[i];
889e201b564SRichard Henderson                 continue;
890e201b564SRichard Henderson             }
89101ee5282SAurelien Jarno         default:
89201ee5282SAurelien Jarno             break;
89301ee5282SAurelien Jarno         }
89401ee5282SAurelien Jarno 
895464a1441SRichard Henderson         /* Simplify expression for "op r, a, const => mov r, a" cases */
896c45cb8bbSRichard Henderson         switch (opc) {
897170ba88fSRichard Henderson         CASE_OP_32_64_VEC(add):
898170ba88fSRichard Henderson         CASE_OP_32_64_VEC(sub):
899170ba88fSRichard Henderson         CASE_OP_32_64_VEC(or):
900170ba88fSRichard Henderson         CASE_OP_32_64_VEC(xor):
901170ba88fSRichard Henderson         CASE_OP_32_64_VEC(andc):
90255c0975cSKirill Batuzov         CASE_OP_32_64(shl):
90355c0975cSKirill Batuzov         CASE_OP_32_64(shr):
90455c0975cSKirill Batuzov         CASE_OP_32_64(sar):
90525c4d9ccSRichard Henderson         CASE_OP_32_64(rotl):
90625c4d9ccSRichard Henderson         CASE_OP_32_64(rotr):
9076349039dSRichard Henderson             if (!arg_is_const(op->args[1])
9086349039dSRichard Henderson                 && arg_is_const(op->args[2])
9096349039dSRichard Henderson                 && arg_info(op->args[2])->val == 0) {
910dc84988aSRichard Henderson                 tcg_opt_gen_mov(&ctx, op, op->args[0], op->args[1]);
91197a79eb7SAurelien Jarno                 continue;
912464a1441SRichard Henderson             }
913464a1441SRichard Henderson             break;
914170ba88fSRichard Henderson         CASE_OP_32_64_VEC(and):
915170ba88fSRichard Henderson         CASE_OP_32_64_VEC(orc):
916464a1441SRichard Henderson         CASE_OP_32_64(eqv):
9176349039dSRichard Henderson             if (!arg_is_const(op->args[1])
9186349039dSRichard Henderson                 && arg_is_const(op->args[2])
9196349039dSRichard Henderson                 && arg_info(op->args[2])->val == -1) {
920dc84988aSRichard Henderson                 tcg_opt_gen_mov(&ctx, op, op->args[0], op->args[1]);
92153108fb5SKirill Batuzov                 continue;
92297a79eb7SAurelien Jarno             }
92397a79eb7SAurelien Jarno             break;
92456e49438SAurelien Jarno         default:
92556e49438SAurelien Jarno             break;
92656e49438SAurelien Jarno         }
92756e49438SAurelien Jarno 
9283031244bSAurelien Jarno         /* Simplify using known-zero bits. Currently only ops with a single
9293031244bSAurelien Jarno            output argument is supported. */
930b1fde411SRichard Henderson         z_mask = -1;
931633f6502SPaolo Bonzini         affected = -1;
932c45cb8bbSRichard Henderson         switch (opc) {
9333a9d8b17SPaolo Bonzini         CASE_OP_32_64(ext8s):
934b1fde411SRichard Henderson             if ((arg_info(op->args[1])->z_mask & 0x80) != 0) {
9353a9d8b17SPaolo Bonzini                 break;
9363a9d8b17SPaolo Bonzini             }
937d84568b7SThomas Huth             QEMU_FALLTHROUGH;
9383a9d8b17SPaolo Bonzini         CASE_OP_32_64(ext8u):
939b1fde411SRichard Henderson             z_mask = 0xff;
9403a9d8b17SPaolo Bonzini             goto and_const;
9413a9d8b17SPaolo Bonzini         CASE_OP_32_64(ext16s):
942b1fde411SRichard Henderson             if ((arg_info(op->args[1])->z_mask & 0x8000) != 0) {
9433a9d8b17SPaolo Bonzini                 break;
9443a9d8b17SPaolo Bonzini             }
945d84568b7SThomas Huth             QEMU_FALLTHROUGH;
9463a9d8b17SPaolo Bonzini         CASE_OP_32_64(ext16u):
947b1fde411SRichard Henderson             z_mask = 0xffff;
9483a9d8b17SPaolo Bonzini             goto and_const;
9493a9d8b17SPaolo Bonzini         case INDEX_op_ext32s_i64:
950b1fde411SRichard Henderson             if ((arg_info(op->args[1])->z_mask & 0x80000000) != 0) {
9513a9d8b17SPaolo Bonzini                 break;
9523a9d8b17SPaolo Bonzini             }
953d84568b7SThomas Huth             QEMU_FALLTHROUGH;
9543a9d8b17SPaolo Bonzini         case INDEX_op_ext32u_i64:
955b1fde411SRichard Henderson             z_mask = 0xffffffffU;
9563a9d8b17SPaolo Bonzini             goto and_const;
9573a9d8b17SPaolo Bonzini 
9583a9d8b17SPaolo Bonzini         CASE_OP_32_64(and):
959b1fde411SRichard Henderson             z_mask = arg_info(op->args[2])->z_mask;
9606349039dSRichard Henderson             if (arg_is_const(op->args[2])) {
9613a9d8b17SPaolo Bonzini         and_const:
962b1fde411SRichard Henderson                 affected = arg_info(op->args[1])->z_mask & ~z_mask;
9633a9d8b17SPaolo Bonzini             }
964b1fde411SRichard Henderson             z_mask = arg_info(op->args[1])->z_mask & z_mask;
9653a9d8b17SPaolo Bonzini             break;
9663a9d8b17SPaolo Bonzini 
9678bcb5c8fSAurelien Jarno         case INDEX_op_ext_i32_i64:
968b1fde411SRichard Henderson             if ((arg_info(op->args[1])->z_mask & 0x80000000) != 0) {
9698bcb5c8fSAurelien Jarno                 break;
9708bcb5c8fSAurelien Jarno             }
971d84568b7SThomas Huth             QEMU_FALLTHROUGH;
9728bcb5c8fSAurelien Jarno         case INDEX_op_extu_i32_i64:
9738bcb5c8fSAurelien Jarno             /* We do not compute affected as it is a size changing op.  */
974b1fde411SRichard Henderson             z_mask = (uint32_t)arg_info(op->args[1])->z_mask;
9758bcb5c8fSAurelien Jarno             break;
9768bcb5c8fSAurelien Jarno 
97723ec69edSRichard Henderson         CASE_OP_32_64(andc):
97823ec69edSRichard Henderson             /* Known-zeros does not imply known-ones.  Therefore unless
979acd93701SRichard Henderson                op->args[2] is constant, we can't infer anything from it.  */
9806349039dSRichard Henderson             if (arg_is_const(op->args[2])) {
981b1fde411SRichard Henderson                 z_mask = ~arg_info(op->args[2])->z_mask;
98223ec69edSRichard Henderson                 goto and_const;
98323ec69edSRichard Henderson             }
9846349039dSRichard Henderson             /* But we certainly know nothing outside args[1] may be set. */
985b1fde411SRichard Henderson             z_mask = arg_info(op->args[1])->z_mask;
98623ec69edSRichard Henderson             break;
98723ec69edSRichard Henderson 
988e46b225aSAurelien Jarno         case INDEX_op_sar_i32:
9896349039dSRichard Henderson             if (arg_is_const(op->args[2])) {
9906349039dSRichard Henderson                 tmp = arg_info(op->args[2])->val & 31;
991b1fde411SRichard Henderson                 z_mask = (int32_t)arg_info(op->args[1])->z_mask >> tmp;
992e46b225aSAurelien Jarno             }
993e46b225aSAurelien Jarno             break;
994e46b225aSAurelien Jarno         case INDEX_op_sar_i64:
9956349039dSRichard Henderson             if (arg_is_const(op->args[2])) {
9966349039dSRichard Henderson                 tmp = arg_info(op->args[2])->val & 63;
997b1fde411SRichard Henderson                 z_mask = (int64_t)arg_info(op->args[1])->z_mask >> tmp;
9983a9d8b17SPaolo Bonzini             }
9993a9d8b17SPaolo Bonzini             break;
10003a9d8b17SPaolo Bonzini 
1001e46b225aSAurelien Jarno         case INDEX_op_shr_i32:
10026349039dSRichard Henderson             if (arg_is_const(op->args[2])) {
10036349039dSRichard Henderson                 tmp = arg_info(op->args[2])->val & 31;
1004b1fde411SRichard Henderson                 z_mask = (uint32_t)arg_info(op->args[1])->z_mask >> tmp;
1005e46b225aSAurelien Jarno             }
1006e46b225aSAurelien Jarno             break;
1007e46b225aSAurelien Jarno         case INDEX_op_shr_i64:
10086349039dSRichard Henderson             if (arg_is_const(op->args[2])) {
10096349039dSRichard Henderson                 tmp = arg_info(op->args[2])->val & 63;
1010b1fde411SRichard Henderson                 z_mask = (uint64_t)arg_info(op->args[1])->z_mask >> tmp;
10113a9d8b17SPaolo Bonzini             }
10123a9d8b17SPaolo Bonzini             break;
10133a9d8b17SPaolo Bonzini 
1014609ad705SRichard Henderson         case INDEX_op_extrl_i64_i32:
1015b1fde411SRichard Henderson             z_mask = (uint32_t)arg_info(op->args[1])->z_mask;
1016609ad705SRichard Henderson             break;
1017609ad705SRichard Henderson         case INDEX_op_extrh_i64_i32:
1018b1fde411SRichard Henderson             z_mask = (uint64_t)arg_info(op->args[1])->z_mask >> 32;
10194bb7a41eSRichard Henderson             break;
10204bb7a41eSRichard Henderson 
10213a9d8b17SPaolo Bonzini         CASE_OP_32_64(shl):
10226349039dSRichard Henderson             if (arg_is_const(op->args[2])) {
10236349039dSRichard Henderson                 tmp = arg_info(op->args[2])->val & (TCG_TARGET_REG_BITS - 1);
1024b1fde411SRichard Henderson                 z_mask = arg_info(op->args[1])->z_mask << tmp;
10253a9d8b17SPaolo Bonzini             }
10263a9d8b17SPaolo Bonzini             break;
10273a9d8b17SPaolo Bonzini 
10283a9d8b17SPaolo Bonzini         CASE_OP_32_64(neg):
10293a9d8b17SPaolo Bonzini             /* Set to 1 all bits to the left of the rightmost.  */
1030b1fde411SRichard Henderson             z_mask = -(arg_info(op->args[1])->z_mask
1031b1fde411SRichard Henderson                        & -arg_info(op->args[1])->z_mask);
10323a9d8b17SPaolo Bonzini             break;
10333a9d8b17SPaolo Bonzini 
10343a9d8b17SPaolo Bonzini         CASE_OP_32_64(deposit):
1035b1fde411SRichard Henderson             z_mask = deposit64(arg_info(op->args[1])->z_mask,
10366349039dSRichard Henderson                                op->args[3], op->args[4],
1037b1fde411SRichard Henderson                                arg_info(op->args[2])->z_mask);
10383a9d8b17SPaolo Bonzini             break;
10393a9d8b17SPaolo Bonzini 
10407ec8bab3SRichard Henderson         CASE_OP_32_64(extract):
1041b1fde411SRichard Henderson             z_mask = extract64(arg_info(op->args[1])->z_mask,
10426349039dSRichard Henderson                                op->args[2], op->args[3]);
1043acd93701SRichard Henderson             if (op->args[2] == 0) {
1044b1fde411SRichard Henderson                 affected = arg_info(op->args[1])->z_mask & ~z_mask;
10457ec8bab3SRichard Henderson             }
10467ec8bab3SRichard Henderson             break;
10477ec8bab3SRichard Henderson         CASE_OP_32_64(sextract):
1048b1fde411SRichard Henderson             z_mask = sextract64(arg_info(op->args[1])->z_mask,
1049acd93701SRichard Henderson                                 op->args[2], op->args[3]);
1050b1fde411SRichard Henderson             if (op->args[2] == 0 && (tcg_target_long)z_mask >= 0) {
1051b1fde411SRichard Henderson                 affected = arg_info(op->args[1])->z_mask & ~z_mask;
10527ec8bab3SRichard Henderson             }
10537ec8bab3SRichard Henderson             break;
10547ec8bab3SRichard Henderson 
10553a9d8b17SPaolo Bonzini         CASE_OP_32_64(or):
10563a9d8b17SPaolo Bonzini         CASE_OP_32_64(xor):
1057b1fde411SRichard Henderson             z_mask = arg_info(op->args[1])->z_mask
1058b1fde411SRichard Henderson                    | arg_info(op->args[2])->z_mask;
10593a9d8b17SPaolo Bonzini             break;
10603a9d8b17SPaolo Bonzini 
10610e28d006SRichard Henderson         case INDEX_op_clz_i32:
10620e28d006SRichard Henderson         case INDEX_op_ctz_i32:
1063b1fde411SRichard Henderson             z_mask = arg_info(op->args[2])->z_mask | 31;
10640e28d006SRichard Henderson             break;
10650e28d006SRichard Henderson 
10660e28d006SRichard Henderson         case INDEX_op_clz_i64:
10670e28d006SRichard Henderson         case INDEX_op_ctz_i64:
1068b1fde411SRichard Henderson             z_mask = arg_info(op->args[2])->z_mask | 63;
10690e28d006SRichard Henderson             break;
10700e28d006SRichard Henderson 
1071a768e4e9SRichard Henderson         case INDEX_op_ctpop_i32:
1072b1fde411SRichard Henderson             z_mask = 32 | 31;
1073a768e4e9SRichard Henderson             break;
1074a768e4e9SRichard Henderson         case INDEX_op_ctpop_i64:
1075b1fde411SRichard Henderson             z_mask = 64 | 63;
1076a768e4e9SRichard Henderson             break;
1077a768e4e9SRichard Henderson 
10783a9d8b17SPaolo Bonzini         CASE_OP_32_64(setcond):
1079a763551aSRichard Henderson         case INDEX_op_setcond2_i32:
1080b1fde411SRichard Henderson             z_mask = 1;
10813a9d8b17SPaolo Bonzini             break;
10823a9d8b17SPaolo Bonzini 
10833a9d8b17SPaolo Bonzini         CASE_OP_32_64(movcond):
1084b1fde411SRichard Henderson             z_mask = arg_info(op->args[3])->z_mask
1085b1fde411SRichard Henderson                    | arg_info(op->args[4])->z_mask;
10863a9d8b17SPaolo Bonzini             break;
10873a9d8b17SPaolo Bonzini 
1088c8d70272SAurelien Jarno         CASE_OP_32_64(ld8u):
1089b1fde411SRichard Henderson             z_mask = 0xff;
1090c8d70272SAurelien Jarno             break;
1091c8d70272SAurelien Jarno         CASE_OP_32_64(ld16u):
1092b1fde411SRichard Henderson             z_mask = 0xffff;
1093c8d70272SAurelien Jarno             break;
1094c8d70272SAurelien Jarno         case INDEX_op_ld32u_i64:
1095b1fde411SRichard Henderson             z_mask = 0xffffffffu;
1096c8d70272SAurelien Jarno             break;
1097c8d70272SAurelien Jarno 
1098c8d70272SAurelien Jarno         CASE_OP_32_64(qemu_ld):
1099c8d70272SAurelien Jarno             {
1100ec5d4cbeSRichard Henderson                 MemOpIdx oi = op->args[def->nb_oargs + def->nb_iargs];
110114776ab5STony Nguyen                 MemOp mop = get_memop(oi);
1102c8d70272SAurelien Jarno                 if (!(mop & MO_SIGN)) {
1103b1fde411SRichard Henderson                     z_mask = (2ULL << ((8 << (mop & MO_SIZE)) - 1)) - 1;
1104c8d70272SAurelien Jarno                 }
1105c8d70272SAurelien Jarno             }
1106c8d70272SAurelien Jarno             break;
1107c8d70272SAurelien Jarno 
11080b76ff8fSRichard Henderson         CASE_OP_32_64(bswap16):
1109b1fde411SRichard Henderson             z_mask = arg_info(op->args[1])->z_mask;
1110b1fde411SRichard Henderson             if (z_mask <= 0xffff) {
11110b76ff8fSRichard Henderson                 op->args[2] |= TCG_BSWAP_IZ;
11120b76ff8fSRichard Henderson             }
1113b1fde411SRichard Henderson             z_mask = bswap16(z_mask);
11140b76ff8fSRichard Henderson             switch (op->args[2] & (TCG_BSWAP_OZ | TCG_BSWAP_OS)) {
11150b76ff8fSRichard Henderson             case TCG_BSWAP_OZ:
11160b76ff8fSRichard Henderson                 break;
11170b76ff8fSRichard Henderson             case TCG_BSWAP_OS:
1118b1fde411SRichard Henderson                 z_mask = (int16_t)z_mask;
11190b76ff8fSRichard Henderson                 break;
11200b76ff8fSRichard Henderson             default: /* undefined high bits */
1121b1fde411SRichard Henderson                 z_mask |= MAKE_64BIT_MASK(16, 48);
11220b76ff8fSRichard Henderson                 break;
11230b76ff8fSRichard Henderson             }
11240b76ff8fSRichard Henderson             break;
11250b76ff8fSRichard Henderson 
11260b76ff8fSRichard Henderson         case INDEX_op_bswap32_i64:
1127b1fde411SRichard Henderson             z_mask = arg_info(op->args[1])->z_mask;
1128b1fde411SRichard Henderson             if (z_mask <= 0xffffffffu) {
11290b76ff8fSRichard Henderson                 op->args[2] |= TCG_BSWAP_IZ;
11300b76ff8fSRichard Henderson             }
1131b1fde411SRichard Henderson             z_mask = bswap32(z_mask);
11320b76ff8fSRichard Henderson             switch (op->args[2] & (TCG_BSWAP_OZ | TCG_BSWAP_OS)) {
11330b76ff8fSRichard Henderson             case TCG_BSWAP_OZ:
11340b76ff8fSRichard Henderson                 break;
11350b76ff8fSRichard Henderson             case TCG_BSWAP_OS:
1136b1fde411SRichard Henderson                 z_mask = (int32_t)z_mask;
11370b76ff8fSRichard Henderson                 break;
11380b76ff8fSRichard Henderson             default: /* undefined high bits */
1139b1fde411SRichard Henderson                 z_mask |= MAKE_64BIT_MASK(32, 32);
11400b76ff8fSRichard Henderson                 break;
11410b76ff8fSRichard Henderson             }
11420b76ff8fSRichard Henderson             break;
11430b76ff8fSRichard Henderson 
11443a9d8b17SPaolo Bonzini         default:
11453a9d8b17SPaolo Bonzini             break;
11463a9d8b17SPaolo Bonzini         }
11473a9d8b17SPaolo Bonzini 
1148bc8d688fSRichard Henderson         /* 32-bit ops generate 32-bit results.  For the result is zero test
1149bc8d688fSRichard Henderson            below, we can ignore high bits, but for further optimizations we
1150bc8d688fSRichard Henderson            need to record that the high bits contain garbage.  */
1151b1fde411SRichard Henderson         partmask = z_mask;
1152bc8d688fSRichard Henderson         if (!(def->flags & TCG_OPF_64BIT)) {
1153b1fde411SRichard Henderson             z_mask |= ~(tcg_target_ulong)0xffffffffu;
115424666bafSRichard Henderson             partmask &= 0xffffffffu;
115524666bafSRichard Henderson             affected &= 0xffffffffu;
1156f096dc96SAurelien Jarno         }
1157137f1f44SRichard Henderson         ctx.z_mask = z_mask;
1158f096dc96SAurelien Jarno 
115924666bafSRichard Henderson         if (partmask == 0) {
1160dc84988aSRichard Henderson             tcg_opt_gen_movi(&ctx, op, op->args[0], 0);
1161633f6502SPaolo Bonzini             continue;
1162633f6502SPaolo Bonzini         }
1163633f6502SPaolo Bonzini         if (affected == 0) {
1164dc84988aSRichard Henderson             tcg_opt_gen_mov(&ctx, op, op->args[0], op->args[1]);
1165633f6502SPaolo Bonzini             continue;
1166633f6502SPaolo Bonzini         }
1167633f6502SPaolo Bonzini 
116856e49438SAurelien Jarno         /* Simplify expression for "op r, a, 0 => movi r, 0" cases */
1169c45cb8bbSRichard Henderson         switch (opc) {
1170170ba88fSRichard Henderson         CASE_OP_32_64_VEC(and):
1171170ba88fSRichard Henderson         CASE_OP_32_64_VEC(mul):
117203271524SRichard Henderson         CASE_OP_32_64(muluh):
117303271524SRichard Henderson         CASE_OP_32_64(mulsh):
11746349039dSRichard Henderson             if (arg_is_const(op->args[2])
11756349039dSRichard Henderson                 && arg_info(op->args[2])->val == 0) {
1176dc84988aSRichard Henderson                 tcg_opt_gen_movi(&ctx, op, op->args[0], 0);
117753108fb5SKirill Batuzov                 continue;
117853108fb5SKirill Batuzov             }
117953108fb5SKirill Batuzov             break;
118056e49438SAurelien Jarno         default:
118156e49438SAurelien Jarno             break;
118256e49438SAurelien Jarno         }
118356e49438SAurelien Jarno 
118456e49438SAurelien Jarno         /* Simplify expression for "op r, a, a => mov r, a" cases */
1185c45cb8bbSRichard Henderson         switch (opc) {
1186170ba88fSRichard Henderson         CASE_OP_32_64_VEC(or):
1187170ba88fSRichard Henderson         CASE_OP_32_64_VEC(and):
11886349039dSRichard Henderson             if (args_are_copies(op->args[1], op->args[2])) {
1189dc84988aSRichard Henderson                 tcg_opt_gen_mov(&ctx, op, op->args[0], op->args[1]);
11909a81090bSKirill Batuzov                 continue;
11919a81090bSKirill Batuzov             }
11929a81090bSKirill Batuzov             break;
1193fe0de7aaSBlue Swirl         default:
1194fe0de7aaSBlue Swirl             break;
119553108fb5SKirill Batuzov         }
119653108fb5SKirill Batuzov 
11973c94193eSAurelien Jarno         /* Simplify expression for "op r, a, a => movi r, 0" cases */
1198c45cb8bbSRichard Henderson         switch (opc) {
1199170ba88fSRichard Henderson         CASE_OP_32_64_VEC(andc):
1200170ba88fSRichard Henderson         CASE_OP_32_64_VEC(sub):
1201170ba88fSRichard Henderson         CASE_OP_32_64_VEC(xor):
12026349039dSRichard Henderson             if (args_are_copies(op->args[1], op->args[2])) {
1203dc84988aSRichard Henderson                 tcg_opt_gen_movi(&ctx, op, op->args[0], 0);
12043c94193eSAurelien Jarno                 continue;
12053c94193eSAurelien Jarno             }
12063c94193eSAurelien Jarno             break;
12073c94193eSAurelien Jarno         default:
12083c94193eSAurelien Jarno             break;
12093c94193eSAurelien Jarno         }
12103c94193eSAurelien Jarno 
121122613af4SKirill Batuzov         /* Propagate constants through copy operations and do constant
121222613af4SKirill Batuzov            folding.  Constants will be substituted to arguments by register
121322613af4SKirill Batuzov            allocator where needed and possible.  Also detect copies. */
1214c45cb8bbSRichard Henderson         switch (opc) {
1215170ba88fSRichard Henderson         CASE_OP_32_64_VEC(mov):
1216*404a148dSRichard Henderson             done = tcg_opt_gen_mov(&ctx, op, op->args[0], op->args[1]);
1217*404a148dSRichard Henderson             break;
12186e14e91bSRichard Henderson 
1219170ba88fSRichard Henderson         case INDEX_op_dup_vec:
1220170ba88fSRichard Henderson             if (arg_is_const(op->args[1])) {
1221170ba88fSRichard Henderson                 tmp = arg_info(op->args[1])->val;
1222170ba88fSRichard Henderson                 tmp = dup_const(TCGOP_VECE(op), tmp);
1223dc84988aSRichard Henderson                 tcg_opt_gen_movi(&ctx, op, op->args[0], tmp);
1224b10f3833SRichard Henderson                 continue;
12251fb57da7SRichard Henderson             }
1226b10f3833SRichard Henderson             break;
1227170ba88fSRichard Henderson 
12281dc4fe70SRichard Henderson         case INDEX_op_dup2_vec:
12291dc4fe70SRichard Henderson             assert(TCG_TARGET_REG_BITS == 32);
12301dc4fe70SRichard Henderson             if (arg_is_const(op->args[1]) && arg_is_const(op->args[2])) {
1231dc84988aSRichard Henderson                 tcg_opt_gen_movi(&ctx, op, op->args[0],
12320b4286ddSRichard Henderson                                  deposit64(arg_info(op->args[1])->val, 32, 32,
12330b4286ddSRichard Henderson                                            arg_info(op->args[2])->val));
1234b10f3833SRichard Henderson                 continue;
12351dc4fe70SRichard Henderson             } else if (args_are_copies(op->args[1], op->args[2])) {
12361dc4fe70SRichard Henderson                 op->opc = INDEX_op_dup_vec;
12371dc4fe70SRichard Henderson                 TCGOP_VECE(op) = MO_32;
12381dc4fe70SRichard Henderson             }
1239b10f3833SRichard Henderson             break;
12401dc4fe70SRichard Henderson 
1241a640f031SKirill Batuzov         CASE_OP_32_64(not):
1242cb25c80aSRichard Henderson         CASE_OP_32_64(neg):
124325c4d9ccSRichard Henderson         CASE_OP_32_64(ext8s):
124425c4d9ccSRichard Henderson         CASE_OP_32_64(ext8u):
124525c4d9ccSRichard Henderson         CASE_OP_32_64(ext16s):
124625c4d9ccSRichard Henderson         CASE_OP_32_64(ext16u):
1247a768e4e9SRichard Henderson         CASE_OP_32_64(ctpop):
1248a640f031SKirill Batuzov         case INDEX_op_ext32s_i64:
1249a640f031SKirill Batuzov         case INDEX_op_ext32u_i64:
12508bcb5c8fSAurelien Jarno         case INDEX_op_ext_i32_i64:
12518bcb5c8fSAurelien Jarno         case INDEX_op_extu_i32_i64:
1252609ad705SRichard Henderson         case INDEX_op_extrl_i64_i32:
1253609ad705SRichard Henderson         case INDEX_op_extrh_i64_i32:
12546349039dSRichard Henderson             if (arg_is_const(op->args[1])) {
12556349039dSRichard Henderson                 tmp = do_constant_folding(opc, arg_info(op->args[1])->val, 0);
1256dc84988aSRichard Henderson                 tcg_opt_gen_movi(&ctx, op, op->args[0], tmp);
1257b10f3833SRichard Henderson                 continue;
12586e14e91bSRichard Henderson             }
1259b10f3833SRichard Henderson             break;
12606e14e91bSRichard Henderson 
12610b76ff8fSRichard Henderson         CASE_OP_32_64(bswap16):
12620b76ff8fSRichard Henderson         CASE_OP_32_64(bswap32):
12630b76ff8fSRichard Henderson         case INDEX_op_bswap64_i64:
12640b76ff8fSRichard Henderson             if (arg_is_const(op->args[1])) {
12650b76ff8fSRichard Henderson                 tmp = do_constant_folding(opc, arg_info(op->args[1])->val,
12660b76ff8fSRichard Henderson                                           op->args[2]);
1267dc84988aSRichard Henderson                 tcg_opt_gen_movi(&ctx, op, op->args[0], tmp);
1268b10f3833SRichard Henderson                 continue;
12690b76ff8fSRichard Henderson             }
1270b10f3833SRichard Henderson             break;
12710b76ff8fSRichard Henderson 
127253108fb5SKirill Batuzov         CASE_OP_32_64(add):
127353108fb5SKirill Batuzov         CASE_OP_32_64(sub):
127453108fb5SKirill Batuzov         CASE_OP_32_64(mul):
12759a81090bSKirill Batuzov         CASE_OP_32_64(or):
12769a81090bSKirill Batuzov         CASE_OP_32_64(and):
12779a81090bSKirill Batuzov         CASE_OP_32_64(xor):
127855c0975cSKirill Batuzov         CASE_OP_32_64(shl):
127955c0975cSKirill Batuzov         CASE_OP_32_64(shr):
128055c0975cSKirill Batuzov         CASE_OP_32_64(sar):
128125c4d9ccSRichard Henderson         CASE_OP_32_64(rotl):
128225c4d9ccSRichard Henderson         CASE_OP_32_64(rotr):
1283cb25c80aSRichard Henderson         CASE_OP_32_64(andc):
1284cb25c80aSRichard Henderson         CASE_OP_32_64(orc):
1285cb25c80aSRichard Henderson         CASE_OP_32_64(eqv):
1286cb25c80aSRichard Henderson         CASE_OP_32_64(nand):
1287cb25c80aSRichard Henderson         CASE_OP_32_64(nor):
128803271524SRichard Henderson         CASE_OP_32_64(muluh):
128903271524SRichard Henderson         CASE_OP_32_64(mulsh):
129001547f7fSRichard Henderson         CASE_OP_32_64(div):
129101547f7fSRichard Henderson         CASE_OP_32_64(divu):
129201547f7fSRichard Henderson         CASE_OP_32_64(rem):
129301547f7fSRichard Henderson         CASE_OP_32_64(remu):
12946349039dSRichard Henderson             if (arg_is_const(op->args[1]) && arg_is_const(op->args[2])) {
12956349039dSRichard Henderson                 tmp = do_constant_folding(opc, arg_info(op->args[1])->val,
12966349039dSRichard Henderson                                           arg_info(op->args[2])->val);
1297dc84988aSRichard Henderson                 tcg_opt_gen_movi(&ctx, op, op->args[0], tmp);
1298b10f3833SRichard Henderson                 continue;
12996e14e91bSRichard Henderson             }
1300b10f3833SRichard Henderson             break;
13016e14e91bSRichard Henderson 
13020e28d006SRichard Henderson         CASE_OP_32_64(clz):
13030e28d006SRichard Henderson         CASE_OP_32_64(ctz):
13046349039dSRichard Henderson             if (arg_is_const(op->args[1])) {
13056349039dSRichard Henderson                 TCGArg v = arg_info(op->args[1])->val;
13060e28d006SRichard Henderson                 if (v != 0) {
13070e28d006SRichard Henderson                     tmp = do_constant_folding(opc, v, 0);
1308dc84988aSRichard Henderson                     tcg_opt_gen_movi(&ctx, op, op->args[0], tmp);
13090e28d006SRichard Henderson                 } else {
1310dc84988aSRichard Henderson                     tcg_opt_gen_mov(&ctx, op, op->args[0], op->args[2]);
13110e28d006SRichard Henderson                 }
1312b10f3833SRichard Henderson                 continue;
13130e28d006SRichard Henderson             }
1314b10f3833SRichard Henderson             break;
13150e28d006SRichard Henderson 
13167ef55fc9SAurelien Jarno         CASE_OP_32_64(deposit):
13176349039dSRichard Henderson             if (arg_is_const(op->args[1]) && arg_is_const(op->args[2])) {
13186349039dSRichard Henderson                 tmp = deposit64(arg_info(op->args[1])->val,
13196349039dSRichard Henderson                                 op->args[3], op->args[4],
13206349039dSRichard Henderson                                 arg_info(op->args[2])->val);
1321dc84988aSRichard Henderson                 tcg_opt_gen_movi(&ctx, op, op->args[0], tmp);
1322b10f3833SRichard Henderson                 continue;
13236e14e91bSRichard Henderson             }
1324b10f3833SRichard Henderson             break;
13256e14e91bSRichard Henderson 
13267ec8bab3SRichard Henderson         CASE_OP_32_64(extract):
13276349039dSRichard Henderson             if (arg_is_const(op->args[1])) {
13286349039dSRichard Henderson                 tmp = extract64(arg_info(op->args[1])->val,
1329acd93701SRichard Henderson                                 op->args[2], op->args[3]);
1330dc84988aSRichard Henderson                 tcg_opt_gen_movi(&ctx, op, op->args[0], tmp);
1331b10f3833SRichard Henderson                 continue;
13327ec8bab3SRichard Henderson             }
1333b10f3833SRichard Henderson             break;
13347ec8bab3SRichard Henderson 
13357ec8bab3SRichard Henderson         CASE_OP_32_64(sextract):
13366349039dSRichard Henderson             if (arg_is_const(op->args[1])) {
13376349039dSRichard Henderson                 tmp = sextract64(arg_info(op->args[1])->val,
1338acd93701SRichard Henderson                                  op->args[2], op->args[3]);
1339dc84988aSRichard Henderson                 tcg_opt_gen_movi(&ctx, op, op->args[0], tmp);
1340b10f3833SRichard Henderson                 continue;
13417ec8bab3SRichard Henderson             }
1342b10f3833SRichard Henderson             break;
13437ec8bab3SRichard Henderson 
1344fce1296fSRichard Henderson         CASE_OP_32_64(extract2):
1345fce1296fSRichard Henderson             if (arg_is_const(op->args[1]) && arg_is_const(op->args[2])) {
134654795544SRichard Henderson                 uint64_t v1 = arg_info(op->args[1])->val;
134754795544SRichard Henderson                 uint64_t v2 = arg_info(op->args[2])->val;
134854795544SRichard Henderson                 int shr = op->args[3];
1349fce1296fSRichard Henderson 
1350fce1296fSRichard Henderson                 if (opc == INDEX_op_extract2_i64) {
135154795544SRichard Henderson                     tmp = (v1 >> shr) | (v2 << (64 - shr));
1352fce1296fSRichard Henderson                 } else {
135354795544SRichard Henderson                     tmp = (int32_t)(((uint32_t)v1 >> shr) |
135454795544SRichard Henderson                                     ((uint32_t)v2 << (32 - shr)));
1355fce1296fSRichard Henderson                 }
1356dc84988aSRichard Henderson                 tcg_opt_gen_movi(&ctx, op, op->args[0], tmp);
1357b10f3833SRichard Henderson                 continue;
1358fce1296fSRichard Henderson             }
1359b10f3833SRichard Henderson             break;
1360fce1296fSRichard Henderson 
1361f8dd19e5SAurelien Jarno         CASE_OP_32_64(setcond):
13628d57bf1eSRichard Henderson             i = do_constant_folding_cond(opc, op->args[1],
1363acd93701SRichard Henderson                                          op->args[2], op->args[3]);
13648d57bf1eSRichard Henderson             if (i >= 0) {
13658d57bf1eSRichard Henderson                 tcg_opt_gen_movi(&ctx, op, op->args[0], i);
1366b10f3833SRichard Henderson                 continue;
13676e14e91bSRichard Henderson             }
1368b10f3833SRichard Henderson             break;
13696e14e91bSRichard Henderson 
1370fbeaa26cSAurelien Jarno         CASE_OP_32_64(brcond):
13718d57bf1eSRichard Henderson             i = do_constant_folding_cond(opc, op->args[0],
1372acd93701SRichard Henderson                                          op->args[1], op->args[2]);
13738d57bf1eSRichard Henderson             if (i == 0) {
13740c627cdcSRichard Henderson                 tcg_op_remove(s, op);
1375b10f3833SRichard Henderson                 continue;
13768d57bf1eSRichard Henderson             } else if (i > 0) {
1377b10f3833SRichard Henderson                 memset(&ctx.temps_used, 0, sizeof(ctx.temps_used));
1378b10f3833SRichard Henderson                 op->opc = opc = INDEX_op_br;
1379b10f3833SRichard Henderson                 op->args[0] = op->args[3];
1380fbeaa26cSAurelien Jarno                 break;
13816e14e91bSRichard Henderson             }
1382b10f3833SRichard Henderson             break;
13836e14e91bSRichard Henderson 
1384fa01a208SRichard Henderson         CASE_OP_32_64(movcond):
13858d57bf1eSRichard Henderson             i = do_constant_folding_cond(opc, op->args[1],
1386acd93701SRichard Henderson                                          op->args[2], op->args[5]);
13878d57bf1eSRichard Henderson             if (i >= 0) {
13888d57bf1eSRichard Henderson                 tcg_opt_gen_mov(&ctx, op, op->args[0], op->args[4 - i]);
1389b10f3833SRichard Henderson                 continue;
13906e14e91bSRichard Henderson             }
13916349039dSRichard Henderson             if (arg_is_const(op->args[3]) && arg_is_const(op->args[4])) {
139254795544SRichard Henderson                 uint64_t tv = arg_info(op->args[3])->val;
139354795544SRichard Henderson                 uint64_t fv = arg_info(op->args[4])->val;
1394acd93701SRichard Henderson                 TCGCond cond = op->args[5];
139554795544SRichard Henderson 
1396333b21b8SRichard Henderson                 if (fv == 1 && tv == 0) {
1397333b21b8SRichard Henderson                     cond = tcg_invert_cond(cond);
1398333b21b8SRichard Henderson                 } else if (!(tv == 1 && fv == 0)) {
1399b10f3833SRichard Henderson                     break;
1400333b21b8SRichard Henderson                 }
1401acd93701SRichard Henderson                 op->args[3] = cond;
1402333b21b8SRichard Henderson                 op->opc = opc = (opc == INDEX_op_movcond_i32
1403333b21b8SRichard Henderson                                  ? INDEX_op_setcond_i32
1404333b21b8SRichard Henderson                                  : INDEX_op_setcond_i64);
1405333b21b8SRichard Henderson             }
1406b10f3833SRichard Henderson             break;
14076e14e91bSRichard Henderson 
1408212c328dSRichard Henderson         case INDEX_op_add2_i32:
1409212c328dSRichard Henderson         case INDEX_op_sub2_i32:
14106349039dSRichard Henderson             if (arg_is_const(op->args[2]) && arg_is_const(op->args[3])
14116349039dSRichard Henderson                 && arg_is_const(op->args[4]) && arg_is_const(op->args[5])) {
14126349039dSRichard Henderson                 uint32_t al = arg_info(op->args[2])->val;
14136349039dSRichard Henderson                 uint32_t ah = arg_info(op->args[3])->val;
14146349039dSRichard Henderson                 uint32_t bl = arg_info(op->args[4])->val;
14156349039dSRichard Henderson                 uint32_t bh = arg_info(op->args[5])->val;
1416212c328dSRichard Henderson                 uint64_t a = ((uint64_t)ah << 32) | al;
1417212c328dSRichard Henderson                 uint64_t b = ((uint64_t)bh << 32) | bl;
1418212c328dSRichard Henderson                 TCGArg rl, rh;
14198fe35e04SRichard Henderson                 TCGOp *op2 = tcg_op_insert_before(s, op, INDEX_op_mov_i32);
1420212c328dSRichard Henderson 
1421c45cb8bbSRichard Henderson                 if (opc == INDEX_op_add2_i32) {
1422212c328dSRichard Henderson                     a += b;
1423212c328dSRichard Henderson                 } else {
1424212c328dSRichard Henderson                     a -= b;
1425212c328dSRichard Henderson                 }
1426212c328dSRichard Henderson 
1427acd93701SRichard Henderson                 rl = op->args[0];
1428acd93701SRichard Henderson                 rh = op->args[1];
1429dc84988aSRichard Henderson                 tcg_opt_gen_movi(&ctx, op, rl, (int32_t)a);
1430dc84988aSRichard Henderson                 tcg_opt_gen_movi(&ctx, op2, rh, (int32_t)(a >> 32));
1431b10f3833SRichard Henderson                 continue;
1432212c328dSRichard Henderson             }
1433b10f3833SRichard Henderson             break;
1434212c328dSRichard Henderson 
14351414968aSRichard Henderson         case INDEX_op_mulu2_i32:
14366349039dSRichard Henderson             if (arg_is_const(op->args[2]) && arg_is_const(op->args[3])) {
14376349039dSRichard Henderson                 uint32_t a = arg_info(op->args[2])->val;
14386349039dSRichard Henderson                 uint32_t b = arg_info(op->args[3])->val;
14391414968aSRichard Henderson                 uint64_t r = (uint64_t)a * b;
14401414968aSRichard Henderson                 TCGArg rl, rh;
14418fe35e04SRichard Henderson                 TCGOp *op2 = tcg_op_insert_before(s, op, INDEX_op_mov_i32);
14421414968aSRichard Henderson 
1443acd93701SRichard Henderson                 rl = op->args[0];
1444acd93701SRichard Henderson                 rh = op->args[1];
1445dc84988aSRichard Henderson                 tcg_opt_gen_movi(&ctx, op, rl, (int32_t)r);
1446dc84988aSRichard Henderson                 tcg_opt_gen_movi(&ctx, op2, rh, (int32_t)(r >> 32));
1447b10f3833SRichard Henderson                 continue;
14481414968aSRichard Henderson             }
1449b10f3833SRichard Henderson             break;
14501414968aSRichard Henderson 
1451bc1473efSRichard Henderson         case INDEX_op_brcond2_i32:
14528d57bf1eSRichard Henderson             i = do_constant_folding_cond2(&op->args[0], &op->args[2],
1453acd93701SRichard Henderson                                           op->args[4]);
14548d57bf1eSRichard Henderson             if (i == 0) {
1455a763551aSRichard Henderson             do_brcond_false:
14560c627cdcSRichard Henderson                 tcg_op_remove(s, op);
1457b10f3833SRichard Henderson                 continue;
14586c4382f8SRichard Henderson             }
14598d57bf1eSRichard Henderson             if (i > 0) {
1460b10f3833SRichard Henderson             do_brcond_true:
1461b10f3833SRichard Henderson                 op->opc = opc = INDEX_op_br;
1462b10f3833SRichard Henderson                 op->args[0] = op->args[5];
1463b10f3833SRichard Henderson                 break;
1464b10f3833SRichard Henderson             }
1465b10f3833SRichard Henderson             if ((op->args[4] == TCG_COND_LT || op->args[4] == TCG_COND_GE)
14666349039dSRichard Henderson                  && arg_is_const(op->args[2])
14676349039dSRichard Henderson                  && arg_info(op->args[2])->val == 0
14686349039dSRichard Henderson                  && arg_is_const(op->args[3])
14696349039dSRichard Henderson                  && arg_info(op->args[3])->val == 0) {
14706c4382f8SRichard Henderson                 /* Simplify LT/GE comparisons vs zero to a single compare
14716c4382f8SRichard Henderson                    vs the high word of the input.  */
1472a763551aSRichard Henderson             do_brcond_high:
1473b10f3833SRichard Henderson                 op->opc = opc = INDEX_op_brcond_i32;
1474acd93701SRichard Henderson                 op->args[0] = op->args[1];
1475acd93701SRichard Henderson                 op->args[1] = op->args[3];
1476acd93701SRichard Henderson                 op->args[2] = op->args[4];
1477acd93701SRichard Henderson                 op->args[3] = op->args[5];
1478b10f3833SRichard Henderson                 break;
1479b10f3833SRichard Henderson             }
1480b10f3833SRichard Henderson             if (op->args[4] == TCG_COND_EQ) {
1481a763551aSRichard Henderson                 /* Simplify EQ comparisons where one of the pairs
1482a763551aSRichard Henderson                    can be simplified.  */
14838d57bf1eSRichard Henderson                 i = do_constant_folding_cond(INDEX_op_brcond_i32,
1484acd93701SRichard Henderson                                              op->args[0], op->args[2],
1485acd93701SRichard Henderson                                              TCG_COND_EQ);
14868d57bf1eSRichard Henderson                 if (i == 0) {
1487a763551aSRichard Henderson                     goto do_brcond_false;
14888d57bf1eSRichard Henderson                 } else if (i > 0) {
1489a763551aSRichard Henderson                     goto do_brcond_high;
1490a763551aSRichard Henderson                 }
14918d57bf1eSRichard Henderson                 i = do_constant_folding_cond(INDEX_op_brcond_i32,
1492acd93701SRichard Henderson                                              op->args[1], op->args[3],
1493acd93701SRichard Henderson                                              TCG_COND_EQ);
14948d57bf1eSRichard Henderson                 if (i == 0) {
1495a763551aSRichard Henderson                     goto do_brcond_false;
14968d57bf1eSRichard Henderson                 } else if (i < 0) {
1497b10f3833SRichard Henderson                     break;
1498a763551aSRichard Henderson                 }
1499a763551aSRichard Henderson             do_brcond_low:
15003b3f847dSRichard Henderson                 memset(&ctx.temps_used, 0, sizeof(ctx.temps_used));
1501c45cb8bbSRichard Henderson                 op->opc = INDEX_op_brcond_i32;
1502acd93701SRichard Henderson                 op->args[1] = op->args[2];
1503acd93701SRichard Henderson                 op->args[2] = op->args[4];
1504acd93701SRichard Henderson                 op->args[3] = op->args[5];
1505b10f3833SRichard Henderson                 break;
1506b10f3833SRichard Henderson             }
1507b10f3833SRichard Henderson             if (op->args[4] == TCG_COND_NE) {
1508a763551aSRichard Henderson                 /* Simplify NE comparisons where one of the pairs
1509a763551aSRichard Henderson                    can be simplified.  */
15108d57bf1eSRichard Henderson                 i = do_constant_folding_cond(INDEX_op_brcond_i32,
1511acd93701SRichard Henderson                                              op->args[0], op->args[2],
1512acd93701SRichard Henderson                                              TCG_COND_NE);
15138d57bf1eSRichard Henderson                 if (i == 0) {
1514a763551aSRichard Henderson                     goto do_brcond_high;
15158d57bf1eSRichard Henderson                 } else if (i > 0) {
1516a763551aSRichard Henderson                     goto do_brcond_true;
1517a763551aSRichard Henderson                 }
15188d57bf1eSRichard Henderson                 i = do_constant_folding_cond(INDEX_op_brcond_i32,
1519acd93701SRichard Henderson                                              op->args[1], op->args[3],
1520acd93701SRichard Henderson                                              TCG_COND_NE);
15218d57bf1eSRichard Henderson                 if (i == 0) {
1522a763551aSRichard Henderson                     goto do_brcond_low;
15238d57bf1eSRichard Henderson                 } else if (i > 0) {
1524a763551aSRichard Henderson                     goto do_brcond_true;
1525a763551aSRichard Henderson                 }
15266c4382f8SRichard Henderson             }
15276c4382f8SRichard Henderson             break;
1528bc1473efSRichard Henderson 
1529bc1473efSRichard Henderson         case INDEX_op_setcond2_i32:
15308d57bf1eSRichard Henderson             i = do_constant_folding_cond2(&op->args[1], &op->args[3],
1531acd93701SRichard Henderson                                           op->args[5]);
15328d57bf1eSRichard Henderson             if (i >= 0) {
1533a763551aSRichard Henderson             do_setcond_const:
15348d57bf1eSRichard Henderson                 tcg_opt_gen_movi(&ctx, op, op->args[0], i);
1535b10f3833SRichard Henderson                 continue;
1536b10f3833SRichard Henderson             }
1537b10f3833SRichard Henderson             if ((op->args[5] == TCG_COND_LT || op->args[5] == TCG_COND_GE)
15386349039dSRichard Henderson                  && arg_is_const(op->args[3])
15396349039dSRichard Henderson                  && arg_info(op->args[3])->val == 0
15406349039dSRichard Henderson                  && arg_is_const(op->args[4])
15416349039dSRichard Henderson                  && arg_info(op->args[4])->val == 0) {
15426c4382f8SRichard Henderson                 /* Simplify LT/GE comparisons vs zero to a single compare
15436c4382f8SRichard Henderson                    vs the high word of the input.  */
1544a763551aSRichard Henderson             do_setcond_high:
1545acd93701SRichard Henderson                 reset_temp(op->args[0]);
1546b1fde411SRichard Henderson                 arg_info(op->args[0])->z_mask = 1;
1547c45cb8bbSRichard Henderson                 op->opc = INDEX_op_setcond_i32;
1548acd93701SRichard Henderson                 op->args[1] = op->args[2];
1549acd93701SRichard Henderson                 op->args[2] = op->args[4];
1550acd93701SRichard Henderson                 op->args[3] = op->args[5];
1551b10f3833SRichard Henderson                 break;
1552b10f3833SRichard Henderson             }
1553b10f3833SRichard Henderson             if (op->args[5] == TCG_COND_EQ) {
1554a763551aSRichard Henderson                 /* Simplify EQ comparisons where one of the pairs
1555a763551aSRichard Henderson                    can be simplified.  */
15568d57bf1eSRichard Henderson                 i = do_constant_folding_cond(INDEX_op_setcond_i32,
1557acd93701SRichard Henderson                                              op->args[1], op->args[3],
1558acd93701SRichard Henderson                                              TCG_COND_EQ);
15598d57bf1eSRichard Henderson                 if (i == 0) {
1560a763551aSRichard Henderson                     goto do_setcond_const;
15618d57bf1eSRichard Henderson                 } else if (i > 0) {
1562a763551aSRichard Henderson                     goto do_setcond_high;
1563a763551aSRichard Henderson                 }
15648d57bf1eSRichard Henderson                 i = do_constant_folding_cond(INDEX_op_setcond_i32,
1565acd93701SRichard Henderson                                              op->args[2], op->args[4],
1566acd93701SRichard Henderson                                              TCG_COND_EQ);
15678d57bf1eSRichard Henderson                 if (i == 0) {
1568a763551aSRichard Henderson                     goto do_setcond_high;
15698d57bf1eSRichard Henderson                 } else if (i < 0) {
1570b10f3833SRichard Henderson                     break;
1571a763551aSRichard Henderson                 }
1572a763551aSRichard Henderson             do_setcond_low:
1573acd93701SRichard Henderson                 reset_temp(op->args[0]);
1574b1fde411SRichard Henderson                 arg_info(op->args[0])->z_mask = 1;
1575c45cb8bbSRichard Henderson                 op->opc = INDEX_op_setcond_i32;
1576acd93701SRichard Henderson                 op->args[2] = op->args[3];
1577acd93701SRichard Henderson                 op->args[3] = op->args[5];
1578b10f3833SRichard Henderson                 break;
1579b10f3833SRichard Henderson             }
1580b10f3833SRichard Henderson             if (op->args[5] == TCG_COND_NE) {
1581a763551aSRichard Henderson                 /* Simplify NE comparisons where one of the pairs
1582a763551aSRichard Henderson                    can be simplified.  */
15838d57bf1eSRichard Henderson                 i = do_constant_folding_cond(INDEX_op_setcond_i32,
1584acd93701SRichard Henderson                                              op->args[1], op->args[3],
1585acd93701SRichard Henderson                                              TCG_COND_NE);
15868d57bf1eSRichard Henderson                 if (i == 0) {
1587a763551aSRichard Henderson                     goto do_setcond_high;
15888d57bf1eSRichard Henderson                 } else if (i > 0) {
1589a763551aSRichard Henderson                     goto do_setcond_const;
1590a763551aSRichard Henderson                 }
15918d57bf1eSRichard Henderson                 i = do_constant_folding_cond(INDEX_op_setcond_i32,
1592acd93701SRichard Henderson                                              op->args[2], op->args[4],
1593acd93701SRichard Henderson                                              TCG_COND_NE);
15948d57bf1eSRichard Henderson                 if (i == 0) {
1595a763551aSRichard Henderson                     goto do_setcond_low;
15968d57bf1eSRichard Henderson                 } else if (i > 0) {
1597a763551aSRichard Henderson                     goto do_setcond_const;
1598a763551aSRichard Henderson                 }
15996c4382f8SRichard Henderson             }
1600bc1473efSRichard Henderson             break;
1601bc1473efSRichard Henderson 
1602b10f3833SRichard Henderson         default:
1603b10f3833SRichard Henderson             break;
1604b10f3833SRichard Henderson         }
1605b10f3833SRichard Henderson 
1606*404a148dSRichard Henderson         if (!done) {
1607137f1f44SRichard Henderson             finish_folding(&ctx, op);
1608*404a148dSRichard Henderson         }
160934f93921SPranith Kumar 
161034f93921SPranith Kumar         /* Eliminate duplicate and redundant fence instructions.  */
1611d0ed5151SRichard Henderson         if (ctx.prev_mb) {
161234f93921SPranith Kumar             switch (opc) {
161334f93921SPranith Kumar             case INDEX_op_mb:
161434f93921SPranith Kumar                 /* Merge two barriers of the same type into one,
161534f93921SPranith Kumar                  * or a weaker barrier into a stronger one,
161634f93921SPranith Kumar                  * or two weaker barriers into a stronger one.
161734f93921SPranith Kumar                  *   mb X; mb Y => mb X|Y
161834f93921SPranith Kumar                  *   mb; strl => mb; st
161934f93921SPranith Kumar                  *   ldaq; mb => ld; mb
162034f93921SPranith Kumar                  *   ldaq; strl => ld; mb; st
162134f93921SPranith Kumar                  * Other combinations are also merged into a strong
162234f93921SPranith Kumar                  * barrier.  This is stricter than specified but for
162334f93921SPranith Kumar                  * the purposes of TCG is better than not optimizing.
162434f93921SPranith Kumar                  */
1625d0ed5151SRichard Henderson                 ctx.prev_mb->args[0] |= op->args[0];
162634f93921SPranith Kumar                 tcg_op_remove(s, op);
162734f93921SPranith Kumar                 break;
162834f93921SPranith Kumar 
162934f93921SPranith Kumar             default:
163034f93921SPranith Kumar                 /* Opcodes that end the block stop the optimization.  */
163134f93921SPranith Kumar                 if ((def->flags & TCG_OPF_BB_END) == 0) {
163234f93921SPranith Kumar                     break;
163334f93921SPranith Kumar                 }
163434f93921SPranith Kumar                 /* fallthru */
163534f93921SPranith Kumar             case INDEX_op_qemu_ld_i32:
163634f93921SPranith Kumar             case INDEX_op_qemu_ld_i64:
163734f93921SPranith Kumar             case INDEX_op_qemu_st_i32:
163807ce0b05SRichard Henderson             case INDEX_op_qemu_st8_i32:
163934f93921SPranith Kumar             case INDEX_op_qemu_st_i64:
164034f93921SPranith Kumar                 /* Opcodes that touch guest memory stop the optimization.  */
1641d0ed5151SRichard Henderson                 ctx.prev_mb = NULL;
164234f93921SPranith Kumar                 break;
164334f93921SPranith Kumar             }
164434f93921SPranith Kumar         } else if (opc == INDEX_op_mb) {
1645d0ed5151SRichard Henderson             ctx.prev_mb = op;
164634f93921SPranith Kumar         }
16478f2e8c07SKirill Batuzov     }
16488f2e8c07SKirill Batuzov }
1649