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; 4922613af4SKirill Batuzov }; 5022613af4SKirill Batuzov 5122613af4SKirill Batuzov static struct tcg_temp_info temps[TCG_MAX_TEMPS]; 5222613af4SKirill Batuzov 53e590d4e6SAurelien Jarno /* Reset TEMP's state to TCG_TEMP_UNDEF. If TEMP only had one copy, remove 54e590d4e6SAurelien Jarno the copy flag from the left temp. */ 55e590d4e6SAurelien Jarno static void reset_temp(TCGArg temp) 5622613af4SKirill Batuzov { 57e590d4e6SAurelien Jarno if (temps[temp].state == TCG_TEMP_COPY) { 58e590d4e6SAurelien Jarno if (temps[temp].prev_copy == temps[temp].next_copy) { 59e590d4e6SAurelien Jarno temps[temps[temp].next_copy].state = TCG_TEMP_UNDEF; 6022613af4SKirill Batuzov } else { 6122613af4SKirill Batuzov temps[temps[temp].next_copy].prev_copy = temps[temp].prev_copy; 6222613af4SKirill Batuzov temps[temps[temp].prev_copy].next_copy = temps[temp].next_copy; 63e590d4e6SAurelien Jarno } 6422613af4SKirill Batuzov } 6548b56ce1SAurelien Jarno temps[temp].state = TCG_TEMP_UNDEF; 6622613af4SKirill Batuzov } 6722613af4SKirill Batuzov 68*d193a14aSPaolo Bonzini /* Reset all temporaries, given that there are NB_TEMPS of them. */ 69*d193a14aSPaolo Bonzini static void reset_all_temps(int nb_temps) 70*d193a14aSPaolo Bonzini { 71*d193a14aSPaolo Bonzini int i; 72*d193a14aSPaolo Bonzini for (i = 0; i < nb_temps; i++) { 73*d193a14aSPaolo Bonzini temps[i].state = TCG_TEMP_UNDEF; 74*d193a14aSPaolo Bonzini } 75*d193a14aSPaolo Bonzini } 76*d193a14aSPaolo Bonzini 77fe0de7aaSBlue Swirl static int op_bits(TCGOpcode op) 7822613af4SKirill Batuzov { 798399ad59SRichard Henderson const TCGOpDef *def = &tcg_op_defs[op]; 808399ad59SRichard Henderson return def->flags & TCG_OPF_64BIT ? 64 : 32; 8122613af4SKirill Batuzov } 8222613af4SKirill Batuzov 83fe0de7aaSBlue Swirl static TCGOpcode op_to_movi(TCGOpcode op) 8422613af4SKirill Batuzov { 8522613af4SKirill Batuzov switch (op_bits(op)) { 8622613af4SKirill Batuzov case 32: 8722613af4SKirill Batuzov return INDEX_op_movi_i32; 8822613af4SKirill Batuzov case 64: 8922613af4SKirill Batuzov return INDEX_op_movi_i64; 9022613af4SKirill Batuzov default: 9122613af4SKirill Batuzov fprintf(stderr, "op_to_movi: unexpected return value of " 9222613af4SKirill Batuzov "function op_bits.\n"); 9322613af4SKirill Batuzov tcg_abort(); 9422613af4SKirill Batuzov } 9522613af4SKirill Batuzov } 9622613af4SKirill Batuzov 97e590d4e6SAurelien Jarno static TCGArg find_better_copy(TCGContext *s, TCGArg temp) 98e590d4e6SAurelien Jarno { 99e590d4e6SAurelien Jarno TCGArg i; 100e590d4e6SAurelien Jarno 101e590d4e6SAurelien Jarno /* If this is already a global, we can't do better. */ 102e590d4e6SAurelien Jarno if (temp < s->nb_globals) { 103e590d4e6SAurelien Jarno return temp; 104e590d4e6SAurelien Jarno } 105e590d4e6SAurelien Jarno 106e590d4e6SAurelien Jarno /* Search for a global first. */ 107e590d4e6SAurelien Jarno for (i = temps[temp].next_copy ; i != temp ; i = temps[i].next_copy) { 108e590d4e6SAurelien Jarno if (i < s->nb_globals) { 109e590d4e6SAurelien Jarno return i; 110e590d4e6SAurelien Jarno } 111e590d4e6SAurelien Jarno } 112e590d4e6SAurelien Jarno 113e590d4e6SAurelien Jarno /* If it is a temp, search for a temp local. */ 114e590d4e6SAurelien Jarno if (!s->temps[temp].temp_local) { 115e590d4e6SAurelien Jarno for (i = temps[temp].next_copy ; i != temp ; i = temps[i].next_copy) { 116e590d4e6SAurelien Jarno if (s->temps[i].temp_local) { 117e590d4e6SAurelien Jarno return i; 118e590d4e6SAurelien Jarno } 119e590d4e6SAurelien Jarno } 120e590d4e6SAurelien Jarno } 121e590d4e6SAurelien Jarno 122e590d4e6SAurelien Jarno /* Failure to find a better representation, return the same temp. */ 123e590d4e6SAurelien Jarno return temp; 124e590d4e6SAurelien Jarno } 125e590d4e6SAurelien Jarno 126e590d4e6SAurelien Jarno static bool temps_are_copies(TCGArg arg1, TCGArg arg2) 127e590d4e6SAurelien Jarno { 128e590d4e6SAurelien Jarno TCGArg i; 129e590d4e6SAurelien Jarno 130e590d4e6SAurelien Jarno if (arg1 == arg2) { 131e590d4e6SAurelien Jarno return true; 132e590d4e6SAurelien Jarno } 133e590d4e6SAurelien Jarno 134e590d4e6SAurelien Jarno if (temps[arg1].state != TCG_TEMP_COPY 135e590d4e6SAurelien Jarno || temps[arg2].state != TCG_TEMP_COPY) { 136e590d4e6SAurelien Jarno return false; 137e590d4e6SAurelien Jarno } 138e590d4e6SAurelien Jarno 139e590d4e6SAurelien Jarno for (i = temps[arg1].next_copy ; i != arg1 ; i = temps[i].next_copy) { 140e590d4e6SAurelien Jarno if (i == arg2) { 141e590d4e6SAurelien Jarno return true; 142e590d4e6SAurelien Jarno } 143e590d4e6SAurelien Jarno } 144e590d4e6SAurelien Jarno 145e590d4e6SAurelien Jarno return false; 146e590d4e6SAurelien Jarno } 147e590d4e6SAurelien Jarno 148b80bb016SAurelien Jarno static void tcg_opt_gen_mov(TCGContext *s, TCGArg *gen_args, 149b80bb016SAurelien Jarno TCGArg dst, TCGArg src) 15022613af4SKirill Batuzov { 151e590d4e6SAurelien Jarno reset_temp(dst); 15222613af4SKirill Batuzov assert(temps[src].state != TCG_TEMP_CONST); 153e590d4e6SAurelien Jarno 154e590d4e6SAurelien Jarno if (s->temps[src].type == s->temps[dst].type) { 155e590d4e6SAurelien Jarno if (temps[src].state != TCG_TEMP_COPY) { 156e590d4e6SAurelien Jarno temps[src].state = TCG_TEMP_COPY; 15722613af4SKirill Batuzov temps[src].next_copy = src; 15822613af4SKirill Batuzov temps[src].prev_copy = src; 15922613af4SKirill Batuzov } 16022613af4SKirill Batuzov temps[dst].state = TCG_TEMP_COPY; 16122613af4SKirill Batuzov temps[dst].next_copy = temps[src].next_copy; 16222613af4SKirill Batuzov temps[dst].prev_copy = src; 16322613af4SKirill Batuzov temps[temps[dst].next_copy].prev_copy = dst; 16422613af4SKirill Batuzov temps[src].next_copy = dst; 16522613af4SKirill Batuzov } 166e590d4e6SAurelien Jarno 16722613af4SKirill Batuzov gen_args[0] = dst; 16822613af4SKirill Batuzov gen_args[1] = src; 16922613af4SKirill Batuzov } 17022613af4SKirill Batuzov 171e590d4e6SAurelien Jarno static void tcg_opt_gen_movi(TCGArg *gen_args, TCGArg dst, TCGArg val) 17222613af4SKirill Batuzov { 173e590d4e6SAurelien Jarno reset_temp(dst); 17422613af4SKirill Batuzov temps[dst].state = TCG_TEMP_CONST; 17522613af4SKirill Batuzov temps[dst].val = val; 17622613af4SKirill Batuzov gen_args[0] = dst; 17722613af4SKirill Batuzov gen_args[1] = val; 17822613af4SKirill Batuzov } 17922613af4SKirill Batuzov 180fe0de7aaSBlue Swirl static TCGOpcode op_to_mov(TCGOpcode op) 18153108fb5SKirill Batuzov { 18253108fb5SKirill Batuzov switch (op_bits(op)) { 18353108fb5SKirill Batuzov case 32: 18453108fb5SKirill Batuzov return INDEX_op_mov_i32; 18553108fb5SKirill Batuzov case 64: 18653108fb5SKirill Batuzov return INDEX_op_mov_i64; 18753108fb5SKirill Batuzov default: 18853108fb5SKirill Batuzov fprintf(stderr, "op_to_mov: unexpected return value of " 18953108fb5SKirill Batuzov "function op_bits.\n"); 19053108fb5SKirill Batuzov tcg_abort(); 19153108fb5SKirill Batuzov } 19253108fb5SKirill Batuzov } 19353108fb5SKirill Batuzov 194fe0de7aaSBlue Swirl static TCGArg do_constant_folding_2(TCGOpcode op, TCGArg x, TCGArg y) 19553108fb5SKirill Batuzov { 19653108fb5SKirill Batuzov switch (op) { 19753108fb5SKirill Batuzov CASE_OP_32_64(add): 19853108fb5SKirill Batuzov return x + y; 19953108fb5SKirill Batuzov 20053108fb5SKirill Batuzov CASE_OP_32_64(sub): 20153108fb5SKirill Batuzov return x - y; 20253108fb5SKirill Batuzov 20353108fb5SKirill Batuzov CASE_OP_32_64(mul): 20453108fb5SKirill Batuzov return x * y; 20553108fb5SKirill Batuzov 2069a81090bSKirill Batuzov CASE_OP_32_64(and): 2079a81090bSKirill Batuzov return x & y; 2089a81090bSKirill Batuzov 2099a81090bSKirill Batuzov CASE_OP_32_64(or): 2109a81090bSKirill Batuzov return x | y; 2119a81090bSKirill Batuzov 2129a81090bSKirill Batuzov CASE_OP_32_64(xor): 2139a81090bSKirill Batuzov return x ^ y; 2149a81090bSKirill Batuzov 21555c0975cSKirill Batuzov case INDEX_op_shl_i32: 21655c0975cSKirill Batuzov return (uint32_t)x << (uint32_t)y; 21755c0975cSKirill Batuzov 21855c0975cSKirill Batuzov case INDEX_op_shl_i64: 21955c0975cSKirill Batuzov return (uint64_t)x << (uint64_t)y; 22055c0975cSKirill Batuzov 22155c0975cSKirill Batuzov case INDEX_op_shr_i32: 22255c0975cSKirill Batuzov return (uint32_t)x >> (uint32_t)y; 22355c0975cSKirill Batuzov 22455c0975cSKirill Batuzov case INDEX_op_shr_i64: 22555c0975cSKirill Batuzov return (uint64_t)x >> (uint64_t)y; 22655c0975cSKirill Batuzov 22755c0975cSKirill Batuzov case INDEX_op_sar_i32: 22855c0975cSKirill Batuzov return (int32_t)x >> (int32_t)y; 22955c0975cSKirill Batuzov 23055c0975cSKirill Batuzov case INDEX_op_sar_i64: 23155c0975cSKirill Batuzov return (int64_t)x >> (int64_t)y; 23255c0975cSKirill Batuzov 23355c0975cSKirill Batuzov case INDEX_op_rotr_i32: 23425c4d9ccSRichard Henderson x = ((uint32_t)x << (32 - y)) | ((uint32_t)x >> y); 23555c0975cSKirill Batuzov return x; 23655c0975cSKirill Batuzov 23755c0975cSKirill Batuzov case INDEX_op_rotr_i64: 23825c4d9ccSRichard Henderson x = ((uint64_t)x << (64 - y)) | ((uint64_t)x >> y); 23955c0975cSKirill Batuzov return x; 24055c0975cSKirill Batuzov 24155c0975cSKirill Batuzov case INDEX_op_rotl_i32: 24225c4d9ccSRichard Henderson x = ((uint32_t)x << y) | ((uint32_t)x >> (32 - y)); 24355c0975cSKirill Batuzov return x; 24455c0975cSKirill Batuzov 24555c0975cSKirill Batuzov case INDEX_op_rotl_i64: 24625c4d9ccSRichard Henderson x = ((uint64_t)x << y) | ((uint64_t)x >> (64 - y)); 24755c0975cSKirill Batuzov return x; 24855c0975cSKirill Batuzov 24925c4d9ccSRichard Henderson CASE_OP_32_64(not): 250a640f031SKirill Batuzov return ~x; 251a640f031SKirill Batuzov 252cb25c80aSRichard Henderson CASE_OP_32_64(neg): 253cb25c80aSRichard Henderson return -x; 254cb25c80aSRichard Henderson 255cb25c80aSRichard Henderson CASE_OP_32_64(andc): 256cb25c80aSRichard Henderson return x & ~y; 257cb25c80aSRichard Henderson 258cb25c80aSRichard Henderson CASE_OP_32_64(orc): 259cb25c80aSRichard Henderson return x | ~y; 260cb25c80aSRichard Henderson 261cb25c80aSRichard Henderson CASE_OP_32_64(eqv): 262cb25c80aSRichard Henderson return ~(x ^ y); 263cb25c80aSRichard Henderson 264cb25c80aSRichard Henderson CASE_OP_32_64(nand): 265cb25c80aSRichard Henderson return ~(x & y); 266cb25c80aSRichard Henderson 267cb25c80aSRichard Henderson CASE_OP_32_64(nor): 268cb25c80aSRichard Henderson return ~(x | y); 269cb25c80aSRichard Henderson 27025c4d9ccSRichard Henderson CASE_OP_32_64(ext8s): 271a640f031SKirill Batuzov return (int8_t)x; 272a640f031SKirill Batuzov 27325c4d9ccSRichard Henderson CASE_OP_32_64(ext16s): 274a640f031SKirill Batuzov return (int16_t)x; 275a640f031SKirill Batuzov 27625c4d9ccSRichard Henderson CASE_OP_32_64(ext8u): 277a640f031SKirill Batuzov return (uint8_t)x; 278a640f031SKirill Batuzov 27925c4d9ccSRichard Henderson CASE_OP_32_64(ext16u): 280a640f031SKirill Batuzov return (uint16_t)x; 281a640f031SKirill Batuzov 282a640f031SKirill Batuzov case INDEX_op_ext32s_i64: 283a640f031SKirill Batuzov return (int32_t)x; 284a640f031SKirill Batuzov 285a640f031SKirill Batuzov case INDEX_op_ext32u_i64: 286a640f031SKirill Batuzov return (uint32_t)x; 287a640f031SKirill Batuzov 28853108fb5SKirill Batuzov default: 28953108fb5SKirill Batuzov fprintf(stderr, 29053108fb5SKirill Batuzov "Unrecognized operation %d in do_constant_folding.\n", op); 29153108fb5SKirill Batuzov tcg_abort(); 29253108fb5SKirill Batuzov } 29353108fb5SKirill Batuzov } 29453108fb5SKirill Batuzov 295fe0de7aaSBlue Swirl static TCGArg do_constant_folding(TCGOpcode op, TCGArg x, TCGArg y) 29653108fb5SKirill Batuzov { 29753108fb5SKirill Batuzov TCGArg res = do_constant_folding_2(op, x, y); 29853108fb5SKirill Batuzov if (op_bits(op) == 32) { 29953108fb5SKirill Batuzov res &= 0xffffffff; 30053108fb5SKirill Batuzov } 30153108fb5SKirill Batuzov return res; 30253108fb5SKirill Batuzov } 30353108fb5SKirill Batuzov 3049519da7eSRichard Henderson static bool do_constant_folding_cond_32(uint32_t x, uint32_t y, TCGCond c) 305f8dd19e5SAurelien Jarno { 306f8dd19e5SAurelien Jarno switch (c) { 307f8dd19e5SAurelien Jarno case TCG_COND_EQ: 3089519da7eSRichard Henderson return x == y; 309f8dd19e5SAurelien Jarno case TCG_COND_NE: 3109519da7eSRichard Henderson return x != y; 311f8dd19e5SAurelien Jarno case TCG_COND_LT: 3129519da7eSRichard Henderson return (int32_t)x < (int32_t)y; 313f8dd19e5SAurelien Jarno case TCG_COND_GE: 3149519da7eSRichard Henderson return (int32_t)x >= (int32_t)y; 315f8dd19e5SAurelien Jarno case TCG_COND_LE: 3169519da7eSRichard Henderson return (int32_t)x <= (int32_t)y; 317f8dd19e5SAurelien Jarno case TCG_COND_GT: 3189519da7eSRichard Henderson return (int32_t)x > (int32_t)y; 319f8dd19e5SAurelien Jarno case TCG_COND_LTU: 3209519da7eSRichard Henderson return x < y; 321f8dd19e5SAurelien Jarno case TCG_COND_GEU: 3229519da7eSRichard Henderson return x >= y; 323f8dd19e5SAurelien Jarno case TCG_COND_LEU: 3249519da7eSRichard Henderson return x <= y; 325f8dd19e5SAurelien Jarno case TCG_COND_GTU: 3269519da7eSRichard Henderson return x > y; 3270aed257fSRichard Henderson default: 3289519da7eSRichard Henderson tcg_abort(); 329f8dd19e5SAurelien Jarno } 3309519da7eSRichard Henderson } 3319519da7eSRichard Henderson 3329519da7eSRichard Henderson static bool do_constant_folding_cond_64(uint64_t x, uint64_t y, TCGCond c) 3339519da7eSRichard Henderson { 334f8dd19e5SAurelien Jarno switch (c) { 335f8dd19e5SAurelien Jarno case TCG_COND_EQ: 3369519da7eSRichard Henderson return x == y; 337f8dd19e5SAurelien Jarno case TCG_COND_NE: 3389519da7eSRichard Henderson return x != y; 339f8dd19e5SAurelien Jarno case TCG_COND_LT: 3409519da7eSRichard Henderson return (int64_t)x < (int64_t)y; 341f8dd19e5SAurelien Jarno case TCG_COND_GE: 3429519da7eSRichard Henderson return (int64_t)x >= (int64_t)y; 343f8dd19e5SAurelien Jarno case TCG_COND_LE: 3449519da7eSRichard Henderson return (int64_t)x <= (int64_t)y; 345f8dd19e5SAurelien Jarno case TCG_COND_GT: 3469519da7eSRichard Henderson return (int64_t)x > (int64_t)y; 347f8dd19e5SAurelien Jarno case TCG_COND_LTU: 3489519da7eSRichard Henderson return x < y; 349f8dd19e5SAurelien Jarno case TCG_COND_GEU: 3509519da7eSRichard Henderson return x >= y; 351f8dd19e5SAurelien Jarno case TCG_COND_LEU: 3529519da7eSRichard Henderson return x <= y; 353f8dd19e5SAurelien Jarno case TCG_COND_GTU: 3549519da7eSRichard Henderson return x > y; 3550aed257fSRichard Henderson default: 3569519da7eSRichard Henderson tcg_abort(); 357f8dd19e5SAurelien Jarno } 358f8dd19e5SAurelien Jarno } 3599519da7eSRichard Henderson 3609519da7eSRichard Henderson static bool do_constant_folding_cond_eq(TCGCond c) 3619519da7eSRichard Henderson { 362b336ceb6SAurelien Jarno switch (c) { 363b336ceb6SAurelien Jarno case TCG_COND_GT: 364b336ceb6SAurelien Jarno case TCG_COND_LTU: 365b336ceb6SAurelien Jarno case TCG_COND_LT: 366b336ceb6SAurelien Jarno case TCG_COND_GTU: 367b336ceb6SAurelien Jarno case TCG_COND_NE: 368b336ceb6SAurelien Jarno return 0; 369b336ceb6SAurelien Jarno case TCG_COND_GE: 370b336ceb6SAurelien Jarno case TCG_COND_GEU: 371b336ceb6SAurelien Jarno case TCG_COND_LE: 372b336ceb6SAurelien Jarno case TCG_COND_LEU: 373b336ceb6SAurelien Jarno case TCG_COND_EQ: 374b336ceb6SAurelien Jarno return 1; 3750aed257fSRichard Henderson default: 3769519da7eSRichard Henderson tcg_abort(); 377b336ceb6SAurelien Jarno } 3789519da7eSRichard Henderson } 3799519da7eSRichard Henderson 3809519da7eSRichard Henderson /* Return 2 if the condition can't be simplified, and the result 3819519da7eSRichard Henderson of the condition (0 or 1) if it can */ 3829519da7eSRichard Henderson static TCGArg do_constant_folding_cond(TCGOpcode op, TCGArg x, 3839519da7eSRichard Henderson TCGArg y, TCGCond c) 3849519da7eSRichard Henderson { 3859519da7eSRichard Henderson if (temps[x].state == TCG_TEMP_CONST && temps[y].state == TCG_TEMP_CONST) { 3869519da7eSRichard Henderson switch (op_bits(op)) { 3879519da7eSRichard Henderson case 32: 3889519da7eSRichard Henderson return do_constant_folding_cond_32(temps[x].val, temps[y].val, c); 3899519da7eSRichard Henderson case 64: 3909519da7eSRichard Henderson return do_constant_folding_cond_64(temps[x].val, temps[y].val, c); 3919519da7eSRichard Henderson default: 3929519da7eSRichard Henderson tcg_abort(); 3939519da7eSRichard Henderson } 3949519da7eSRichard Henderson } else if (temps_are_copies(x, y)) { 3959519da7eSRichard Henderson return do_constant_folding_cond_eq(c); 396b336ceb6SAurelien Jarno } else if (temps[y].state == TCG_TEMP_CONST && temps[y].val == 0) { 397b336ceb6SAurelien Jarno switch (c) { 398b336ceb6SAurelien Jarno case TCG_COND_LTU: 399b336ceb6SAurelien Jarno return 0; 400b336ceb6SAurelien Jarno case TCG_COND_GEU: 401b336ceb6SAurelien Jarno return 1; 402b336ceb6SAurelien Jarno default: 403b336ceb6SAurelien Jarno return 2; 404b336ceb6SAurelien Jarno } 405b336ceb6SAurelien Jarno } else { 406b336ceb6SAurelien Jarno return 2; 407b336ceb6SAurelien Jarno } 408f8dd19e5SAurelien Jarno } 409f8dd19e5SAurelien Jarno 4106c4382f8SRichard Henderson /* Return 2 if the condition can't be simplified, and the result 4116c4382f8SRichard Henderson of the condition (0 or 1) if it can */ 4126c4382f8SRichard Henderson static TCGArg do_constant_folding_cond2(TCGArg *p1, TCGArg *p2, TCGCond c) 4136c4382f8SRichard Henderson { 4146c4382f8SRichard Henderson TCGArg al = p1[0], ah = p1[1]; 4156c4382f8SRichard Henderson TCGArg bl = p2[0], bh = p2[1]; 4166c4382f8SRichard Henderson 4176c4382f8SRichard Henderson if (temps[bl].state == TCG_TEMP_CONST 4186c4382f8SRichard Henderson && temps[bh].state == TCG_TEMP_CONST) { 4196c4382f8SRichard Henderson uint64_t b = ((uint64_t)temps[bh].val << 32) | (uint32_t)temps[bl].val; 4206c4382f8SRichard Henderson 4216c4382f8SRichard Henderson if (temps[al].state == TCG_TEMP_CONST 4226c4382f8SRichard Henderson && temps[ah].state == TCG_TEMP_CONST) { 4236c4382f8SRichard Henderson uint64_t a; 4246c4382f8SRichard Henderson a = ((uint64_t)temps[ah].val << 32) | (uint32_t)temps[al].val; 4256c4382f8SRichard Henderson return do_constant_folding_cond_64(a, b, c); 4266c4382f8SRichard Henderson } 4276c4382f8SRichard Henderson if (b == 0) { 4286c4382f8SRichard Henderson switch (c) { 4296c4382f8SRichard Henderson case TCG_COND_LTU: 4306c4382f8SRichard Henderson return 0; 4316c4382f8SRichard Henderson case TCG_COND_GEU: 4326c4382f8SRichard Henderson return 1; 4336c4382f8SRichard Henderson default: 4346c4382f8SRichard Henderson break; 4356c4382f8SRichard Henderson } 4366c4382f8SRichard Henderson } 4376c4382f8SRichard Henderson } 4386c4382f8SRichard Henderson if (temps_are_copies(al, bl) && temps_are_copies(ah, bh)) { 4396c4382f8SRichard Henderson return do_constant_folding_cond_eq(c); 4406c4382f8SRichard Henderson } 4416c4382f8SRichard Henderson return 2; 4426c4382f8SRichard Henderson } 4436c4382f8SRichard Henderson 44424c9ae4eSRichard Henderson static bool swap_commutative(TCGArg dest, TCGArg *p1, TCGArg *p2) 44524c9ae4eSRichard Henderson { 44624c9ae4eSRichard Henderson TCGArg a1 = *p1, a2 = *p2; 44724c9ae4eSRichard Henderson int sum = 0; 44824c9ae4eSRichard Henderson sum += temps[a1].state == TCG_TEMP_CONST; 44924c9ae4eSRichard Henderson sum -= temps[a2].state == TCG_TEMP_CONST; 45024c9ae4eSRichard Henderson 45124c9ae4eSRichard Henderson /* Prefer the constant in second argument, and then the form 45224c9ae4eSRichard Henderson op a, a, b, which is better handled on non-RISC hosts. */ 45324c9ae4eSRichard Henderson if (sum > 0 || (sum == 0 && dest == a2)) { 45424c9ae4eSRichard Henderson *p1 = a2; 45524c9ae4eSRichard Henderson *p2 = a1; 45624c9ae4eSRichard Henderson return true; 45724c9ae4eSRichard Henderson } 45824c9ae4eSRichard Henderson return false; 45924c9ae4eSRichard Henderson } 46024c9ae4eSRichard Henderson 4610bfcb865SRichard Henderson static bool swap_commutative2(TCGArg *p1, TCGArg *p2) 4620bfcb865SRichard Henderson { 4630bfcb865SRichard Henderson int sum = 0; 4640bfcb865SRichard Henderson sum += temps[p1[0]].state == TCG_TEMP_CONST; 4650bfcb865SRichard Henderson sum += temps[p1[1]].state == TCG_TEMP_CONST; 4660bfcb865SRichard Henderson sum -= temps[p2[0]].state == TCG_TEMP_CONST; 4670bfcb865SRichard Henderson sum -= temps[p2[1]].state == TCG_TEMP_CONST; 4680bfcb865SRichard Henderson if (sum > 0) { 4690bfcb865SRichard Henderson TCGArg t; 4700bfcb865SRichard Henderson t = p1[0], p1[0] = p2[0], p2[0] = t; 4710bfcb865SRichard Henderson t = p1[1], p1[1] = p2[1], p2[1] = t; 4720bfcb865SRichard Henderson return true; 4730bfcb865SRichard Henderson } 4740bfcb865SRichard Henderson return false; 4750bfcb865SRichard Henderson } 4760bfcb865SRichard Henderson 47722613af4SKirill Batuzov /* Propagate constants and copies, fold constant expressions. */ 4788f2e8c07SKirill Batuzov static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, 4798f2e8c07SKirill Batuzov TCGArg *args, TCGOpDef *tcg_op_defs) 4808f2e8c07SKirill Batuzov { 481fe0de7aaSBlue Swirl int i, nb_ops, op_index, nb_temps, nb_globals, nb_call_args; 482fe0de7aaSBlue Swirl TCGOpcode op; 4838f2e8c07SKirill Batuzov const TCGOpDef *def; 4848f2e8c07SKirill Batuzov TCGArg *gen_args; 48553108fb5SKirill Batuzov TCGArg tmp; 4865d8f5363SRichard Henderson 48722613af4SKirill Batuzov /* Array VALS has an element for each temp. 48822613af4SKirill Batuzov If this temp holds a constant then its value is kept in VALS' element. 489e590d4e6SAurelien Jarno If this temp is a copy of other ones then the other copies are 490e590d4e6SAurelien Jarno available through the doubly linked circular list. */ 4918f2e8c07SKirill Batuzov 4928f2e8c07SKirill Batuzov nb_temps = s->nb_temps; 4938f2e8c07SKirill Batuzov nb_globals = s->nb_globals; 494*d193a14aSPaolo Bonzini reset_all_temps(nb_temps); 4958f2e8c07SKirill Batuzov 49692414b31SEvgeny Voevodin nb_ops = tcg_opc_ptr - s->gen_opc_buf; 4978f2e8c07SKirill Batuzov gen_args = args; 4988f2e8c07SKirill Batuzov for (op_index = 0; op_index < nb_ops; op_index++) { 49992414b31SEvgeny Voevodin op = s->gen_opc_buf[op_index]; 5008f2e8c07SKirill Batuzov def = &tcg_op_defs[op]; 50122613af4SKirill Batuzov /* Do copy propagation */ 5021ff8c541SAurelien Jarno if (op == INDEX_op_call) { 5031ff8c541SAurelien Jarno int nb_oargs = args[0] >> 16; 5041ff8c541SAurelien Jarno int nb_iargs = args[0] & 0xffff; 5051ff8c541SAurelien Jarno for (i = nb_oargs + 1; i < nb_oargs + nb_iargs + 1; i++) { 5061ff8c541SAurelien Jarno if (temps[args[i]].state == TCG_TEMP_COPY) { 5071ff8c541SAurelien Jarno args[i] = find_better_copy(s, args[i]); 5081ff8c541SAurelien Jarno } 5091ff8c541SAurelien Jarno } 5101ff8c541SAurelien Jarno } else { 51122613af4SKirill Batuzov for (i = def->nb_oargs; i < def->nb_oargs + def->nb_iargs; i++) { 51222613af4SKirill Batuzov if (temps[args[i]].state == TCG_TEMP_COPY) { 513e590d4e6SAurelien Jarno args[i] = find_better_copy(s, args[i]); 51422613af4SKirill Batuzov } 51522613af4SKirill Batuzov } 51622613af4SKirill Batuzov } 51722613af4SKirill Batuzov 51853108fb5SKirill Batuzov /* For commutative operations make constant second argument */ 51953108fb5SKirill Batuzov switch (op) { 52053108fb5SKirill Batuzov CASE_OP_32_64(add): 52153108fb5SKirill Batuzov CASE_OP_32_64(mul): 5229a81090bSKirill Batuzov CASE_OP_32_64(and): 5239a81090bSKirill Batuzov CASE_OP_32_64(or): 5249a81090bSKirill Batuzov CASE_OP_32_64(xor): 525cb25c80aSRichard Henderson CASE_OP_32_64(eqv): 526cb25c80aSRichard Henderson CASE_OP_32_64(nand): 527cb25c80aSRichard Henderson CASE_OP_32_64(nor): 52824c9ae4eSRichard Henderson swap_commutative(args[0], &args[1], &args[2]); 52953108fb5SKirill Batuzov break; 53065a7cce1SAurelien Jarno CASE_OP_32_64(brcond): 53124c9ae4eSRichard Henderson if (swap_commutative(-1, &args[0], &args[1])) { 53265a7cce1SAurelien Jarno args[2] = tcg_swap_cond(args[2]); 53365a7cce1SAurelien Jarno } 53465a7cce1SAurelien Jarno break; 53565a7cce1SAurelien Jarno CASE_OP_32_64(setcond): 53624c9ae4eSRichard Henderson if (swap_commutative(args[0], &args[1], &args[2])) { 53765a7cce1SAurelien Jarno args[3] = tcg_swap_cond(args[3]); 53865a7cce1SAurelien Jarno } 53965a7cce1SAurelien Jarno break; 540fa01a208SRichard Henderson CASE_OP_32_64(movcond): 54124c9ae4eSRichard Henderson if (swap_commutative(-1, &args[1], &args[2])) { 54224c9ae4eSRichard Henderson args[5] = tcg_swap_cond(args[5]); 543fa01a208SRichard Henderson } 5445d8f5363SRichard Henderson /* For movcond, we canonicalize the "false" input reg to match 5455d8f5363SRichard Henderson the destination reg so that the tcg backend can implement 5465d8f5363SRichard Henderson a "move if true" operation. */ 54724c9ae4eSRichard Henderson if (swap_commutative(args[0], &args[4], &args[3])) { 54824c9ae4eSRichard Henderson args[5] = tcg_invert_cond(args[5]); 5495d8f5363SRichard Henderson } 5501e484e61SRichard Henderson break; 5511e484e61SRichard Henderson case INDEX_op_add2_i32: 5521e484e61SRichard Henderson swap_commutative(args[0], &args[2], &args[4]); 5531e484e61SRichard Henderson swap_commutative(args[1], &args[3], &args[5]); 5541e484e61SRichard Henderson break; 5551414968aSRichard Henderson case INDEX_op_mulu2_i32: 5561414968aSRichard Henderson swap_commutative(args[0], &args[2], &args[3]); 5571414968aSRichard Henderson break; 5580bfcb865SRichard Henderson case INDEX_op_brcond2_i32: 5590bfcb865SRichard Henderson if (swap_commutative2(&args[0], &args[2])) { 5600bfcb865SRichard Henderson args[4] = tcg_swap_cond(args[4]); 5610bfcb865SRichard Henderson } 5620bfcb865SRichard Henderson break; 5630bfcb865SRichard Henderson case INDEX_op_setcond2_i32: 5640bfcb865SRichard Henderson if (swap_commutative2(&args[1], &args[3])) { 5650bfcb865SRichard Henderson args[5] = tcg_swap_cond(args[5]); 5660bfcb865SRichard Henderson } 5670bfcb865SRichard Henderson break; 56853108fb5SKirill Batuzov default: 56953108fb5SKirill Batuzov break; 57053108fb5SKirill Batuzov } 57153108fb5SKirill Batuzov 57201ee5282SAurelien Jarno /* Simplify expressions for "shift/rot r, 0, a => movi r, 0" */ 57301ee5282SAurelien Jarno switch (op) { 57401ee5282SAurelien Jarno CASE_OP_32_64(shl): 57501ee5282SAurelien Jarno CASE_OP_32_64(shr): 57601ee5282SAurelien Jarno CASE_OP_32_64(sar): 57701ee5282SAurelien Jarno CASE_OP_32_64(rotl): 57801ee5282SAurelien Jarno CASE_OP_32_64(rotr): 57901ee5282SAurelien Jarno if (temps[args[1]].state == TCG_TEMP_CONST 58001ee5282SAurelien Jarno && temps[args[1]].val == 0) { 58192414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = op_to_movi(op); 582e590d4e6SAurelien Jarno tcg_opt_gen_movi(gen_args, args[0], 0); 58301ee5282SAurelien Jarno args += 3; 58401ee5282SAurelien Jarno gen_args += 2; 58501ee5282SAurelien Jarno continue; 58601ee5282SAurelien Jarno } 58701ee5282SAurelien Jarno break; 58801ee5282SAurelien Jarno default: 58901ee5282SAurelien Jarno break; 59001ee5282SAurelien Jarno } 59101ee5282SAurelien Jarno 59256e49438SAurelien Jarno /* Simplify expression for "op r, a, 0 => mov r, a" cases */ 59353108fb5SKirill Batuzov switch (op) { 59453108fb5SKirill Batuzov CASE_OP_32_64(add): 59553108fb5SKirill Batuzov CASE_OP_32_64(sub): 59655c0975cSKirill Batuzov CASE_OP_32_64(shl): 59755c0975cSKirill Batuzov CASE_OP_32_64(shr): 59855c0975cSKirill Batuzov CASE_OP_32_64(sar): 59925c4d9ccSRichard Henderson CASE_OP_32_64(rotl): 60025c4d9ccSRichard Henderson CASE_OP_32_64(rotr): 60138ee188bSAurelien Jarno CASE_OP_32_64(or): 60238ee188bSAurelien Jarno CASE_OP_32_64(xor): 60353108fb5SKirill Batuzov if (temps[args[1]].state == TCG_TEMP_CONST) { 60453108fb5SKirill Batuzov /* Proceed with possible constant folding. */ 60553108fb5SKirill Batuzov break; 60653108fb5SKirill Batuzov } 60753108fb5SKirill Batuzov if (temps[args[2]].state == TCG_TEMP_CONST 60853108fb5SKirill Batuzov && temps[args[2]].val == 0) { 609e590d4e6SAurelien Jarno if (temps_are_copies(args[0], args[1])) { 61092414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = INDEX_op_nop; 61153108fb5SKirill Batuzov } else { 61292414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = op_to_mov(op); 613b80bb016SAurelien Jarno tcg_opt_gen_mov(s, gen_args, args[0], args[1]); 61453108fb5SKirill Batuzov gen_args += 2; 61553108fb5SKirill Batuzov } 616fedc0da2SAurelien Jarno args += 3; 61753108fb5SKirill Batuzov continue; 61853108fb5SKirill Batuzov } 61953108fb5SKirill Batuzov break; 62056e49438SAurelien Jarno default: 62156e49438SAurelien Jarno break; 62256e49438SAurelien Jarno } 62356e49438SAurelien Jarno 62456e49438SAurelien Jarno /* Simplify expression for "op r, a, 0 => movi r, 0" cases */ 62556e49438SAurelien Jarno switch (op) { 62661251c0cSAurelien Jarno CASE_OP_32_64(and): 62753108fb5SKirill Batuzov CASE_OP_32_64(mul): 62853108fb5SKirill Batuzov if ((temps[args[2]].state == TCG_TEMP_CONST 62953108fb5SKirill Batuzov && temps[args[2]].val == 0)) { 63092414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = op_to_movi(op); 631e590d4e6SAurelien Jarno tcg_opt_gen_movi(gen_args, args[0], 0); 63253108fb5SKirill Batuzov args += 3; 63353108fb5SKirill Batuzov gen_args += 2; 63453108fb5SKirill Batuzov continue; 63553108fb5SKirill Batuzov } 63653108fb5SKirill Batuzov break; 63756e49438SAurelien Jarno default: 63856e49438SAurelien Jarno break; 63956e49438SAurelien Jarno } 64056e49438SAurelien Jarno 64156e49438SAurelien Jarno /* Simplify expression for "op r, a, a => mov r, a" cases */ 64256e49438SAurelien Jarno switch (op) { 6439a81090bSKirill Batuzov CASE_OP_32_64(or): 6449a81090bSKirill Batuzov CASE_OP_32_64(and): 6450aba1c73SAurelien Jarno if (temps_are_copies(args[1], args[2])) { 646e590d4e6SAurelien Jarno if (temps_are_copies(args[0], args[1])) { 64792414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = INDEX_op_nop; 6489a81090bSKirill Batuzov } else { 64992414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = op_to_mov(op); 650b80bb016SAurelien Jarno tcg_opt_gen_mov(s, gen_args, args[0], args[1]); 6519a81090bSKirill Batuzov gen_args += 2; 6529a81090bSKirill Batuzov } 653fedc0da2SAurelien Jarno args += 3; 6549a81090bSKirill Batuzov continue; 6559a81090bSKirill Batuzov } 6569a81090bSKirill Batuzov break; 657fe0de7aaSBlue Swirl default: 658fe0de7aaSBlue Swirl break; 65953108fb5SKirill Batuzov } 66053108fb5SKirill Batuzov 6613c94193eSAurelien Jarno /* Simplify expression for "op r, a, a => movi r, 0" cases */ 6623c94193eSAurelien Jarno switch (op) { 6633c94193eSAurelien Jarno CASE_OP_32_64(sub): 6643c94193eSAurelien Jarno CASE_OP_32_64(xor): 6653c94193eSAurelien Jarno if (temps_are_copies(args[1], args[2])) { 66692414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = op_to_movi(op); 6673c94193eSAurelien Jarno tcg_opt_gen_movi(gen_args, args[0], 0); 6683c94193eSAurelien Jarno gen_args += 2; 6693c94193eSAurelien Jarno args += 3; 6703c94193eSAurelien Jarno continue; 6713c94193eSAurelien Jarno } 6723c94193eSAurelien Jarno break; 6733c94193eSAurelien Jarno default: 6743c94193eSAurelien Jarno break; 6753c94193eSAurelien Jarno } 6763c94193eSAurelien Jarno 67722613af4SKirill Batuzov /* Propagate constants through copy operations and do constant 67822613af4SKirill Batuzov folding. Constants will be substituted to arguments by register 67922613af4SKirill Batuzov allocator where needed and possible. Also detect copies. */ 6808f2e8c07SKirill Batuzov switch (op) { 68122613af4SKirill Batuzov CASE_OP_32_64(mov): 682e590d4e6SAurelien Jarno if (temps_are_copies(args[0], args[1])) { 68322613af4SKirill Batuzov args += 2; 68492414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = INDEX_op_nop; 68522613af4SKirill Batuzov break; 68622613af4SKirill Batuzov } 68722613af4SKirill Batuzov if (temps[args[1]].state != TCG_TEMP_CONST) { 688b80bb016SAurelien Jarno tcg_opt_gen_mov(s, gen_args, args[0], args[1]); 68922613af4SKirill Batuzov gen_args += 2; 69022613af4SKirill Batuzov args += 2; 69122613af4SKirill Batuzov break; 69222613af4SKirill Batuzov } 69322613af4SKirill Batuzov /* Source argument is constant. Rewrite the operation and 69422613af4SKirill Batuzov let movi case handle it. */ 69522613af4SKirill Batuzov op = op_to_movi(op); 69692414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = op; 69722613af4SKirill Batuzov args[1] = temps[args[1]].val; 69822613af4SKirill Batuzov /* fallthrough */ 69922613af4SKirill Batuzov CASE_OP_32_64(movi): 700e590d4e6SAurelien Jarno tcg_opt_gen_movi(gen_args, args[0], args[1]); 70122613af4SKirill Batuzov gen_args += 2; 70222613af4SKirill Batuzov args += 2; 70322613af4SKirill Batuzov break; 7046e14e91bSRichard Henderson 705a640f031SKirill Batuzov CASE_OP_32_64(not): 706cb25c80aSRichard Henderson CASE_OP_32_64(neg): 70725c4d9ccSRichard Henderson CASE_OP_32_64(ext8s): 70825c4d9ccSRichard Henderson CASE_OP_32_64(ext8u): 70925c4d9ccSRichard Henderson CASE_OP_32_64(ext16s): 71025c4d9ccSRichard Henderson CASE_OP_32_64(ext16u): 711a640f031SKirill Batuzov case INDEX_op_ext32s_i64: 712a640f031SKirill Batuzov case INDEX_op_ext32u_i64: 713a640f031SKirill Batuzov if (temps[args[1]].state == TCG_TEMP_CONST) { 71492414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = op_to_movi(op); 715a640f031SKirill Batuzov tmp = do_constant_folding(op, temps[args[1]].val, 0); 716e590d4e6SAurelien Jarno tcg_opt_gen_movi(gen_args, args[0], tmp); 717a640f031SKirill Batuzov gen_args += 2; 718a640f031SKirill Batuzov args += 2; 719a640f031SKirill Batuzov break; 7206e14e91bSRichard Henderson } 7216e14e91bSRichard Henderson goto do_default; 7226e14e91bSRichard Henderson 72353108fb5SKirill Batuzov CASE_OP_32_64(add): 72453108fb5SKirill Batuzov CASE_OP_32_64(sub): 72553108fb5SKirill Batuzov CASE_OP_32_64(mul): 7269a81090bSKirill Batuzov CASE_OP_32_64(or): 7279a81090bSKirill Batuzov CASE_OP_32_64(and): 7289a81090bSKirill Batuzov CASE_OP_32_64(xor): 72955c0975cSKirill Batuzov CASE_OP_32_64(shl): 73055c0975cSKirill Batuzov CASE_OP_32_64(shr): 73155c0975cSKirill Batuzov CASE_OP_32_64(sar): 73225c4d9ccSRichard Henderson CASE_OP_32_64(rotl): 73325c4d9ccSRichard Henderson CASE_OP_32_64(rotr): 734cb25c80aSRichard Henderson CASE_OP_32_64(andc): 735cb25c80aSRichard Henderson CASE_OP_32_64(orc): 736cb25c80aSRichard Henderson CASE_OP_32_64(eqv): 737cb25c80aSRichard Henderson CASE_OP_32_64(nand): 738cb25c80aSRichard Henderson CASE_OP_32_64(nor): 73953108fb5SKirill Batuzov if (temps[args[1]].state == TCG_TEMP_CONST 74053108fb5SKirill Batuzov && temps[args[2]].state == TCG_TEMP_CONST) { 74192414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = op_to_movi(op); 74253108fb5SKirill Batuzov tmp = do_constant_folding(op, temps[args[1]].val, 74353108fb5SKirill Batuzov temps[args[2]].val); 744e590d4e6SAurelien Jarno tcg_opt_gen_movi(gen_args, args[0], tmp); 74553108fb5SKirill Batuzov gen_args += 2; 74653108fb5SKirill Batuzov args += 3; 74753108fb5SKirill Batuzov break; 7486e14e91bSRichard Henderson } 7496e14e91bSRichard Henderson goto do_default; 7506e14e91bSRichard Henderson 7517ef55fc9SAurelien Jarno CASE_OP_32_64(deposit): 7527ef55fc9SAurelien Jarno if (temps[args[1]].state == TCG_TEMP_CONST 7537ef55fc9SAurelien Jarno && temps[args[2]].state == TCG_TEMP_CONST) { 75492414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = op_to_movi(op); 7557ef55fc9SAurelien Jarno tmp = ((1ull << args[4]) - 1); 7567ef55fc9SAurelien Jarno tmp = (temps[args[1]].val & ~(tmp << args[3])) 7577ef55fc9SAurelien Jarno | ((temps[args[2]].val & tmp) << args[3]); 7587ef55fc9SAurelien Jarno tcg_opt_gen_movi(gen_args, args[0], tmp); 7597ef55fc9SAurelien Jarno gen_args += 2; 7607ef55fc9SAurelien Jarno args += 5; 7617ef55fc9SAurelien Jarno break; 7626e14e91bSRichard Henderson } 7636e14e91bSRichard Henderson goto do_default; 7646e14e91bSRichard Henderson 765f8dd19e5SAurelien Jarno CASE_OP_32_64(setcond): 766b336ceb6SAurelien Jarno tmp = do_constant_folding_cond(op, args[1], args[2], args[3]); 767b336ceb6SAurelien Jarno if (tmp != 2) { 76892414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = op_to_movi(op); 769e590d4e6SAurelien Jarno tcg_opt_gen_movi(gen_args, args[0], tmp); 770f8dd19e5SAurelien Jarno gen_args += 2; 771f8dd19e5SAurelien Jarno args += 4; 772f8dd19e5SAurelien Jarno break; 7736e14e91bSRichard Henderson } 7746e14e91bSRichard Henderson goto do_default; 7756e14e91bSRichard Henderson 776fbeaa26cSAurelien Jarno CASE_OP_32_64(brcond): 777b336ceb6SAurelien Jarno tmp = do_constant_folding_cond(op, args[0], args[1], args[2]); 778b336ceb6SAurelien Jarno if (tmp != 2) { 779b336ceb6SAurelien Jarno if (tmp) { 780*d193a14aSPaolo Bonzini reset_all_temps(nb_temps); 78192414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = INDEX_op_br; 782fbeaa26cSAurelien Jarno gen_args[0] = args[3]; 783fbeaa26cSAurelien Jarno gen_args += 1; 784fbeaa26cSAurelien Jarno } else { 78592414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = INDEX_op_nop; 786fbeaa26cSAurelien Jarno } 787fbeaa26cSAurelien Jarno args += 4; 788fbeaa26cSAurelien Jarno break; 7896e14e91bSRichard Henderson } 7906e14e91bSRichard Henderson goto do_default; 7916e14e91bSRichard Henderson 792fa01a208SRichard Henderson CASE_OP_32_64(movcond): 793b336ceb6SAurelien Jarno tmp = do_constant_folding_cond(op, args[1], args[2], args[5]); 794b336ceb6SAurelien Jarno if (tmp != 2) { 795e590d4e6SAurelien Jarno if (temps_are_copies(args[0], args[4-tmp])) { 79692414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = INDEX_op_nop; 797fa01a208SRichard Henderson } else if (temps[args[4-tmp]].state == TCG_TEMP_CONST) { 79892414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = op_to_movi(op); 799e590d4e6SAurelien Jarno tcg_opt_gen_movi(gen_args, args[0], temps[args[4-tmp]].val); 800fa01a208SRichard Henderson gen_args += 2; 801fa01a208SRichard Henderson } else { 80292414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = op_to_mov(op); 803e590d4e6SAurelien Jarno tcg_opt_gen_mov(s, gen_args, args[0], args[4-tmp]); 804fa01a208SRichard Henderson gen_args += 2; 805fa01a208SRichard Henderson } 806fa01a208SRichard Henderson args += 6; 807fa01a208SRichard Henderson break; 8086e14e91bSRichard Henderson } 8096e14e91bSRichard Henderson goto do_default; 8106e14e91bSRichard Henderson 811212c328dSRichard Henderson case INDEX_op_add2_i32: 812212c328dSRichard Henderson case INDEX_op_sub2_i32: 813212c328dSRichard Henderson if (temps[args[2]].state == TCG_TEMP_CONST 814212c328dSRichard Henderson && temps[args[3]].state == TCG_TEMP_CONST 815212c328dSRichard Henderson && temps[args[4]].state == TCG_TEMP_CONST 816212c328dSRichard Henderson && temps[args[5]].state == TCG_TEMP_CONST) { 817212c328dSRichard Henderson uint32_t al = temps[args[2]].val; 818212c328dSRichard Henderson uint32_t ah = temps[args[3]].val; 819212c328dSRichard Henderson uint32_t bl = temps[args[4]].val; 820212c328dSRichard Henderson uint32_t bh = temps[args[5]].val; 821212c328dSRichard Henderson uint64_t a = ((uint64_t)ah << 32) | al; 822212c328dSRichard Henderson uint64_t b = ((uint64_t)bh << 32) | bl; 823212c328dSRichard Henderson TCGArg rl, rh; 824212c328dSRichard Henderson 825212c328dSRichard Henderson if (op == INDEX_op_add2_i32) { 826212c328dSRichard Henderson a += b; 827212c328dSRichard Henderson } else { 828212c328dSRichard Henderson a -= b; 829212c328dSRichard Henderson } 830212c328dSRichard Henderson 831212c328dSRichard Henderson /* We emit the extra nop when we emit the add2/sub2. */ 83292414b31SEvgeny Voevodin assert(s->gen_opc_buf[op_index + 1] == INDEX_op_nop); 833212c328dSRichard Henderson 834212c328dSRichard Henderson rl = args[0]; 835212c328dSRichard Henderson rh = args[1]; 83692414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = INDEX_op_movi_i32; 83792414b31SEvgeny Voevodin s->gen_opc_buf[++op_index] = INDEX_op_movi_i32; 838212c328dSRichard Henderson tcg_opt_gen_movi(&gen_args[0], rl, (uint32_t)a); 839212c328dSRichard Henderson tcg_opt_gen_movi(&gen_args[2], rh, (uint32_t)(a >> 32)); 840212c328dSRichard Henderson gen_args += 4; 841212c328dSRichard Henderson args += 6; 842212c328dSRichard Henderson break; 843212c328dSRichard Henderson } 844212c328dSRichard Henderson goto do_default; 845212c328dSRichard Henderson 8461414968aSRichard Henderson case INDEX_op_mulu2_i32: 8471414968aSRichard Henderson if (temps[args[2]].state == TCG_TEMP_CONST 8481414968aSRichard Henderson && temps[args[3]].state == TCG_TEMP_CONST) { 8491414968aSRichard Henderson uint32_t a = temps[args[2]].val; 8501414968aSRichard Henderson uint32_t b = temps[args[3]].val; 8511414968aSRichard Henderson uint64_t r = (uint64_t)a * b; 8521414968aSRichard Henderson TCGArg rl, rh; 8531414968aSRichard Henderson 8541414968aSRichard Henderson /* We emit the extra nop when we emit the mulu2. */ 85592414b31SEvgeny Voevodin assert(s->gen_opc_buf[op_index + 1] == INDEX_op_nop); 8561414968aSRichard Henderson 8571414968aSRichard Henderson rl = args[0]; 8581414968aSRichard Henderson rh = args[1]; 85992414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = INDEX_op_movi_i32; 86092414b31SEvgeny Voevodin s->gen_opc_buf[++op_index] = INDEX_op_movi_i32; 8611414968aSRichard Henderson tcg_opt_gen_movi(&gen_args[0], rl, (uint32_t)r); 8621414968aSRichard Henderson tcg_opt_gen_movi(&gen_args[2], rh, (uint32_t)(r >> 32)); 8631414968aSRichard Henderson gen_args += 4; 8641414968aSRichard Henderson args += 4; 8651414968aSRichard Henderson break; 8661414968aSRichard Henderson } 8671414968aSRichard Henderson goto do_default; 8681414968aSRichard Henderson 869bc1473efSRichard Henderson case INDEX_op_brcond2_i32: 8706c4382f8SRichard Henderson tmp = do_constant_folding_cond2(&args[0], &args[2], args[4]); 8716c4382f8SRichard Henderson if (tmp != 2) { 8726c4382f8SRichard Henderson if (tmp) { 873*d193a14aSPaolo Bonzini reset_all_temps(nb_temps); 87492414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = INDEX_op_br; 8756c4382f8SRichard Henderson gen_args[0] = args[5]; 8766c4382f8SRichard Henderson gen_args += 1; 8776c4382f8SRichard Henderson } else { 87892414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = INDEX_op_nop; 8796c4382f8SRichard Henderson } 8806c4382f8SRichard Henderson } else if ((args[4] == TCG_COND_LT || args[4] == TCG_COND_GE) 881bc1473efSRichard Henderson && temps[args[2]].state == TCG_TEMP_CONST 882bc1473efSRichard Henderson && temps[args[3]].state == TCG_TEMP_CONST 883bc1473efSRichard Henderson && temps[args[2]].val == 0 884bc1473efSRichard Henderson && temps[args[3]].val == 0) { 8856c4382f8SRichard Henderson /* Simplify LT/GE comparisons vs zero to a single compare 8866c4382f8SRichard Henderson vs the high word of the input. */ 887*d193a14aSPaolo Bonzini reset_all_temps(nb_temps); 88892414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = INDEX_op_brcond_i32; 889bc1473efSRichard Henderson gen_args[0] = args[1]; 890bc1473efSRichard Henderson gen_args[1] = args[3]; 891bc1473efSRichard Henderson gen_args[2] = args[4]; 892bc1473efSRichard Henderson gen_args[3] = args[5]; 893bc1473efSRichard Henderson gen_args += 4; 8946c4382f8SRichard Henderson } else { 895bc1473efSRichard Henderson goto do_default; 8966c4382f8SRichard Henderson } 8976c4382f8SRichard Henderson args += 6; 8986c4382f8SRichard Henderson break; 899bc1473efSRichard Henderson 900bc1473efSRichard Henderson case INDEX_op_setcond2_i32: 9016c4382f8SRichard Henderson tmp = do_constant_folding_cond2(&args[1], &args[3], args[5]); 9026c4382f8SRichard Henderson if (tmp != 2) { 90392414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = INDEX_op_movi_i32; 9046c4382f8SRichard Henderson tcg_opt_gen_movi(gen_args, args[0], tmp); 9056c4382f8SRichard Henderson gen_args += 2; 9066c4382f8SRichard Henderson } else if ((args[5] == TCG_COND_LT || args[5] == TCG_COND_GE) 907bc1473efSRichard Henderson && temps[args[3]].state == TCG_TEMP_CONST 908bc1473efSRichard Henderson && temps[args[4]].state == TCG_TEMP_CONST 909bc1473efSRichard Henderson && temps[args[3]].val == 0 910bc1473efSRichard Henderson && temps[args[4]].val == 0) { 9116c4382f8SRichard Henderson /* Simplify LT/GE comparisons vs zero to a single compare 9126c4382f8SRichard Henderson vs the high word of the input. */ 91392414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = INDEX_op_setcond_i32; 914bc1473efSRichard Henderson gen_args[0] = args[0]; 915bc1473efSRichard Henderson gen_args[1] = args[2]; 916bc1473efSRichard Henderson gen_args[2] = args[4]; 917bc1473efSRichard Henderson gen_args[3] = args[5]; 918bc1473efSRichard Henderson gen_args += 4; 9196c4382f8SRichard Henderson } else { 9206c4382f8SRichard Henderson goto do_default; 9216c4382f8SRichard Henderson } 922bc1473efSRichard Henderson args += 6; 923bc1473efSRichard Henderson break; 924bc1473efSRichard Henderson 9258f2e8c07SKirill Batuzov case INDEX_op_call: 92622613af4SKirill Batuzov nb_call_args = (args[0] >> 16) + (args[0] & 0xffff); 92778505279SAurelien Jarno if (!(args[nb_call_args + 1] & (TCG_CALL_NO_READ_GLOBALS | 92878505279SAurelien Jarno TCG_CALL_NO_WRITE_GLOBALS))) { 92922613af4SKirill Batuzov for (i = 0; i < nb_globals; i++) { 930e590d4e6SAurelien Jarno reset_temp(i); 93122613af4SKirill Batuzov } 93222613af4SKirill Batuzov } 93322613af4SKirill Batuzov for (i = 0; i < (args[0] >> 16); i++) { 934e590d4e6SAurelien Jarno reset_temp(args[i + 1]); 93522613af4SKirill Batuzov } 93622613af4SKirill Batuzov i = nb_call_args + 3; 9378f2e8c07SKirill Batuzov while (i) { 9388f2e8c07SKirill Batuzov *gen_args = *args; 9398f2e8c07SKirill Batuzov args++; 9408f2e8c07SKirill Batuzov gen_args++; 9418f2e8c07SKirill Batuzov i--; 9428f2e8c07SKirill Batuzov } 9438f2e8c07SKirill Batuzov break; 9446e14e91bSRichard Henderson 9458f2e8c07SKirill Batuzov default: 9466e14e91bSRichard Henderson do_default: 9476e14e91bSRichard Henderson /* Default case: we know nothing about operation (or were unable 9486e14e91bSRichard Henderson to compute the operation result) so no propagation is done. 9496e14e91bSRichard Henderson We trash everything if the operation is the end of a basic 9506e14e91bSRichard Henderson block, otherwise we only trash the output args. */ 951a2550660SAurelien Jarno if (def->flags & TCG_OPF_BB_END) { 952*d193a14aSPaolo Bonzini reset_all_temps(nb_temps); 953a2550660SAurelien Jarno } else { 95422613af4SKirill Batuzov for (i = 0; i < def->nb_oargs; i++) { 955e590d4e6SAurelien Jarno reset_temp(args[i]); 95622613af4SKirill Batuzov } 957a2550660SAurelien Jarno } 9588f2e8c07SKirill Batuzov for (i = 0; i < def->nb_args; i++) { 9598f2e8c07SKirill Batuzov gen_args[i] = args[i]; 9608f2e8c07SKirill Batuzov } 9618f2e8c07SKirill Batuzov args += def->nb_args; 9628f2e8c07SKirill Batuzov gen_args += def->nb_args; 9638f2e8c07SKirill Batuzov break; 9648f2e8c07SKirill Batuzov } 9658f2e8c07SKirill Batuzov } 9668f2e8c07SKirill Batuzov 9678f2e8c07SKirill Batuzov return gen_args; 9688f2e8c07SKirill Batuzov } 9698f2e8c07SKirill Batuzov 9708f2e8c07SKirill Batuzov TCGArg *tcg_optimize(TCGContext *s, uint16_t *tcg_opc_ptr, 9718f2e8c07SKirill Batuzov TCGArg *args, TCGOpDef *tcg_op_defs) 9728f2e8c07SKirill Batuzov { 9738f2e8c07SKirill Batuzov TCGArg *res; 9748f2e8c07SKirill Batuzov res = tcg_constant_folding(s, tcg_opc_ptr, args, tcg_op_defs); 9758f2e8c07SKirill Batuzov return res; 9768f2e8c07SKirill Batuzov } 977