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