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 268f2e8c07SKirill Batuzov #include "config.h" 278f2e8c07SKirill Batuzov 288f2e8c07SKirill Batuzov #include <stdlib.h> 298f2e8c07SKirill Batuzov #include <stdio.h> 308f2e8c07SKirill Batuzov 318f2e8c07SKirill Batuzov #include "qemu-common.h" 328f2e8c07SKirill Batuzov #include "tcg-op.h" 338f2e8c07SKirill Batuzov 348f2e8c07SKirill Batuzov #define CASE_OP_32_64(x) \ 358f2e8c07SKirill Batuzov glue(glue(case INDEX_op_, x), _i32): \ 368f2e8c07SKirill Batuzov glue(glue(case INDEX_op_, x), _i64) 378f2e8c07SKirill Batuzov 3822613af4SKirill Batuzov typedef enum { 3922613af4SKirill Batuzov TCG_TEMP_UNDEF = 0, 4022613af4SKirill Batuzov TCG_TEMP_CONST, 4122613af4SKirill Batuzov TCG_TEMP_COPY, 4222613af4SKirill Batuzov } tcg_temp_state; 4322613af4SKirill Batuzov 4422613af4SKirill Batuzov struct tcg_temp_info { 4522613af4SKirill Batuzov tcg_temp_state state; 4622613af4SKirill Batuzov uint16_t prev_copy; 4722613af4SKirill Batuzov uint16_t next_copy; 4822613af4SKirill Batuzov tcg_target_ulong val; 493a9d8b17SPaolo Bonzini tcg_target_ulong mask; 5022613af4SKirill Batuzov }; 5122613af4SKirill Batuzov 5222613af4SKirill Batuzov static struct tcg_temp_info temps[TCG_MAX_TEMPS]; 5322613af4SKirill Batuzov 54e590d4e6SAurelien Jarno /* Reset TEMP's state to TCG_TEMP_UNDEF. If TEMP only had one copy, remove 55e590d4e6SAurelien Jarno the copy flag from the left temp. */ 56e590d4e6SAurelien Jarno static void reset_temp(TCGArg temp) 5722613af4SKirill Batuzov { 58e590d4e6SAurelien Jarno if (temps[temp].state == TCG_TEMP_COPY) { 59e590d4e6SAurelien Jarno if (temps[temp].prev_copy == temps[temp].next_copy) { 60e590d4e6SAurelien Jarno temps[temps[temp].next_copy].state = TCG_TEMP_UNDEF; 6122613af4SKirill Batuzov } else { 6222613af4SKirill Batuzov temps[temps[temp].next_copy].prev_copy = temps[temp].prev_copy; 6322613af4SKirill Batuzov temps[temps[temp].prev_copy].next_copy = temps[temp].next_copy; 64e590d4e6SAurelien Jarno } 6522613af4SKirill Batuzov } 6648b56ce1SAurelien Jarno temps[temp].state = TCG_TEMP_UNDEF; 673a9d8b17SPaolo Bonzini temps[temp].mask = -1; 6822613af4SKirill Batuzov } 6922613af4SKirill Batuzov 70d193a14aSPaolo Bonzini /* Reset all temporaries, given that there are NB_TEMPS of them. */ 71d193a14aSPaolo Bonzini static void reset_all_temps(int nb_temps) 72d193a14aSPaolo Bonzini { 73d193a14aSPaolo Bonzini int i; 74d193a14aSPaolo Bonzini for (i = 0; i < nb_temps; i++) { 75d193a14aSPaolo Bonzini temps[i].state = TCG_TEMP_UNDEF; 763a9d8b17SPaolo Bonzini temps[i].mask = -1; 77d193a14aSPaolo Bonzini } 78d193a14aSPaolo Bonzini } 79d193a14aSPaolo Bonzini 80fe0de7aaSBlue Swirl static int op_bits(TCGOpcode op) 8122613af4SKirill Batuzov { 828399ad59SRichard Henderson const TCGOpDef *def = &tcg_op_defs[op]; 838399ad59SRichard Henderson return def->flags & TCG_OPF_64BIT ? 64 : 32; 8422613af4SKirill Batuzov } 8522613af4SKirill Batuzov 86fe0de7aaSBlue Swirl static TCGOpcode op_to_movi(TCGOpcode op) 8722613af4SKirill Batuzov { 8822613af4SKirill Batuzov switch (op_bits(op)) { 8922613af4SKirill Batuzov case 32: 9022613af4SKirill Batuzov return INDEX_op_movi_i32; 9122613af4SKirill Batuzov case 64: 9222613af4SKirill Batuzov return INDEX_op_movi_i64; 9322613af4SKirill Batuzov default: 9422613af4SKirill Batuzov fprintf(stderr, "op_to_movi: unexpected return value of " 9522613af4SKirill Batuzov "function op_bits.\n"); 9622613af4SKirill Batuzov tcg_abort(); 9722613af4SKirill Batuzov } 9822613af4SKirill Batuzov } 9922613af4SKirill Batuzov 100e590d4e6SAurelien Jarno static TCGArg find_better_copy(TCGContext *s, TCGArg temp) 101e590d4e6SAurelien Jarno { 102e590d4e6SAurelien Jarno TCGArg i; 103e590d4e6SAurelien Jarno 104e590d4e6SAurelien Jarno /* If this is already a global, we can't do better. */ 105e590d4e6SAurelien Jarno if (temp < s->nb_globals) { 106e590d4e6SAurelien Jarno return temp; 107e590d4e6SAurelien Jarno } 108e590d4e6SAurelien Jarno 109e590d4e6SAurelien Jarno /* Search for a global first. */ 110e590d4e6SAurelien Jarno for (i = temps[temp].next_copy ; i != temp ; i = temps[i].next_copy) { 111e590d4e6SAurelien Jarno if (i < s->nb_globals) { 112e590d4e6SAurelien Jarno return i; 113e590d4e6SAurelien Jarno } 114e590d4e6SAurelien Jarno } 115e590d4e6SAurelien Jarno 116e590d4e6SAurelien Jarno /* If it is a temp, search for a temp local. */ 117e590d4e6SAurelien Jarno if (!s->temps[temp].temp_local) { 118e590d4e6SAurelien Jarno for (i = temps[temp].next_copy ; i != temp ; i = temps[i].next_copy) { 119e590d4e6SAurelien Jarno if (s->temps[i].temp_local) { 120e590d4e6SAurelien Jarno return i; 121e590d4e6SAurelien Jarno } 122e590d4e6SAurelien Jarno } 123e590d4e6SAurelien Jarno } 124e590d4e6SAurelien Jarno 125e590d4e6SAurelien Jarno /* Failure to find a better representation, return the same temp. */ 126e590d4e6SAurelien Jarno return temp; 127e590d4e6SAurelien Jarno } 128e590d4e6SAurelien Jarno 129e590d4e6SAurelien Jarno static bool temps_are_copies(TCGArg arg1, TCGArg arg2) 130e590d4e6SAurelien Jarno { 131e590d4e6SAurelien Jarno TCGArg i; 132e590d4e6SAurelien Jarno 133e590d4e6SAurelien Jarno if (arg1 == arg2) { 134e590d4e6SAurelien Jarno return true; 135e590d4e6SAurelien Jarno } 136e590d4e6SAurelien Jarno 137e590d4e6SAurelien Jarno if (temps[arg1].state != TCG_TEMP_COPY 138e590d4e6SAurelien Jarno || temps[arg2].state != TCG_TEMP_COPY) { 139e590d4e6SAurelien Jarno return false; 140e590d4e6SAurelien Jarno } 141e590d4e6SAurelien Jarno 142e590d4e6SAurelien Jarno for (i = temps[arg1].next_copy ; i != arg1 ; i = temps[i].next_copy) { 143e590d4e6SAurelien Jarno if (i == arg2) { 144e590d4e6SAurelien Jarno return true; 145e590d4e6SAurelien Jarno } 146e590d4e6SAurelien Jarno } 147e590d4e6SAurelien Jarno 148e590d4e6SAurelien Jarno return false; 149e590d4e6SAurelien Jarno } 150e590d4e6SAurelien Jarno 151b80bb016SAurelien Jarno static void tcg_opt_gen_mov(TCGContext *s, TCGArg *gen_args, 152b80bb016SAurelien Jarno TCGArg dst, TCGArg src) 15322613af4SKirill Batuzov { 154e590d4e6SAurelien Jarno reset_temp(dst); 1553a9d8b17SPaolo Bonzini temps[dst].mask = temps[src].mask; 15622613af4SKirill Batuzov assert(temps[src].state != TCG_TEMP_CONST); 157e590d4e6SAurelien Jarno 158e590d4e6SAurelien Jarno if (s->temps[src].type == s->temps[dst].type) { 159e590d4e6SAurelien Jarno if (temps[src].state != TCG_TEMP_COPY) { 160e590d4e6SAurelien Jarno temps[src].state = TCG_TEMP_COPY; 16122613af4SKirill Batuzov temps[src].next_copy = src; 16222613af4SKirill Batuzov temps[src].prev_copy = src; 16322613af4SKirill Batuzov } 16422613af4SKirill Batuzov temps[dst].state = TCG_TEMP_COPY; 16522613af4SKirill Batuzov temps[dst].next_copy = temps[src].next_copy; 16622613af4SKirill Batuzov temps[dst].prev_copy = src; 16722613af4SKirill Batuzov temps[temps[dst].next_copy].prev_copy = dst; 16822613af4SKirill Batuzov temps[src].next_copy = dst; 16922613af4SKirill Batuzov } 170e590d4e6SAurelien Jarno 17122613af4SKirill Batuzov gen_args[0] = dst; 17222613af4SKirill Batuzov gen_args[1] = src; 17322613af4SKirill Batuzov } 17422613af4SKirill Batuzov 175e590d4e6SAurelien Jarno static void tcg_opt_gen_movi(TCGArg *gen_args, TCGArg dst, TCGArg val) 17622613af4SKirill Batuzov { 177e590d4e6SAurelien Jarno reset_temp(dst); 17822613af4SKirill Batuzov temps[dst].state = TCG_TEMP_CONST; 17922613af4SKirill Batuzov temps[dst].val = val; 1803a9d8b17SPaolo Bonzini temps[dst].mask = val; 18122613af4SKirill Batuzov gen_args[0] = dst; 18222613af4SKirill Batuzov gen_args[1] = val; 18322613af4SKirill Batuzov } 18422613af4SKirill Batuzov 185fe0de7aaSBlue Swirl static TCGOpcode op_to_mov(TCGOpcode op) 18653108fb5SKirill Batuzov { 18753108fb5SKirill Batuzov switch (op_bits(op)) { 18853108fb5SKirill Batuzov case 32: 18953108fb5SKirill Batuzov return INDEX_op_mov_i32; 19053108fb5SKirill Batuzov case 64: 19153108fb5SKirill Batuzov return INDEX_op_mov_i64; 19253108fb5SKirill Batuzov default: 19353108fb5SKirill Batuzov fprintf(stderr, "op_to_mov: unexpected return value of " 19453108fb5SKirill Batuzov "function op_bits.\n"); 19553108fb5SKirill Batuzov tcg_abort(); 19653108fb5SKirill Batuzov } 19753108fb5SKirill Batuzov } 19853108fb5SKirill Batuzov 199fe0de7aaSBlue Swirl static TCGArg do_constant_folding_2(TCGOpcode op, TCGArg x, TCGArg y) 20053108fb5SKirill Batuzov { 20103271524SRichard Henderson uint64_t l64, h64; 20203271524SRichard Henderson 20353108fb5SKirill Batuzov switch (op) { 20453108fb5SKirill Batuzov CASE_OP_32_64(add): 20553108fb5SKirill Batuzov return x + y; 20653108fb5SKirill Batuzov 20753108fb5SKirill Batuzov CASE_OP_32_64(sub): 20853108fb5SKirill Batuzov return x - y; 20953108fb5SKirill Batuzov 21053108fb5SKirill Batuzov CASE_OP_32_64(mul): 21153108fb5SKirill Batuzov return x * y; 21253108fb5SKirill Batuzov 2139a81090bSKirill Batuzov CASE_OP_32_64(and): 2149a81090bSKirill Batuzov return x & y; 2159a81090bSKirill Batuzov 2169a81090bSKirill Batuzov CASE_OP_32_64(or): 2179a81090bSKirill Batuzov return x | y; 2189a81090bSKirill Batuzov 2199a81090bSKirill Batuzov CASE_OP_32_64(xor): 2209a81090bSKirill Batuzov return x ^ y; 2219a81090bSKirill Batuzov 22255c0975cSKirill Batuzov case INDEX_op_shl_i32: 22350c5c4d1SRichard Henderson return (uint32_t)x << (y & 31); 22455c0975cSKirill Batuzov 22555c0975cSKirill Batuzov case INDEX_op_shl_i64: 22650c5c4d1SRichard Henderson return (uint64_t)x << (y & 63); 22755c0975cSKirill Batuzov 22855c0975cSKirill Batuzov case INDEX_op_shr_i32: 22950c5c4d1SRichard Henderson return (uint32_t)x >> (y & 31); 23055c0975cSKirill Batuzov 2314bb7a41eSRichard Henderson case INDEX_op_trunc_shr_i32: 23255c0975cSKirill Batuzov case INDEX_op_shr_i64: 23350c5c4d1SRichard Henderson return (uint64_t)x >> (y & 63); 23455c0975cSKirill Batuzov 23555c0975cSKirill Batuzov case INDEX_op_sar_i32: 23650c5c4d1SRichard Henderson return (int32_t)x >> (y & 31); 23755c0975cSKirill Batuzov 23855c0975cSKirill Batuzov case INDEX_op_sar_i64: 23950c5c4d1SRichard Henderson return (int64_t)x >> (y & 63); 24055c0975cSKirill Batuzov 24155c0975cSKirill Batuzov case INDEX_op_rotr_i32: 24250c5c4d1SRichard Henderson return ror32(x, y & 31); 24355c0975cSKirill Batuzov 24455c0975cSKirill Batuzov case INDEX_op_rotr_i64: 24550c5c4d1SRichard Henderson return ror64(x, y & 63); 24655c0975cSKirill Batuzov 24755c0975cSKirill Batuzov case INDEX_op_rotl_i32: 24850c5c4d1SRichard Henderson return rol32(x, y & 31); 24955c0975cSKirill Batuzov 25055c0975cSKirill Batuzov case INDEX_op_rotl_i64: 25150c5c4d1SRichard Henderson return rol64(x, y & 63); 25255c0975cSKirill Batuzov 25325c4d9ccSRichard Henderson CASE_OP_32_64(not): 254a640f031SKirill Batuzov return ~x; 255a640f031SKirill Batuzov 256cb25c80aSRichard Henderson CASE_OP_32_64(neg): 257cb25c80aSRichard Henderson return -x; 258cb25c80aSRichard Henderson 259cb25c80aSRichard Henderson CASE_OP_32_64(andc): 260cb25c80aSRichard Henderson return x & ~y; 261cb25c80aSRichard Henderson 262cb25c80aSRichard Henderson CASE_OP_32_64(orc): 263cb25c80aSRichard Henderson return x | ~y; 264cb25c80aSRichard Henderson 265cb25c80aSRichard Henderson CASE_OP_32_64(eqv): 266cb25c80aSRichard Henderson return ~(x ^ y); 267cb25c80aSRichard Henderson 268cb25c80aSRichard Henderson CASE_OP_32_64(nand): 269cb25c80aSRichard Henderson return ~(x & y); 270cb25c80aSRichard Henderson 271cb25c80aSRichard Henderson CASE_OP_32_64(nor): 272cb25c80aSRichard Henderson return ~(x | y); 273cb25c80aSRichard Henderson 27425c4d9ccSRichard Henderson CASE_OP_32_64(ext8s): 275a640f031SKirill Batuzov return (int8_t)x; 276a640f031SKirill Batuzov 27725c4d9ccSRichard Henderson CASE_OP_32_64(ext16s): 278a640f031SKirill Batuzov return (int16_t)x; 279a640f031SKirill Batuzov 28025c4d9ccSRichard Henderson CASE_OP_32_64(ext8u): 281a640f031SKirill Batuzov return (uint8_t)x; 282a640f031SKirill Batuzov 28325c4d9ccSRichard Henderson CASE_OP_32_64(ext16u): 284a640f031SKirill Batuzov return (uint16_t)x; 285a640f031SKirill Batuzov 286a640f031SKirill Batuzov case INDEX_op_ext32s_i64: 287a640f031SKirill Batuzov return (int32_t)x; 288a640f031SKirill Batuzov 289a640f031SKirill Batuzov case INDEX_op_ext32u_i64: 290a640f031SKirill Batuzov return (uint32_t)x; 291a640f031SKirill Batuzov 29203271524SRichard Henderson case INDEX_op_muluh_i32: 29303271524SRichard Henderson return ((uint64_t)(uint32_t)x * (uint32_t)y) >> 32; 29403271524SRichard Henderson case INDEX_op_mulsh_i32: 29503271524SRichard Henderson return ((int64_t)(int32_t)x * (int32_t)y) >> 32; 29603271524SRichard Henderson 29703271524SRichard Henderson case INDEX_op_muluh_i64: 29803271524SRichard Henderson mulu64(&l64, &h64, x, y); 29903271524SRichard Henderson return h64; 30003271524SRichard Henderson case INDEX_op_mulsh_i64: 30103271524SRichard Henderson muls64(&l64, &h64, x, y); 30203271524SRichard Henderson return h64; 30303271524SRichard Henderson 30401547f7fSRichard Henderson case INDEX_op_div_i32: 30501547f7fSRichard Henderson /* Avoid crashing on divide by zero, otherwise undefined. */ 30601547f7fSRichard Henderson return (int32_t)x / ((int32_t)y ? : 1); 30701547f7fSRichard Henderson case INDEX_op_divu_i32: 30801547f7fSRichard Henderson return (uint32_t)x / ((uint32_t)y ? : 1); 30901547f7fSRichard Henderson case INDEX_op_div_i64: 31001547f7fSRichard Henderson return (int64_t)x / ((int64_t)y ? : 1); 31101547f7fSRichard Henderson case INDEX_op_divu_i64: 31201547f7fSRichard Henderson return (uint64_t)x / ((uint64_t)y ? : 1); 31301547f7fSRichard Henderson 31401547f7fSRichard Henderson case INDEX_op_rem_i32: 31501547f7fSRichard Henderson return (int32_t)x % ((int32_t)y ? : 1); 31601547f7fSRichard Henderson case INDEX_op_remu_i32: 31701547f7fSRichard Henderson return (uint32_t)x % ((uint32_t)y ? : 1); 31801547f7fSRichard Henderson case INDEX_op_rem_i64: 31901547f7fSRichard Henderson return (int64_t)x % ((int64_t)y ? : 1); 32001547f7fSRichard Henderson case INDEX_op_remu_i64: 32101547f7fSRichard Henderson return (uint64_t)x % ((uint64_t)y ? : 1); 32201547f7fSRichard Henderson 32353108fb5SKirill Batuzov default: 32453108fb5SKirill Batuzov fprintf(stderr, 32553108fb5SKirill Batuzov "Unrecognized operation %d in do_constant_folding.\n", op); 32653108fb5SKirill Batuzov tcg_abort(); 32753108fb5SKirill Batuzov } 32853108fb5SKirill Batuzov } 32953108fb5SKirill Batuzov 330fe0de7aaSBlue Swirl static TCGArg do_constant_folding(TCGOpcode op, TCGArg x, TCGArg y) 33153108fb5SKirill Batuzov { 33253108fb5SKirill Batuzov TCGArg res = do_constant_folding_2(op, x, y); 33353108fb5SKirill Batuzov if (op_bits(op) == 32) { 33453108fb5SKirill Batuzov res &= 0xffffffff; 33553108fb5SKirill Batuzov } 33653108fb5SKirill Batuzov return res; 33753108fb5SKirill Batuzov } 33853108fb5SKirill Batuzov 3399519da7eSRichard Henderson static bool do_constant_folding_cond_32(uint32_t x, uint32_t y, TCGCond c) 340f8dd19e5SAurelien Jarno { 341f8dd19e5SAurelien Jarno switch (c) { 342f8dd19e5SAurelien Jarno case TCG_COND_EQ: 3439519da7eSRichard Henderson return x == y; 344f8dd19e5SAurelien Jarno case TCG_COND_NE: 3459519da7eSRichard Henderson return x != y; 346f8dd19e5SAurelien Jarno case TCG_COND_LT: 3479519da7eSRichard Henderson return (int32_t)x < (int32_t)y; 348f8dd19e5SAurelien Jarno case TCG_COND_GE: 3499519da7eSRichard Henderson return (int32_t)x >= (int32_t)y; 350f8dd19e5SAurelien Jarno case TCG_COND_LE: 3519519da7eSRichard Henderson return (int32_t)x <= (int32_t)y; 352f8dd19e5SAurelien Jarno case TCG_COND_GT: 3539519da7eSRichard Henderson return (int32_t)x > (int32_t)y; 354f8dd19e5SAurelien Jarno case TCG_COND_LTU: 3559519da7eSRichard Henderson return x < y; 356f8dd19e5SAurelien Jarno case TCG_COND_GEU: 3579519da7eSRichard Henderson return x >= y; 358f8dd19e5SAurelien Jarno case TCG_COND_LEU: 3599519da7eSRichard Henderson return x <= y; 360f8dd19e5SAurelien Jarno case TCG_COND_GTU: 3619519da7eSRichard Henderson return x > y; 3620aed257fSRichard Henderson default: 3639519da7eSRichard Henderson tcg_abort(); 364f8dd19e5SAurelien Jarno } 3659519da7eSRichard Henderson } 3669519da7eSRichard Henderson 3679519da7eSRichard Henderson static bool do_constant_folding_cond_64(uint64_t x, uint64_t y, TCGCond c) 3689519da7eSRichard Henderson { 369f8dd19e5SAurelien Jarno switch (c) { 370f8dd19e5SAurelien Jarno case TCG_COND_EQ: 3719519da7eSRichard Henderson return x == y; 372f8dd19e5SAurelien Jarno case TCG_COND_NE: 3739519da7eSRichard Henderson return x != y; 374f8dd19e5SAurelien Jarno case TCG_COND_LT: 3759519da7eSRichard Henderson return (int64_t)x < (int64_t)y; 376f8dd19e5SAurelien Jarno case TCG_COND_GE: 3779519da7eSRichard Henderson return (int64_t)x >= (int64_t)y; 378f8dd19e5SAurelien Jarno case TCG_COND_LE: 3799519da7eSRichard Henderson return (int64_t)x <= (int64_t)y; 380f8dd19e5SAurelien Jarno case TCG_COND_GT: 3819519da7eSRichard Henderson return (int64_t)x > (int64_t)y; 382f8dd19e5SAurelien Jarno case TCG_COND_LTU: 3839519da7eSRichard Henderson return x < y; 384f8dd19e5SAurelien Jarno case TCG_COND_GEU: 3859519da7eSRichard Henderson return x >= y; 386f8dd19e5SAurelien Jarno case TCG_COND_LEU: 3879519da7eSRichard Henderson return x <= y; 388f8dd19e5SAurelien Jarno case TCG_COND_GTU: 3899519da7eSRichard Henderson return x > y; 3900aed257fSRichard Henderson default: 3919519da7eSRichard Henderson tcg_abort(); 392f8dd19e5SAurelien Jarno } 393f8dd19e5SAurelien Jarno } 3949519da7eSRichard Henderson 3959519da7eSRichard Henderson static bool do_constant_folding_cond_eq(TCGCond c) 3969519da7eSRichard Henderson { 397b336ceb6SAurelien Jarno switch (c) { 398b336ceb6SAurelien Jarno case TCG_COND_GT: 399b336ceb6SAurelien Jarno case TCG_COND_LTU: 400b336ceb6SAurelien Jarno case TCG_COND_LT: 401b336ceb6SAurelien Jarno case TCG_COND_GTU: 402b336ceb6SAurelien Jarno case TCG_COND_NE: 403b336ceb6SAurelien Jarno return 0; 404b336ceb6SAurelien Jarno case TCG_COND_GE: 405b336ceb6SAurelien Jarno case TCG_COND_GEU: 406b336ceb6SAurelien Jarno case TCG_COND_LE: 407b336ceb6SAurelien Jarno case TCG_COND_LEU: 408b336ceb6SAurelien Jarno case TCG_COND_EQ: 409b336ceb6SAurelien Jarno return 1; 4100aed257fSRichard Henderson default: 4119519da7eSRichard Henderson tcg_abort(); 412b336ceb6SAurelien Jarno } 4139519da7eSRichard Henderson } 4149519da7eSRichard Henderson 4159519da7eSRichard Henderson /* Return 2 if the condition can't be simplified, and the result 4169519da7eSRichard Henderson of the condition (0 or 1) if it can */ 4179519da7eSRichard Henderson static TCGArg do_constant_folding_cond(TCGOpcode op, TCGArg x, 4189519da7eSRichard Henderson TCGArg y, TCGCond c) 4199519da7eSRichard Henderson { 4209519da7eSRichard Henderson if (temps[x].state == TCG_TEMP_CONST && temps[y].state == TCG_TEMP_CONST) { 4219519da7eSRichard Henderson switch (op_bits(op)) { 4229519da7eSRichard Henderson case 32: 4239519da7eSRichard Henderson return do_constant_folding_cond_32(temps[x].val, temps[y].val, c); 4249519da7eSRichard Henderson case 64: 4259519da7eSRichard Henderson return do_constant_folding_cond_64(temps[x].val, temps[y].val, c); 4269519da7eSRichard Henderson default: 4279519da7eSRichard Henderson tcg_abort(); 4289519da7eSRichard Henderson } 4299519da7eSRichard Henderson } else if (temps_are_copies(x, y)) { 4309519da7eSRichard Henderson return do_constant_folding_cond_eq(c); 431b336ceb6SAurelien Jarno } else if (temps[y].state == TCG_TEMP_CONST && temps[y].val == 0) { 432b336ceb6SAurelien Jarno switch (c) { 433b336ceb6SAurelien Jarno case TCG_COND_LTU: 434b336ceb6SAurelien Jarno return 0; 435b336ceb6SAurelien Jarno case TCG_COND_GEU: 436b336ceb6SAurelien Jarno return 1; 437b336ceb6SAurelien Jarno default: 438b336ceb6SAurelien Jarno return 2; 439b336ceb6SAurelien Jarno } 440b336ceb6SAurelien Jarno } else { 441b336ceb6SAurelien Jarno return 2; 442b336ceb6SAurelien Jarno } 443f8dd19e5SAurelien Jarno } 444f8dd19e5SAurelien Jarno 4456c4382f8SRichard Henderson /* Return 2 if the condition can't be simplified, and the result 4466c4382f8SRichard Henderson of the condition (0 or 1) if it can */ 4476c4382f8SRichard Henderson static TCGArg do_constant_folding_cond2(TCGArg *p1, TCGArg *p2, TCGCond c) 4486c4382f8SRichard Henderson { 4496c4382f8SRichard Henderson TCGArg al = p1[0], ah = p1[1]; 4506c4382f8SRichard Henderson TCGArg bl = p2[0], bh = p2[1]; 4516c4382f8SRichard Henderson 4526c4382f8SRichard Henderson if (temps[bl].state == TCG_TEMP_CONST 4536c4382f8SRichard Henderson && temps[bh].state == TCG_TEMP_CONST) { 4546c4382f8SRichard Henderson uint64_t b = ((uint64_t)temps[bh].val << 32) | (uint32_t)temps[bl].val; 4556c4382f8SRichard Henderson 4566c4382f8SRichard Henderson if (temps[al].state == TCG_TEMP_CONST 4576c4382f8SRichard Henderson && temps[ah].state == TCG_TEMP_CONST) { 4586c4382f8SRichard Henderson uint64_t a; 4596c4382f8SRichard Henderson a = ((uint64_t)temps[ah].val << 32) | (uint32_t)temps[al].val; 4606c4382f8SRichard Henderson return do_constant_folding_cond_64(a, b, c); 4616c4382f8SRichard Henderson } 4626c4382f8SRichard Henderson if (b == 0) { 4636c4382f8SRichard Henderson switch (c) { 4646c4382f8SRichard Henderson case TCG_COND_LTU: 4656c4382f8SRichard Henderson return 0; 4666c4382f8SRichard Henderson case TCG_COND_GEU: 4676c4382f8SRichard Henderson return 1; 4686c4382f8SRichard Henderson default: 4696c4382f8SRichard Henderson break; 4706c4382f8SRichard Henderson } 4716c4382f8SRichard Henderson } 4726c4382f8SRichard Henderson } 4736c4382f8SRichard Henderson if (temps_are_copies(al, bl) && temps_are_copies(ah, bh)) { 4746c4382f8SRichard Henderson return do_constant_folding_cond_eq(c); 4756c4382f8SRichard Henderson } 4766c4382f8SRichard Henderson return 2; 4776c4382f8SRichard Henderson } 4786c4382f8SRichard Henderson 47924c9ae4eSRichard Henderson static bool swap_commutative(TCGArg dest, TCGArg *p1, TCGArg *p2) 48024c9ae4eSRichard Henderson { 48124c9ae4eSRichard Henderson TCGArg a1 = *p1, a2 = *p2; 48224c9ae4eSRichard Henderson int sum = 0; 48324c9ae4eSRichard Henderson sum += temps[a1].state == TCG_TEMP_CONST; 48424c9ae4eSRichard Henderson sum -= temps[a2].state == TCG_TEMP_CONST; 48524c9ae4eSRichard Henderson 48624c9ae4eSRichard Henderson /* Prefer the constant in second argument, and then the form 48724c9ae4eSRichard Henderson op a, a, b, which is better handled on non-RISC hosts. */ 48824c9ae4eSRichard Henderson if (sum > 0 || (sum == 0 && dest == a2)) { 48924c9ae4eSRichard Henderson *p1 = a2; 49024c9ae4eSRichard Henderson *p2 = a1; 49124c9ae4eSRichard Henderson return true; 49224c9ae4eSRichard Henderson } 49324c9ae4eSRichard Henderson return false; 49424c9ae4eSRichard Henderson } 49524c9ae4eSRichard Henderson 4960bfcb865SRichard Henderson static bool swap_commutative2(TCGArg *p1, TCGArg *p2) 4970bfcb865SRichard Henderson { 4980bfcb865SRichard Henderson int sum = 0; 4990bfcb865SRichard Henderson sum += temps[p1[0]].state == TCG_TEMP_CONST; 5000bfcb865SRichard Henderson sum += temps[p1[1]].state == TCG_TEMP_CONST; 5010bfcb865SRichard Henderson sum -= temps[p2[0]].state == TCG_TEMP_CONST; 5020bfcb865SRichard Henderson sum -= temps[p2[1]].state == TCG_TEMP_CONST; 5030bfcb865SRichard Henderson if (sum > 0) { 5040bfcb865SRichard Henderson TCGArg t; 5050bfcb865SRichard Henderson t = p1[0], p1[0] = p2[0], p2[0] = t; 5060bfcb865SRichard Henderson t = p1[1], p1[1] = p2[1], p2[1] = t; 5070bfcb865SRichard Henderson return true; 5080bfcb865SRichard Henderson } 5090bfcb865SRichard Henderson return false; 5100bfcb865SRichard Henderson } 5110bfcb865SRichard Henderson 51222613af4SKirill Batuzov /* Propagate constants and copies, fold constant expressions. */ 5138f2e8c07SKirill Batuzov static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, 5148f2e8c07SKirill Batuzov TCGArg *args, TCGOpDef *tcg_op_defs) 5158f2e8c07SKirill Batuzov { 516*cf066674SRichard Henderson int nb_ops, op_index, nb_temps, nb_globals; 5178f2e8c07SKirill Batuzov TCGArg *gen_args; 5185d8f5363SRichard Henderson 51922613af4SKirill Batuzov /* Array VALS has an element for each temp. 52022613af4SKirill Batuzov If this temp holds a constant then its value is kept in VALS' element. 521e590d4e6SAurelien Jarno If this temp is a copy of other ones then the other copies are 522e590d4e6SAurelien Jarno available through the doubly linked circular list. */ 5238f2e8c07SKirill Batuzov 5248f2e8c07SKirill Batuzov nb_temps = s->nb_temps; 5258f2e8c07SKirill Batuzov nb_globals = s->nb_globals; 526d193a14aSPaolo Bonzini reset_all_temps(nb_temps); 5278f2e8c07SKirill Batuzov 52892414b31SEvgeny Voevodin nb_ops = tcg_opc_ptr - s->gen_opc_buf; 5298f2e8c07SKirill Batuzov gen_args = args; 5308f2e8c07SKirill Batuzov for (op_index = 0; op_index < nb_ops; op_index++) { 531*cf066674SRichard Henderson TCGOpcode op = s->gen_opc_buf[op_index]; 532*cf066674SRichard Henderson const TCGOpDef *def = &tcg_op_defs[op]; 533*cf066674SRichard Henderson tcg_target_ulong mask, affected; 534*cf066674SRichard Henderson int nb_oargs, nb_iargs, nb_args, i; 535*cf066674SRichard Henderson TCGArg tmp; 536*cf066674SRichard Henderson 5371ff8c541SAurelien Jarno if (op == INDEX_op_call) { 538*cf066674SRichard Henderson *gen_args++ = tmp = *args++; 539*cf066674SRichard Henderson nb_oargs = tmp >> 16; 540*cf066674SRichard Henderson nb_iargs = tmp & 0xffff; 541*cf066674SRichard Henderson nb_args = nb_oargs + nb_iargs + def->nb_cargs; 5421ff8c541SAurelien Jarno } else { 543*cf066674SRichard Henderson nb_oargs = def->nb_oargs; 544*cf066674SRichard Henderson nb_iargs = def->nb_iargs; 545*cf066674SRichard Henderson nb_args = def->nb_args; 546*cf066674SRichard Henderson } 547*cf066674SRichard Henderson 548*cf066674SRichard Henderson /* Do copy propagation */ 549*cf066674SRichard Henderson for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 55022613af4SKirill Batuzov if (temps[args[i]].state == TCG_TEMP_COPY) { 551e590d4e6SAurelien Jarno args[i] = find_better_copy(s, args[i]); 55222613af4SKirill Batuzov } 55322613af4SKirill Batuzov } 55422613af4SKirill Batuzov 55553108fb5SKirill Batuzov /* For commutative operations make constant second argument */ 55653108fb5SKirill Batuzov switch (op) { 55753108fb5SKirill Batuzov CASE_OP_32_64(add): 55853108fb5SKirill Batuzov CASE_OP_32_64(mul): 5599a81090bSKirill Batuzov CASE_OP_32_64(and): 5609a81090bSKirill Batuzov CASE_OP_32_64(or): 5619a81090bSKirill Batuzov CASE_OP_32_64(xor): 562cb25c80aSRichard Henderson CASE_OP_32_64(eqv): 563cb25c80aSRichard Henderson CASE_OP_32_64(nand): 564cb25c80aSRichard Henderson CASE_OP_32_64(nor): 56503271524SRichard Henderson CASE_OP_32_64(muluh): 56603271524SRichard Henderson CASE_OP_32_64(mulsh): 56724c9ae4eSRichard Henderson swap_commutative(args[0], &args[1], &args[2]); 56853108fb5SKirill Batuzov break; 56965a7cce1SAurelien Jarno CASE_OP_32_64(brcond): 57024c9ae4eSRichard Henderson if (swap_commutative(-1, &args[0], &args[1])) { 57165a7cce1SAurelien Jarno args[2] = tcg_swap_cond(args[2]); 57265a7cce1SAurelien Jarno } 57365a7cce1SAurelien Jarno break; 57465a7cce1SAurelien Jarno CASE_OP_32_64(setcond): 57524c9ae4eSRichard Henderson if (swap_commutative(args[0], &args[1], &args[2])) { 57665a7cce1SAurelien Jarno args[3] = tcg_swap_cond(args[3]); 57765a7cce1SAurelien Jarno } 57865a7cce1SAurelien Jarno break; 579fa01a208SRichard Henderson CASE_OP_32_64(movcond): 58024c9ae4eSRichard Henderson if (swap_commutative(-1, &args[1], &args[2])) { 58124c9ae4eSRichard Henderson args[5] = tcg_swap_cond(args[5]); 582fa01a208SRichard Henderson } 5835d8f5363SRichard Henderson /* For movcond, we canonicalize the "false" input reg to match 5845d8f5363SRichard Henderson the destination reg so that the tcg backend can implement 5855d8f5363SRichard Henderson a "move if true" operation. */ 58624c9ae4eSRichard Henderson if (swap_commutative(args[0], &args[4], &args[3])) { 58724c9ae4eSRichard Henderson args[5] = tcg_invert_cond(args[5]); 5885d8f5363SRichard Henderson } 5891e484e61SRichard Henderson break; 590d7156f7cSRichard Henderson CASE_OP_32_64(add2): 5911e484e61SRichard Henderson swap_commutative(args[0], &args[2], &args[4]); 5921e484e61SRichard Henderson swap_commutative(args[1], &args[3], &args[5]); 5931e484e61SRichard Henderson break; 594d7156f7cSRichard Henderson CASE_OP_32_64(mulu2): 5954d3203fdSRichard Henderson CASE_OP_32_64(muls2): 5961414968aSRichard Henderson swap_commutative(args[0], &args[2], &args[3]); 5971414968aSRichard Henderson break; 5980bfcb865SRichard Henderson case INDEX_op_brcond2_i32: 5990bfcb865SRichard Henderson if (swap_commutative2(&args[0], &args[2])) { 6000bfcb865SRichard Henderson args[4] = tcg_swap_cond(args[4]); 6010bfcb865SRichard Henderson } 6020bfcb865SRichard Henderson break; 6030bfcb865SRichard Henderson case INDEX_op_setcond2_i32: 6040bfcb865SRichard Henderson if (swap_commutative2(&args[1], &args[3])) { 6050bfcb865SRichard Henderson args[5] = tcg_swap_cond(args[5]); 6060bfcb865SRichard Henderson } 6070bfcb865SRichard Henderson break; 60853108fb5SKirill Batuzov default: 60953108fb5SKirill Batuzov break; 61053108fb5SKirill Batuzov } 61153108fb5SKirill Batuzov 6122d497542SRichard Henderson /* Simplify expressions for "shift/rot r, 0, a => movi r, 0", 6132d497542SRichard Henderson and "sub r, 0, a => neg r, a" case. */ 61401ee5282SAurelien Jarno switch (op) { 61501ee5282SAurelien Jarno CASE_OP_32_64(shl): 61601ee5282SAurelien Jarno CASE_OP_32_64(shr): 61701ee5282SAurelien Jarno CASE_OP_32_64(sar): 61801ee5282SAurelien Jarno CASE_OP_32_64(rotl): 61901ee5282SAurelien Jarno CASE_OP_32_64(rotr): 62001ee5282SAurelien Jarno if (temps[args[1]].state == TCG_TEMP_CONST 62101ee5282SAurelien Jarno && temps[args[1]].val == 0) { 62292414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = op_to_movi(op); 623e590d4e6SAurelien Jarno tcg_opt_gen_movi(gen_args, args[0], 0); 62401ee5282SAurelien Jarno args += 3; 62501ee5282SAurelien Jarno gen_args += 2; 62601ee5282SAurelien Jarno continue; 62701ee5282SAurelien Jarno } 62801ee5282SAurelien Jarno break; 6292d497542SRichard Henderson CASE_OP_32_64(sub): 6302d497542SRichard Henderson { 6312d497542SRichard Henderson TCGOpcode neg_op; 6322d497542SRichard Henderson bool have_neg; 6332d497542SRichard Henderson 6342d497542SRichard Henderson if (temps[args[2]].state == TCG_TEMP_CONST) { 6352d497542SRichard Henderson /* Proceed with possible constant folding. */ 6362d497542SRichard Henderson break; 6372d497542SRichard Henderson } 6382d497542SRichard Henderson if (op == INDEX_op_sub_i32) { 6392d497542SRichard Henderson neg_op = INDEX_op_neg_i32; 6402d497542SRichard Henderson have_neg = TCG_TARGET_HAS_neg_i32; 6412d497542SRichard Henderson } else { 6422d497542SRichard Henderson neg_op = INDEX_op_neg_i64; 6432d497542SRichard Henderson have_neg = TCG_TARGET_HAS_neg_i64; 6442d497542SRichard Henderson } 6452d497542SRichard Henderson if (!have_neg) { 6462d497542SRichard Henderson break; 6472d497542SRichard Henderson } 6482d497542SRichard Henderson if (temps[args[1]].state == TCG_TEMP_CONST 6492d497542SRichard Henderson && temps[args[1]].val == 0) { 6502d497542SRichard Henderson s->gen_opc_buf[op_index] = neg_op; 6512d497542SRichard Henderson reset_temp(args[0]); 6522d497542SRichard Henderson gen_args[0] = args[0]; 6532d497542SRichard Henderson gen_args[1] = args[2]; 6542d497542SRichard Henderson args += 3; 6552d497542SRichard Henderson gen_args += 2; 6562d497542SRichard Henderson continue; 6572d497542SRichard Henderson } 6582d497542SRichard Henderson } 6592d497542SRichard Henderson break; 660e201b564SRichard Henderson CASE_OP_32_64(xor): 661e201b564SRichard Henderson CASE_OP_32_64(nand): 662e201b564SRichard Henderson if (temps[args[1]].state != TCG_TEMP_CONST 663e201b564SRichard Henderson && temps[args[2]].state == TCG_TEMP_CONST 664e201b564SRichard Henderson && temps[args[2]].val == -1) { 665e201b564SRichard Henderson i = 1; 666e201b564SRichard Henderson goto try_not; 667e201b564SRichard Henderson } 668e201b564SRichard Henderson break; 669e201b564SRichard Henderson CASE_OP_32_64(nor): 670e201b564SRichard Henderson if (temps[args[1]].state != TCG_TEMP_CONST 671e201b564SRichard Henderson && temps[args[2]].state == TCG_TEMP_CONST 672e201b564SRichard Henderson && temps[args[2]].val == 0) { 673e201b564SRichard Henderson i = 1; 674e201b564SRichard Henderson goto try_not; 675e201b564SRichard Henderson } 676e201b564SRichard Henderson break; 677e201b564SRichard Henderson CASE_OP_32_64(andc): 678e201b564SRichard Henderson if (temps[args[2]].state != TCG_TEMP_CONST 679e201b564SRichard Henderson && temps[args[1]].state == TCG_TEMP_CONST 680e201b564SRichard Henderson && temps[args[1]].val == -1) { 681e201b564SRichard Henderson i = 2; 682e201b564SRichard Henderson goto try_not; 683e201b564SRichard Henderson } 684e201b564SRichard Henderson break; 685e201b564SRichard Henderson CASE_OP_32_64(orc): 686e201b564SRichard Henderson CASE_OP_32_64(eqv): 687e201b564SRichard Henderson if (temps[args[2]].state != TCG_TEMP_CONST 688e201b564SRichard Henderson && temps[args[1]].state == TCG_TEMP_CONST 689e201b564SRichard Henderson && temps[args[1]].val == 0) { 690e201b564SRichard Henderson i = 2; 691e201b564SRichard Henderson goto try_not; 692e201b564SRichard Henderson } 693e201b564SRichard Henderson break; 694e201b564SRichard Henderson try_not: 695e201b564SRichard Henderson { 696e201b564SRichard Henderson TCGOpcode not_op; 697e201b564SRichard Henderson bool have_not; 698e201b564SRichard Henderson 699e201b564SRichard Henderson if (def->flags & TCG_OPF_64BIT) { 700e201b564SRichard Henderson not_op = INDEX_op_not_i64; 701e201b564SRichard Henderson have_not = TCG_TARGET_HAS_not_i64; 702e201b564SRichard Henderson } else { 703e201b564SRichard Henderson not_op = INDEX_op_not_i32; 704e201b564SRichard Henderson have_not = TCG_TARGET_HAS_not_i32; 705e201b564SRichard Henderson } 706e201b564SRichard Henderson if (!have_not) { 707e201b564SRichard Henderson break; 708e201b564SRichard Henderson } 709e201b564SRichard Henderson s->gen_opc_buf[op_index] = not_op; 710e201b564SRichard Henderson reset_temp(args[0]); 711e201b564SRichard Henderson gen_args[0] = args[0]; 712e201b564SRichard Henderson gen_args[1] = args[i]; 713e201b564SRichard Henderson args += 3; 714e201b564SRichard Henderson gen_args += 2; 715e201b564SRichard Henderson continue; 716e201b564SRichard Henderson } 71701ee5282SAurelien Jarno default: 71801ee5282SAurelien Jarno break; 71901ee5282SAurelien Jarno } 72001ee5282SAurelien Jarno 721464a1441SRichard Henderson /* Simplify expression for "op r, a, const => mov r, a" cases */ 72253108fb5SKirill Batuzov switch (op) { 72353108fb5SKirill Batuzov CASE_OP_32_64(add): 72453108fb5SKirill Batuzov CASE_OP_32_64(sub): 72555c0975cSKirill Batuzov CASE_OP_32_64(shl): 72655c0975cSKirill Batuzov CASE_OP_32_64(shr): 72755c0975cSKirill Batuzov CASE_OP_32_64(sar): 72825c4d9ccSRichard Henderson CASE_OP_32_64(rotl): 72925c4d9ccSRichard Henderson CASE_OP_32_64(rotr): 73038ee188bSAurelien Jarno CASE_OP_32_64(or): 73138ee188bSAurelien Jarno CASE_OP_32_64(xor): 732464a1441SRichard Henderson CASE_OP_32_64(andc): 733464a1441SRichard Henderson if (temps[args[1]].state != TCG_TEMP_CONST 734464a1441SRichard Henderson && temps[args[2]].state == TCG_TEMP_CONST 73553108fb5SKirill Batuzov && temps[args[2]].val == 0) { 736464a1441SRichard Henderson goto do_mov3; 737464a1441SRichard Henderson } 738464a1441SRichard Henderson break; 739464a1441SRichard Henderson CASE_OP_32_64(and): 740464a1441SRichard Henderson CASE_OP_32_64(orc): 741464a1441SRichard Henderson CASE_OP_32_64(eqv): 742464a1441SRichard Henderson if (temps[args[1]].state != TCG_TEMP_CONST 743464a1441SRichard Henderson && temps[args[2]].state == TCG_TEMP_CONST 744464a1441SRichard Henderson && temps[args[2]].val == -1) { 745464a1441SRichard Henderson goto do_mov3; 746464a1441SRichard Henderson } 747464a1441SRichard Henderson break; 748464a1441SRichard Henderson do_mov3: 749e590d4e6SAurelien Jarno if (temps_are_copies(args[0], args[1])) { 75092414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = INDEX_op_nop; 75153108fb5SKirill Batuzov } else { 75292414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = op_to_mov(op); 753b80bb016SAurelien Jarno tcg_opt_gen_mov(s, gen_args, args[0], args[1]); 75453108fb5SKirill Batuzov gen_args += 2; 75553108fb5SKirill Batuzov } 756fedc0da2SAurelien Jarno args += 3; 75753108fb5SKirill Batuzov continue; 75856e49438SAurelien Jarno default: 75956e49438SAurelien Jarno break; 76056e49438SAurelien Jarno } 76156e49438SAurelien Jarno 7623031244bSAurelien Jarno /* Simplify using known-zero bits. Currently only ops with a single 7633031244bSAurelien Jarno output argument is supported. */ 7643a9d8b17SPaolo Bonzini mask = -1; 765633f6502SPaolo Bonzini affected = -1; 7663a9d8b17SPaolo Bonzini switch (op) { 7673a9d8b17SPaolo Bonzini CASE_OP_32_64(ext8s): 7683a9d8b17SPaolo Bonzini if ((temps[args[1]].mask & 0x80) != 0) { 7693a9d8b17SPaolo Bonzini break; 7703a9d8b17SPaolo Bonzini } 7713a9d8b17SPaolo Bonzini CASE_OP_32_64(ext8u): 7723a9d8b17SPaolo Bonzini mask = 0xff; 7733a9d8b17SPaolo Bonzini goto and_const; 7743a9d8b17SPaolo Bonzini CASE_OP_32_64(ext16s): 7753a9d8b17SPaolo Bonzini if ((temps[args[1]].mask & 0x8000) != 0) { 7763a9d8b17SPaolo Bonzini break; 7773a9d8b17SPaolo Bonzini } 7783a9d8b17SPaolo Bonzini CASE_OP_32_64(ext16u): 7793a9d8b17SPaolo Bonzini mask = 0xffff; 7803a9d8b17SPaolo Bonzini goto and_const; 7813a9d8b17SPaolo Bonzini case INDEX_op_ext32s_i64: 7823a9d8b17SPaolo Bonzini if ((temps[args[1]].mask & 0x80000000) != 0) { 7833a9d8b17SPaolo Bonzini break; 7843a9d8b17SPaolo Bonzini } 7853a9d8b17SPaolo Bonzini case INDEX_op_ext32u_i64: 7863a9d8b17SPaolo Bonzini mask = 0xffffffffU; 7873a9d8b17SPaolo Bonzini goto and_const; 7883a9d8b17SPaolo Bonzini 7893a9d8b17SPaolo Bonzini CASE_OP_32_64(and): 7903a9d8b17SPaolo Bonzini mask = temps[args[2]].mask; 7913a9d8b17SPaolo Bonzini if (temps[args[2]].state == TCG_TEMP_CONST) { 7923a9d8b17SPaolo Bonzini and_const: 793633f6502SPaolo Bonzini affected = temps[args[1]].mask & ~mask; 7943a9d8b17SPaolo Bonzini } 7953a9d8b17SPaolo Bonzini mask = temps[args[1]].mask & mask; 7963a9d8b17SPaolo Bonzini break; 7973a9d8b17SPaolo Bonzini 79823ec69edSRichard Henderson CASE_OP_32_64(andc): 79923ec69edSRichard Henderson /* Known-zeros does not imply known-ones. Therefore unless 80023ec69edSRichard Henderson args[2] is constant, we can't infer anything from it. */ 80123ec69edSRichard Henderson if (temps[args[2]].state == TCG_TEMP_CONST) { 80223ec69edSRichard Henderson mask = ~temps[args[2]].mask; 80323ec69edSRichard Henderson goto and_const; 80423ec69edSRichard Henderson } 80523ec69edSRichard Henderson /* But we certainly know nothing outside args[1] may be set. */ 80623ec69edSRichard Henderson mask = temps[args[1]].mask; 80723ec69edSRichard Henderson break; 80823ec69edSRichard Henderson 809e46b225aSAurelien Jarno case INDEX_op_sar_i32: 8103a9d8b17SPaolo Bonzini if (temps[args[2]].state == TCG_TEMP_CONST) { 81150c5c4d1SRichard Henderson tmp = temps[args[2]].val & 31; 81250c5c4d1SRichard Henderson mask = (int32_t)temps[args[1]].mask >> tmp; 813e46b225aSAurelien Jarno } 814e46b225aSAurelien Jarno break; 815e46b225aSAurelien Jarno case INDEX_op_sar_i64: 816e46b225aSAurelien Jarno if (temps[args[2]].state == TCG_TEMP_CONST) { 81750c5c4d1SRichard Henderson tmp = temps[args[2]].val & 63; 81850c5c4d1SRichard Henderson mask = (int64_t)temps[args[1]].mask >> tmp; 8193a9d8b17SPaolo Bonzini } 8203a9d8b17SPaolo Bonzini break; 8213a9d8b17SPaolo Bonzini 822e46b225aSAurelien Jarno case INDEX_op_shr_i32: 8233a9d8b17SPaolo Bonzini if (temps[args[2]].state == TCG_TEMP_CONST) { 82450c5c4d1SRichard Henderson tmp = temps[args[2]].val & 31; 82550c5c4d1SRichard Henderson mask = (uint32_t)temps[args[1]].mask >> tmp; 826e46b225aSAurelien Jarno } 827e46b225aSAurelien Jarno break; 828e46b225aSAurelien Jarno case INDEX_op_shr_i64: 829e46b225aSAurelien Jarno if (temps[args[2]].state == TCG_TEMP_CONST) { 83050c5c4d1SRichard Henderson tmp = temps[args[2]].val & 63; 83150c5c4d1SRichard Henderson mask = (uint64_t)temps[args[1]].mask >> tmp; 8323a9d8b17SPaolo Bonzini } 8333a9d8b17SPaolo Bonzini break; 8343a9d8b17SPaolo Bonzini 8354bb7a41eSRichard Henderson case INDEX_op_trunc_shr_i32: 8364bb7a41eSRichard Henderson mask = (uint64_t)temps[args[1]].mask >> args[2]; 8374bb7a41eSRichard Henderson break; 8384bb7a41eSRichard Henderson 8393a9d8b17SPaolo Bonzini CASE_OP_32_64(shl): 8403a9d8b17SPaolo Bonzini if (temps[args[2]].state == TCG_TEMP_CONST) { 84150c5c4d1SRichard Henderson tmp = temps[args[2]].val & (TCG_TARGET_REG_BITS - 1); 84250c5c4d1SRichard Henderson mask = temps[args[1]].mask << tmp; 8433a9d8b17SPaolo Bonzini } 8443a9d8b17SPaolo Bonzini break; 8453a9d8b17SPaolo Bonzini 8463a9d8b17SPaolo Bonzini CASE_OP_32_64(neg): 8473a9d8b17SPaolo Bonzini /* Set to 1 all bits to the left of the rightmost. */ 8483a9d8b17SPaolo Bonzini mask = -(temps[args[1]].mask & -temps[args[1]].mask); 8493a9d8b17SPaolo Bonzini break; 8503a9d8b17SPaolo Bonzini 8513a9d8b17SPaolo Bonzini CASE_OP_32_64(deposit): 852d998e555SRichard Henderson mask = deposit64(temps[args[1]].mask, args[3], args[4], 853d998e555SRichard Henderson temps[args[2]].mask); 8543a9d8b17SPaolo Bonzini break; 8553a9d8b17SPaolo Bonzini 8563a9d8b17SPaolo Bonzini CASE_OP_32_64(or): 8573a9d8b17SPaolo Bonzini CASE_OP_32_64(xor): 8583a9d8b17SPaolo Bonzini mask = temps[args[1]].mask | temps[args[2]].mask; 8593a9d8b17SPaolo Bonzini break; 8603a9d8b17SPaolo Bonzini 8613a9d8b17SPaolo Bonzini CASE_OP_32_64(setcond): 8623a9d8b17SPaolo Bonzini mask = 1; 8633a9d8b17SPaolo Bonzini break; 8643a9d8b17SPaolo Bonzini 8653a9d8b17SPaolo Bonzini CASE_OP_32_64(movcond): 8663a9d8b17SPaolo Bonzini mask = temps[args[3]].mask | temps[args[4]].mask; 8673a9d8b17SPaolo Bonzini break; 8683a9d8b17SPaolo Bonzini 869c8d70272SAurelien Jarno CASE_OP_32_64(ld8u): 870c8d70272SAurelien Jarno case INDEX_op_qemu_ld8u: 871c8d70272SAurelien Jarno mask = 0xff; 872c8d70272SAurelien Jarno break; 873c8d70272SAurelien Jarno CASE_OP_32_64(ld16u): 874c8d70272SAurelien Jarno case INDEX_op_qemu_ld16u: 875c8d70272SAurelien Jarno mask = 0xffff; 876c8d70272SAurelien Jarno break; 877c8d70272SAurelien Jarno case INDEX_op_ld32u_i64: 878c8d70272SAurelien Jarno #if TCG_TARGET_REG_BITS == 64 879c8d70272SAurelien Jarno case INDEX_op_qemu_ld32u: 880c8d70272SAurelien Jarno #endif 881c8d70272SAurelien Jarno mask = 0xffffffffu; 882c8d70272SAurelien Jarno break; 883c8d70272SAurelien Jarno 884c8d70272SAurelien Jarno CASE_OP_32_64(qemu_ld): 885c8d70272SAurelien Jarno { 886*cf066674SRichard Henderson TCGMemOp mop = args[nb_oargs + nb_iargs]; 887c8d70272SAurelien Jarno if (!(mop & MO_SIGN)) { 888c8d70272SAurelien Jarno mask = (2ULL << ((8 << (mop & MO_SIZE)) - 1)) - 1; 889c8d70272SAurelien Jarno } 890c8d70272SAurelien Jarno } 891c8d70272SAurelien Jarno break; 892c8d70272SAurelien Jarno 8933a9d8b17SPaolo Bonzini default: 8943a9d8b17SPaolo Bonzini break; 8953a9d8b17SPaolo Bonzini } 8963a9d8b17SPaolo Bonzini 897f096dc96SAurelien Jarno /* 32-bit ops (non 64-bit ops and non load/store ops) generate 32-bit 898f096dc96SAurelien Jarno results */ 899c8d70272SAurelien Jarno if (!(def->flags & (TCG_OPF_CALL_CLOBBER | TCG_OPF_64BIT))) { 900f096dc96SAurelien Jarno mask &= 0xffffffffu; 901f096dc96SAurelien Jarno } 902f096dc96SAurelien Jarno 903633f6502SPaolo Bonzini if (mask == 0) { 904*cf066674SRichard Henderson assert(nb_oargs == 1); 905633f6502SPaolo Bonzini s->gen_opc_buf[op_index] = op_to_movi(op); 906633f6502SPaolo Bonzini tcg_opt_gen_movi(gen_args, args[0], 0); 907*cf066674SRichard Henderson args += nb_args; 908633f6502SPaolo Bonzini gen_args += 2; 909633f6502SPaolo Bonzini continue; 910633f6502SPaolo Bonzini } 911633f6502SPaolo Bonzini if (affected == 0) { 912*cf066674SRichard Henderson assert(nb_oargs == 1); 913633f6502SPaolo Bonzini if (temps_are_copies(args[0], args[1])) { 914633f6502SPaolo Bonzini s->gen_opc_buf[op_index] = INDEX_op_nop; 915633f6502SPaolo Bonzini } else if (temps[args[1]].state != TCG_TEMP_CONST) { 916633f6502SPaolo Bonzini s->gen_opc_buf[op_index] = op_to_mov(op); 917633f6502SPaolo Bonzini tcg_opt_gen_mov(s, gen_args, args[0], args[1]); 918633f6502SPaolo Bonzini gen_args += 2; 919633f6502SPaolo Bonzini } else { 920633f6502SPaolo Bonzini s->gen_opc_buf[op_index] = op_to_movi(op); 921633f6502SPaolo Bonzini tcg_opt_gen_movi(gen_args, args[0], temps[args[1]].val); 922633f6502SPaolo Bonzini gen_args += 2; 923633f6502SPaolo Bonzini } 924*cf066674SRichard Henderson args += nb_args; 925633f6502SPaolo Bonzini continue; 926633f6502SPaolo Bonzini } 927633f6502SPaolo Bonzini 92856e49438SAurelien Jarno /* Simplify expression for "op r, a, 0 => movi r, 0" cases */ 92956e49438SAurelien Jarno switch (op) { 93061251c0cSAurelien Jarno CASE_OP_32_64(and): 93153108fb5SKirill Batuzov CASE_OP_32_64(mul): 93203271524SRichard Henderson CASE_OP_32_64(muluh): 93303271524SRichard Henderson CASE_OP_32_64(mulsh): 93453108fb5SKirill Batuzov if ((temps[args[2]].state == TCG_TEMP_CONST 93553108fb5SKirill Batuzov && temps[args[2]].val == 0)) { 93692414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = op_to_movi(op); 937e590d4e6SAurelien Jarno tcg_opt_gen_movi(gen_args, args[0], 0); 93853108fb5SKirill Batuzov args += 3; 93953108fb5SKirill Batuzov gen_args += 2; 94053108fb5SKirill Batuzov continue; 94153108fb5SKirill Batuzov } 94253108fb5SKirill Batuzov break; 94356e49438SAurelien Jarno default: 94456e49438SAurelien Jarno break; 94556e49438SAurelien Jarno } 94656e49438SAurelien Jarno 94756e49438SAurelien Jarno /* Simplify expression for "op r, a, a => mov r, a" cases */ 94856e49438SAurelien Jarno switch (op) { 9499a81090bSKirill Batuzov CASE_OP_32_64(or): 9509a81090bSKirill Batuzov CASE_OP_32_64(and): 9510aba1c73SAurelien Jarno if (temps_are_copies(args[1], args[2])) { 952e590d4e6SAurelien Jarno if (temps_are_copies(args[0], args[1])) { 95392414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = INDEX_op_nop; 9549a81090bSKirill Batuzov } else { 95592414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = op_to_mov(op); 956b80bb016SAurelien Jarno tcg_opt_gen_mov(s, gen_args, args[0], args[1]); 9579a81090bSKirill Batuzov gen_args += 2; 9589a81090bSKirill Batuzov } 959fedc0da2SAurelien Jarno args += 3; 9609a81090bSKirill Batuzov continue; 9619a81090bSKirill Batuzov } 9629a81090bSKirill Batuzov break; 963fe0de7aaSBlue Swirl default: 964fe0de7aaSBlue Swirl break; 96553108fb5SKirill Batuzov } 96653108fb5SKirill Batuzov 9673c94193eSAurelien Jarno /* Simplify expression for "op r, a, a => movi r, 0" cases */ 9683c94193eSAurelien Jarno switch (op) { 969e64e958eSRichard Henderson CASE_OP_32_64(andc): 9703c94193eSAurelien Jarno CASE_OP_32_64(sub): 9713c94193eSAurelien Jarno CASE_OP_32_64(xor): 9723c94193eSAurelien Jarno if (temps_are_copies(args[1], args[2])) { 97392414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = op_to_movi(op); 9743c94193eSAurelien Jarno tcg_opt_gen_movi(gen_args, args[0], 0); 9753c94193eSAurelien Jarno gen_args += 2; 9763c94193eSAurelien Jarno args += 3; 9773c94193eSAurelien Jarno continue; 9783c94193eSAurelien Jarno } 9793c94193eSAurelien Jarno break; 9803c94193eSAurelien Jarno default: 9813c94193eSAurelien Jarno break; 9823c94193eSAurelien Jarno } 9833c94193eSAurelien Jarno 98422613af4SKirill Batuzov /* Propagate constants through copy operations and do constant 98522613af4SKirill Batuzov folding. Constants will be substituted to arguments by register 98622613af4SKirill Batuzov allocator where needed and possible. Also detect copies. */ 9878f2e8c07SKirill Batuzov switch (op) { 98822613af4SKirill Batuzov CASE_OP_32_64(mov): 989e590d4e6SAurelien Jarno if (temps_are_copies(args[0], args[1])) { 99022613af4SKirill Batuzov args += 2; 99192414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = INDEX_op_nop; 99222613af4SKirill Batuzov break; 99322613af4SKirill Batuzov } 99422613af4SKirill Batuzov if (temps[args[1]].state != TCG_TEMP_CONST) { 995b80bb016SAurelien Jarno tcg_opt_gen_mov(s, gen_args, args[0], args[1]); 99622613af4SKirill Batuzov gen_args += 2; 99722613af4SKirill Batuzov args += 2; 99822613af4SKirill Batuzov break; 99922613af4SKirill Batuzov } 100022613af4SKirill Batuzov /* Source argument is constant. Rewrite the operation and 100122613af4SKirill Batuzov let movi case handle it. */ 100222613af4SKirill Batuzov op = op_to_movi(op); 100392414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = op; 100422613af4SKirill Batuzov args[1] = temps[args[1]].val; 100522613af4SKirill Batuzov /* fallthrough */ 100622613af4SKirill Batuzov CASE_OP_32_64(movi): 1007e590d4e6SAurelien Jarno tcg_opt_gen_movi(gen_args, args[0], args[1]); 100822613af4SKirill Batuzov gen_args += 2; 100922613af4SKirill Batuzov args += 2; 101022613af4SKirill Batuzov break; 10116e14e91bSRichard Henderson 1012a640f031SKirill Batuzov CASE_OP_32_64(not): 1013cb25c80aSRichard Henderson CASE_OP_32_64(neg): 101425c4d9ccSRichard Henderson CASE_OP_32_64(ext8s): 101525c4d9ccSRichard Henderson CASE_OP_32_64(ext8u): 101625c4d9ccSRichard Henderson CASE_OP_32_64(ext16s): 101725c4d9ccSRichard Henderson CASE_OP_32_64(ext16u): 1018a640f031SKirill Batuzov case INDEX_op_ext32s_i64: 1019a640f031SKirill Batuzov case INDEX_op_ext32u_i64: 1020a640f031SKirill Batuzov if (temps[args[1]].state == TCG_TEMP_CONST) { 102192414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = op_to_movi(op); 1022a640f031SKirill Batuzov tmp = do_constant_folding(op, temps[args[1]].val, 0); 1023e590d4e6SAurelien Jarno tcg_opt_gen_movi(gen_args, args[0], tmp); 1024a640f031SKirill Batuzov gen_args += 2; 1025a640f031SKirill Batuzov args += 2; 1026a640f031SKirill Batuzov break; 10276e14e91bSRichard Henderson } 10286e14e91bSRichard Henderson goto do_default; 10296e14e91bSRichard Henderson 10304bb7a41eSRichard Henderson case INDEX_op_trunc_shr_i32: 10314bb7a41eSRichard Henderson if (temps[args[1]].state == TCG_TEMP_CONST) { 10324bb7a41eSRichard Henderson s->gen_opc_buf[op_index] = op_to_movi(op); 10334bb7a41eSRichard Henderson tmp = do_constant_folding(op, temps[args[1]].val, args[2]); 10344bb7a41eSRichard Henderson tcg_opt_gen_movi(gen_args, args[0], tmp); 10354bb7a41eSRichard Henderson gen_args += 2; 10364bb7a41eSRichard Henderson args += 3; 10374bb7a41eSRichard Henderson break; 10384bb7a41eSRichard Henderson } 10394bb7a41eSRichard Henderson goto do_default; 10404bb7a41eSRichard Henderson 104153108fb5SKirill Batuzov CASE_OP_32_64(add): 104253108fb5SKirill Batuzov CASE_OP_32_64(sub): 104353108fb5SKirill Batuzov CASE_OP_32_64(mul): 10449a81090bSKirill Batuzov CASE_OP_32_64(or): 10459a81090bSKirill Batuzov CASE_OP_32_64(and): 10469a81090bSKirill Batuzov CASE_OP_32_64(xor): 104755c0975cSKirill Batuzov CASE_OP_32_64(shl): 104855c0975cSKirill Batuzov CASE_OP_32_64(shr): 104955c0975cSKirill Batuzov CASE_OP_32_64(sar): 105025c4d9ccSRichard Henderson CASE_OP_32_64(rotl): 105125c4d9ccSRichard Henderson CASE_OP_32_64(rotr): 1052cb25c80aSRichard Henderson CASE_OP_32_64(andc): 1053cb25c80aSRichard Henderson CASE_OP_32_64(orc): 1054cb25c80aSRichard Henderson CASE_OP_32_64(eqv): 1055cb25c80aSRichard Henderson CASE_OP_32_64(nand): 1056cb25c80aSRichard Henderson CASE_OP_32_64(nor): 105703271524SRichard Henderson CASE_OP_32_64(muluh): 105803271524SRichard Henderson CASE_OP_32_64(mulsh): 105901547f7fSRichard Henderson CASE_OP_32_64(div): 106001547f7fSRichard Henderson CASE_OP_32_64(divu): 106101547f7fSRichard Henderson CASE_OP_32_64(rem): 106201547f7fSRichard Henderson CASE_OP_32_64(remu): 106353108fb5SKirill Batuzov if (temps[args[1]].state == TCG_TEMP_CONST 106453108fb5SKirill Batuzov && temps[args[2]].state == TCG_TEMP_CONST) { 106592414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = op_to_movi(op); 106653108fb5SKirill Batuzov tmp = do_constant_folding(op, temps[args[1]].val, 106753108fb5SKirill Batuzov temps[args[2]].val); 1068e590d4e6SAurelien Jarno tcg_opt_gen_movi(gen_args, args[0], tmp); 106953108fb5SKirill Batuzov gen_args += 2; 107053108fb5SKirill Batuzov args += 3; 107153108fb5SKirill Batuzov break; 10726e14e91bSRichard Henderson } 10736e14e91bSRichard Henderson goto do_default; 10746e14e91bSRichard Henderson 10757ef55fc9SAurelien Jarno CASE_OP_32_64(deposit): 10767ef55fc9SAurelien Jarno if (temps[args[1]].state == TCG_TEMP_CONST 10777ef55fc9SAurelien Jarno && temps[args[2]].state == TCG_TEMP_CONST) { 107892414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = op_to_movi(op); 1079d998e555SRichard Henderson tmp = deposit64(temps[args[1]].val, args[3], args[4], 1080d998e555SRichard Henderson temps[args[2]].val); 10817ef55fc9SAurelien Jarno tcg_opt_gen_movi(gen_args, args[0], tmp); 10827ef55fc9SAurelien Jarno gen_args += 2; 10837ef55fc9SAurelien Jarno args += 5; 10847ef55fc9SAurelien Jarno break; 10856e14e91bSRichard Henderson } 10866e14e91bSRichard Henderson goto do_default; 10876e14e91bSRichard Henderson 1088f8dd19e5SAurelien Jarno CASE_OP_32_64(setcond): 1089b336ceb6SAurelien Jarno tmp = do_constant_folding_cond(op, args[1], args[2], args[3]); 1090b336ceb6SAurelien Jarno if (tmp != 2) { 109192414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = op_to_movi(op); 1092e590d4e6SAurelien Jarno tcg_opt_gen_movi(gen_args, args[0], tmp); 1093f8dd19e5SAurelien Jarno gen_args += 2; 1094f8dd19e5SAurelien Jarno args += 4; 1095f8dd19e5SAurelien Jarno break; 10966e14e91bSRichard Henderson } 10976e14e91bSRichard Henderson goto do_default; 10986e14e91bSRichard Henderson 1099fbeaa26cSAurelien Jarno CASE_OP_32_64(brcond): 1100b336ceb6SAurelien Jarno tmp = do_constant_folding_cond(op, args[0], args[1], args[2]); 1101b336ceb6SAurelien Jarno if (tmp != 2) { 1102b336ceb6SAurelien Jarno if (tmp) { 1103d193a14aSPaolo Bonzini reset_all_temps(nb_temps); 110492414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = INDEX_op_br; 1105fbeaa26cSAurelien Jarno gen_args[0] = args[3]; 1106fbeaa26cSAurelien Jarno gen_args += 1; 1107fbeaa26cSAurelien Jarno } else { 110892414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = INDEX_op_nop; 1109fbeaa26cSAurelien Jarno } 1110fbeaa26cSAurelien Jarno args += 4; 1111fbeaa26cSAurelien Jarno break; 11126e14e91bSRichard Henderson } 11136e14e91bSRichard Henderson goto do_default; 11146e14e91bSRichard Henderson 1115fa01a208SRichard Henderson CASE_OP_32_64(movcond): 1116b336ceb6SAurelien Jarno tmp = do_constant_folding_cond(op, args[1], args[2], args[5]); 1117b336ceb6SAurelien Jarno if (tmp != 2) { 1118e590d4e6SAurelien Jarno if (temps_are_copies(args[0], args[4-tmp])) { 111992414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = INDEX_op_nop; 1120fa01a208SRichard Henderson } else if (temps[args[4-tmp]].state == TCG_TEMP_CONST) { 112192414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = op_to_movi(op); 1122e590d4e6SAurelien Jarno tcg_opt_gen_movi(gen_args, args[0], temps[args[4-tmp]].val); 1123fa01a208SRichard Henderson gen_args += 2; 1124fa01a208SRichard Henderson } else { 112592414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = op_to_mov(op); 1126e590d4e6SAurelien Jarno tcg_opt_gen_mov(s, gen_args, args[0], args[4-tmp]); 1127fa01a208SRichard Henderson gen_args += 2; 1128fa01a208SRichard Henderson } 1129fa01a208SRichard Henderson args += 6; 1130fa01a208SRichard Henderson break; 11316e14e91bSRichard Henderson } 11326e14e91bSRichard Henderson goto do_default; 11336e14e91bSRichard Henderson 1134212c328dSRichard Henderson case INDEX_op_add2_i32: 1135212c328dSRichard Henderson case INDEX_op_sub2_i32: 1136212c328dSRichard Henderson if (temps[args[2]].state == TCG_TEMP_CONST 1137212c328dSRichard Henderson && temps[args[3]].state == TCG_TEMP_CONST 1138212c328dSRichard Henderson && temps[args[4]].state == TCG_TEMP_CONST 1139212c328dSRichard Henderson && temps[args[5]].state == TCG_TEMP_CONST) { 1140212c328dSRichard Henderson uint32_t al = temps[args[2]].val; 1141212c328dSRichard Henderson uint32_t ah = temps[args[3]].val; 1142212c328dSRichard Henderson uint32_t bl = temps[args[4]].val; 1143212c328dSRichard Henderson uint32_t bh = temps[args[5]].val; 1144212c328dSRichard Henderson uint64_t a = ((uint64_t)ah << 32) | al; 1145212c328dSRichard Henderson uint64_t b = ((uint64_t)bh << 32) | bl; 1146212c328dSRichard Henderson TCGArg rl, rh; 1147212c328dSRichard Henderson 1148212c328dSRichard Henderson if (op == INDEX_op_add2_i32) { 1149212c328dSRichard Henderson a += b; 1150212c328dSRichard Henderson } else { 1151212c328dSRichard Henderson a -= b; 1152212c328dSRichard Henderson } 1153212c328dSRichard Henderson 1154212c328dSRichard Henderson /* We emit the extra nop when we emit the add2/sub2. */ 115592414b31SEvgeny Voevodin assert(s->gen_opc_buf[op_index + 1] == INDEX_op_nop); 1156212c328dSRichard Henderson 1157212c328dSRichard Henderson rl = args[0]; 1158212c328dSRichard Henderson rh = args[1]; 115992414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = INDEX_op_movi_i32; 116092414b31SEvgeny Voevodin s->gen_opc_buf[++op_index] = INDEX_op_movi_i32; 1161212c328dSRichard Henderson tcg_opt_gen_movi(&gen_args[0], rl, (uint32_t)a); 1162212c328dSRichard Henderson tcg_opt_gen_movi(&gen_args[2], rh, (uint32_t)(a >> 32)); 1163212c328dSRichard Henderson gen_args += 4; 1164212c328dSRichard Henderson args += 6; 1165212c328dSRichard Henderson break; 1166212c328dSRichard Henderson } 1167212c328dSRichard Henderson goto do_default; 1168212c328dSRichard Henderson 11691414968aSRichard Henderson case INDEX_op_mulu2_i32: 11701414968aSRichard Henderson if (temps[args[2]].state == TCG_TEMP_CONST 11711414968aSRichard Henderson && temps[args[3]].state == TCG_TEMP_CONST) { 11721414968aSRichard Henderson uint32_t a = temps[args[2]].val; 11731414968aSRichard Henderson uint32_t b = temps[args[3]].val; 11741414968aSRichard Henderson uint64_t r = (uint64_t)a * b; 11751414968aSRichard Henderson TCGArg rl, rh; 11761414968aSRichard Henderson 11771414968aSRichard Henderson /* We emit the extra nop when we emit the mulu2. */ 117892414b31SEvgeny Voevodin assert(s->gen_opc_buf[op_index + 1] == INDEX_op_nop); 11791414968aSRichard Henderson 11801414968aSRichard Henderson rl = args[0]; 11811414968aSRichard Henderson rh = args[1]; 118292414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = INDEX_op_movi_i32; 118392414b31SEvgeny Voevodin s->gen_opc_buf[++op_index] = INDEX_op_movi_i32; 11841414968aSRichard Henderson tcg_opt_gen_movi(&gen_args[0], rl, (uint32_t)r); 11851414968aSRichard Henderson tcg_opt_gen_movi(&gen_args[2], rh, (uint32_t)(r >> 32)); 11861414968aSRichard Henderson gen_args += 4; 11871414968aSRichard Henderson args += 4; 11881414968aSRichard Henderson break; 11891414968aSRichard Henderson } 11901414968aSRichard Henderson goto do_default; 11911414968aSRichard Henderson 1192bc1473efSRichard Henderson case INDEX_op_brcond2_i32: 11936c4382f8SRichard Henderson tmp = do_constant_folding_cond2(&args[0], &args[2], args[4]); 11946c4382f8SRichard Henderson if (tmp != 2) { 11956c4382f8SRichard Henderson if (tmp) { 1196d193a14aSPaolo Bonzini reset_all_temps(nb_temps); 119792414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = INDEX_op_br; 11986c4382f8SRichard Henderson gen_args[0] = args[5]; 11996c4382f8SRichard Henderson gen_args += 1; 12006c4382f8SRichard Henderson } else { 120192414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = INDEX_op_nop; 12026c4382f8SRichard Henderson } 12036c4382f8SRichard Henderson } else if ((args[4] == TCG_COND_LT || args[4] == TCG_COND_GE) 1204bc1473efSRichard Henderson && temps[args[2]].state == TCG_TEMP_CONST 1205bc1473efSRichard Henderson && temps[args[3]].state == TCG_TEMP_CONST 1206bc1473efSRichard Henderson && temps[args[2]].val == 0 1207bc1473efSRichard Henderson && temps[args[3]].val == 0) { 12086c4382f8SRichard Henderson /* Simplify LT/GE comparisons vs zero to a single compare 12096c4382f8SRichard Henderson vs the high word of the input. */ 1210d193a14aSPaolo Bonzini reset_all_temps(nb_temps); 121192414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = INDEX_op_brcond_i32; 1212bc1473efSRichard Henderson gen_args[0] = args[1]; 1213bc1473efSRichard Henderson gen_args[1] = args[3]; 1214bc1473efSRichard Henderson gen_args[2] = args[4]; 1215bc1473efSRichard Henderson gen_args[3] = args[5]; 1216bc1473efSRichard Henderson gen_args += 4; 12176c4382f8SRichard Henderson } else { 1218bc1473efSRichard Henderson goto do_default; 12196c4382f8SRichard Henderson } 12206c4382f8SRichard Henderson args += 6; 12216c4382f8SRichard Henderson break; 1222bc1473efSRichard Henderson 1223bc1473efSRichard Henderson case INDEX_op_setcond2_i32: 12246c4382f8SRichard Henderson tmp = do_constant_folding_cond2(&args[1], &args[3], args[5]); 12256c4382f8SRichard Henderson if (tmp != 2) { 122692414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = INDEX_op_movi_i32; 12276c4382f8SRichard Henderson tcg_opt_gen_movi(gen_args, args[0], tmp); 12286c4382f8SRichard Henderson gen_args += 2; 12296c4382f8SRichard Henderson } else if ((args[5] == TCG_COND_LT || args[5] == TCG_COND_GE) 1230bc1473efSRichard Henderson && temps[args[3]].state == TCG_TEMP_CONST 1231bc1473efSRichard Henderson && temps[args[4]].state == TCG_TEMP_CONST 1232bc1473efSRichard Henderson && temps[args[3]].val == 0 1233bc1473efSRichard Henderson && temps[args[4]].val == 0) { 12346c4382f8SRichard Henderson /* Simplify LT/GE comparisons vs zero to a single compare 12356c4382f8SRichard Henderson vs the high word of the input. */ 123692414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = INDEX_op_setcond_i32; 123766e61b55SAurelien Jarno reset_temp(args[0]); 1238bc1473efSRichard Henderson gen_args[0] = args[0]; 1239bc1473efSRichard Henderson gen_args[1] = args[2]; 1240bc1473efSRichard Henderson gen_args[2] = args[4]; 1241bc1473efSRichard Henderson gen_args[3] = args[5]; 1242bc1473efSRichard Henderson gen_args += 4; 12436c4382f8SRichard Henderson } else { 12446c4382f8SRichard Henderson goto do_default; 12456c4382f8SRichard Henderson } 1246bc1473efSRichard Henderson args += 6; 1247bc1473efSRichard Henderson break; 1248bc1473efSRichard Henderson 12498f2e8c07SKirill Batuzov case INDEX_op_call: 1250*cf066674SRichard Henderson if (!(args[nb_oargs + nb_iargs + 1] 1251*cf066674SRichard Henderson & (TCG_CALL_NO_READ_GLOBALS | TCG_CALL_NO_WRITE_GLOBALS))) { 125222613af4SKirill Batuzov for (i = 0; i < nb_globals; i++) { 1253e590d4e6SAurelien Jarno reset_temp(i); 125422613af4SKirill Batuzov } 125522613af4SKirill Batuzov } 1256*cf066674SRichard Henderson goto do_reset_output; 12576e14e91bSRichard Henderson 12588f2e8c07SKirill Batuzov default: 12596e14e91bSRichard Henderson do_default: 12606e14e91bSRichard Henderson /* Default case: we know nothing about operation (or were unable 12616e14e91bSRichard Henderson to compute the operation result) so no propagation is done. 12626e14e91bSRichard Henderson We trash everything if the operation is the end of a basic 12633a9d8b17SPaolo Bonzini block, otherwise we only trash the output args. "mask" is 12643a9d8b17SPaolo Bonzini the non-zero bits mask for the first output arg. */ 1265a2550660SAurelien Jarno if (def->flags & TCG_OPF_BB_END) { 1266d193a14aSPaolo Bonzini reset_all_temps(nb_temps); 1267a2550660SAurelien Jarno } else { 1268*cf066674SRichard Henderson do_reset_output: 1269*cf066674SRichard Henderson for (i = 0; i < nb_oargs; i++) { 1270e590d4e6SAurelien Jarno reset_temp(args[i]); 12713031244bSAurelien Jarno /* Save the corresponding known-zero bits mask for the 12723031244bSAurelien Jarno first output argument (only one supported so far). */ 12733031244bSAurelien Jarno if (i == 0) { 12743031244bSAurelien Jarno temps[args[i]].mask = mask; 12753031244bSAurelien Jarno } 127622613af4SKirill Batuzov } 1277a2550660SAurelien Jarno } 1278*cf066674SRichard Henderson for (i = 0; i < nb_args; i++) { 12798f2e8c07SKirill Batuzov gen_args[i] = args[i]; 12808f2e8c07SKirill Batuzov } 1281*cf066674SRichard Henderson args += nb_args; 1282*cf066674SRichard Henderson gen_args += nb_args; 12838f2e8c07SKirill Batuzov break; 12848f2e8c07SKirill Batuzov } 12858f2e8c07SKirill Batuzov } 12868f2e8c07SKirill Batuzov 12878f2e8c07SKirill Batuzov return gen_args; 12888f2e8c07SKirill Batuzov } 12898f2e8c07SKirill Batuzov 12908f2e8c07SKirill Batuzov TCGArg *tcg_optimize(TCGContext *s, uint16_t *tcg_opc_ptr, 12918f2e8c07SKirill Batuzov TCGArg *args, TCGOpDef *tcg_op_defs) 12928f2e8c07SKirill Batuzov { 12938f2e8c07SKirill Batuzov TCGArg *res; 12948f2e8c07SKirill Batuzov res = tcg_constant_folding(s, tcg_opc_ptr, args, tcg_op_defs); 12958f2e8c07SKirill Batuzov return res; 12968f2e8c07SKirill Batuzov } 1297