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_HAS_COPY, 4322613af4SKirill Batuzov TCG_TEMP_ANY 4422613af4SKirill Batuzov } tcg_temp_state; 4522613af4SKirill Batuzov 4622613af4SKirill Batuzov struct tcg_temp_info { 4722613af4SKirill Batuzov tcg_temp_state state; 4822613af4SKirill Batuzov uint16_t prev_copy; 4922613af4SKirill Batuzov uint16_t next_copy; 5022613af4SKirill Batuzov tcg_target_ulong val; 5122613af4SKirill Batuzov }; 5222613af4SKirill Batuzov 5322613af4SKirill Batuzov static struct tcg_temp_info temps[TCG_MAX_TEMPS]; 5422613af4SKirill Batuzov 5522613af4SKirill Batuzov /* Reset TEMP's state to TCG_TEMP_ANY. If TEMP was a representative of some 5622613af4SKirill Batuzov class of equivalent temp's, a new representative should be chosen in this 5722613af4SKirill Batuzov class. */ 5822613af4SKirill Batuzov static void reset_temp(TCGArg temp, int nb_temps, int nb_globals) 5922613af4SKirill Batuzov { 6022613af4SKirill Batuzov int i; 6122613af4SKirill Batuzov TCGArg new_base = (TCGArg)-1; 6222613af4SKirill Batuzov if (temps[temp].state == TCG_TEMP_HAS_COPY) { 6322613af4SKirill Batuzov for (i = temps[temp].next_copy; i != temp; i = temps[i].next_copy) { 6422613af4SKirill Batuzov if (i >= nb_globals) { 6522613af4SKirill Batuzov temps[i].state = TCG_TEMP_HAS_COPY; 6622613af4SKirill Batuzov new_base = i; 6722613af4SKirill Batuzov break; 6822613af4SKirill Batuzov } 6922613af4SKirill Batuzov } 7022613af4SKirill Batuzov for (i = temps[temp].next_copy; i != temp; i = temps[i].next_copy) { 7122613af4SKirill Batuzov if (new_base == (TCGArg)-1) { 7222613af4SKirill Batuzov temps[i].state = TCG_TEMP_ANY; 7322613af4SKirill Batuzov } else { 7422613af4SKirill Batuzov temps[i].val = new_base; 7522613af4SKirill Batuzov } 7622613af4SKirill Batuzov } 7722613af4SKirill Batuzov temps[temps[temp].next_copy].prev_copy = temps[temp].prev_copy; 7822613af4SKirill Batuzov temps[temps[temp].prev_copy].next_copy = temps[temp].next_copy; 7922613af4SKirill Batuzov } else if (temps[temp].state == TCG_TEMP_COPY) { 8022613af4SKirill Batuzov temps[temps[temp].next_copy].prev_copy = temps[temp].prev_copy; 8122613af4SKirill Batuzov temps[temps[temp].prev_copy].next_copy = temps[temp].next_copy; 8222613af4SKirill Batuzov new_base = temps[temp].val; 8322613af4SKirill Batuzov } 8422613af4SKirill Batuzov temps[temp].state = TCG_TEMP_ANY; 8522613af4SKirill Batuzov if (new_base != (TCGArg)-1 && temps[new_base].next_copy == new_base) { 8622613af4SKirill Batuzov temps[new_base].state = TCG_TEMP_ANY; 8722613af4SKirill Batuzov } 8822613af4SKirill Batuzov } 8922613af4SKirill Batuzov 90fe0de7aaSBlue Swirl static int op_bits(TCGOpcode op) 9122613af4SKirill Batuzov { 928399ad59SRichard Henderson const TCGOpDef *def = &tcg_op_defs[op]; 938399ad59SRichard Henderson return def->flags & TCG_OPF_64BIT ? 64 : 32; 9422613af4SKirill Batuzov } 9522613af4SKirill Batuzov 96fe0de7aaSBlue Swirl static TCGOpcode op_to_movi(TCGOpcode op) 9722613af4SKirill Batuzov { 9822613af4SKirill Batuzov switch (op_bits(op)) { 9922613af4SKirill Batuzov case 32: 10022613af4SKirill Batuzov return INDEX_op_movi_i32; 10122613af4SKirill Batuzov case 64: 10222613af4SKirill Batuzov return INDEX_op_movi_i64; 10322613af4SKirill Batuzov default: 10422613af4SKirill Batuzov fprintf(stderr, "op_to_movi: unexpected return value of " 10522613af4SKirill Batuzov "function op_bits.\n"); 10622613af4SKirill Batuzov tcg_abort(); 10722613af4SKirill Batuzov } 10822613af4SKirill Batuzov } 10922613af4SKirill Batuzov 110d104bebdSAurelien Jarno static void tcg_opt_gen_mov(TCGArg *gen_args, TCGArg dst, TCGArg src, 111d104bebdSAurelien Jarno int nb_temps, int nb_globals) 11222613af4SKirill Batuzov { 11322613af4SKirill Batuzov reset_temp(dst, nb_temps, nb_globals); 11422613af4SKirill Batuzov assert(temps[src].state != TCG_TEMP_COPY); 115d104bebdSAurelien Jarno if (src >= nb_globals) { 11622613af4SKirill Batuzov assert(temps[src].state != TCG_TEMP_CONST); 11722613af4SKirill Batuzov if (temps[src].state != TCG_TEMP_HAS_COPY) { 11822613af4SKirill Batuzov temps[src].state = TCG_TEMP_HAS_COPY; 11922613af4SKirill Batuzov temps[src].next_copy = src; 12022613af4SKirill Batuzov temps[src].prev_copy = src; 12122613af4SKirill Batuzov } 12222613af4SKirill Batuzov temps[dst].state = TCG_TEMP_COPY; 12322613af4SKirill Batuzov temps[dst].val = src; 12422613af4SKirill Batuzov temps[dst].next_copy = temps[src].next_copy; 12522613af4SKirill Batuzov temps[dst].prev_copy = src; 12622613af4SKirill Batuzov temps[temps[dst].next_copy].prev_copy = dst; 12722613af4SKirill Batuzov temps[src].next_copy = dst; 12822613af4SKirill Batuzov } 12922613af4SKirill Batuzov gen_args[0] = dst; 13022613af4SKirill Batuzov gen_args[1] = src; 13122613af4SKirill Batuzov } 13222613af4SKirill Batuzov 13322613af4SKirill Batuzov static void tcg_opt_gen_movi(TCGArg *gen_args, TCGArg dst, TCGArg val, 13422613af4SKirill Batuzov int nb_temps, int nb_globals) 13522613af4SKirill Batuzov { 13622613af4SKirill Batuzov reset_temp(dst, nb_temps, nb_globals); 13722613af4SKirill Batuzov temps[dst].state = TCG_TEMP_CONST; 13822613af4SKirill Batuzov temps[dst].val = val; 13922613af4SKirill Batuzov gen_args[0] = dst; 14022613af4SKirill Batuzov gen_args[1] = val; 14122613af4SKirill Batuzov } 14222613af4SKirill Batuzov 143fe0de7aaSBlue Swirl static TCGOpcode op_to_mov(TCGOpcode op) 14453108fb5SKirill Batuzov { 14553108fb5SKirill Batuzov switch (op_bits(op)) { 14653108fb5SKirill Batuzov case 32: 14753108fb5SKirill Batuzov return INDEX_op_mov_i32; 14853108fb5SKirill Batuzov case 64: 14953108fb5SKirill Batuzov return INDEX_op_mov_i64; 15053108fb5SKirill Batuzov default: 15153108fb5SKirill Batuzov fprintf(stderr, "op_to_mov: unexpected return value of " 15253108fb5SKirill Batuzov "function op_bits.\n"); 15353108fb5SKirill Batuzov tcg_abort(); 15453108fb5SKirill Batuzov } 15553108fb5SKirill Batuzov } 15653108fb5SKirill Batuzov 157fe0de7aaSBlue Swirl static TCGArg do_constant_folding_2(TCGOpcode op, TCGArg x, TCGArg y) 15853108fb5SKirill Batuzov { 15953108fb5SKirill Batuzov switch (op) { 16053108fb5SKirill Batuzov CASE_OP_32_64(add): 16153108fb5SKirill Batuzov return x + y; 16253108fb5SKirill Batuzov 16353108fb5SKirill Batuzov CASE_OP_32_64(sub): 16453108fb5SKirill Batuzov return x - y; 16553108fb5SKirill Batuzov 16653108fb5SKirill Batuzov CASE_OP_32_64(mul): 16753108fb5SKirill Batuzov return x * y; 16853108fb5SKirill Batuzov 1699a81090bSKirill Batuzov CASE_OP_32_64(and): 1709a81090bSKirill Batuzov return x & y; 1719a81090bSKirill Batuzov 1729a81090bSKirill Batuzov CASE_OP_32_64(or): 1739a81090bSKirill Batuzov return x | y; 1749a81090bSKirill Batuzov 1759a81090bSKirill Batuzov CASE_OP_32_64(xor): 1769a81090bSKirill Batuzov return x ^ y; 1779a81090bSKirill Batuzov 17855c0975cSKirill Batuzov case INDEX_op_shl_i32: 17955c0975cSKirill Batuzov return (uint32_t)x << (uint32_t)y; 18055c0975cSKirill Batuzov 18155c0975cSKirill Batuzov case INDEX_op_shl_i64: 18255c0975cSKirill Batuzov return (uint64_t)x << (uint64_t)y; 18355c0975cSKirill Batuzov 18455c0975cSKirill Batuzov case INDEX_op_shr_i32: 18555c0975cSKirill Batuzov return (uint32_t)x >> (uint32_t)y; 18655c0975cSKirill Batuzov 18755c0975cSKirill Batuzov case INDEX_op_shr_i64: 18855c0975cSKirill Batuzov return (uint64_t)x >> (uint64_t)y; 18955c0975cSKirill Batuzov 19055c0975cSKirill Batuzov case INDEX_op_sar_i32: 19155c0975cSKirill Batuzov return (int32_t)x >> (int32_t)y; 19255c0975cSKirill Batuzov 19355c0975cSKirill Batuzov case INDEX_op_sar_i64: 19455c0975cSKirill Batuzov return (int64_t)x >> (int64_t)y; 19555c0975cSKirill Batuzov 19655c0975cSKirill Batuzov case INDEX_op_rotr_i32: 19725c4d9ccSRichard Henderson x = ((uint32_t)x << (32 - y)) | ((uint32_t)x >> y); 19855c0975cSKirill Batuzov return x; 19955c0975cSKirill Batuzov 20055c0975cSKirill Batuzov case INDEX_op_rotr_i64: 20125c4d9ccSRichard Henderson x = ((uint64_t)x << (64 - y)) | ((uint64_t)x >> y); 20255c0975cSKirill Batuzov return x; 20355c0975cSKirill Batuzov 20455c0975cSKirill Batuzov case INDEX_op_rotl_i32: 20525c4d9ccSRichard Henderson x = ((uint32_t)x << y) | ((uint32_t)x >> (32 - y)); 20655c0975cSKirill Batuzov return x; 20755c0975cSKirill Batuzov 20855c0975cSKirill Batuzov case INDEX_op_rotl_i64: 20925c4d9ccSRichard Henderson x = ((uint64_t)x << y) | ((uint64_t)x >> (64 - y)); 21055c0975cSKirill Batuzov return x; 21155c0975cSKirill Batuzov 21225c4d9ccSRichard Henderson CASE_OP_32_64(not): 213a640f031SKirill Batuzov return ~x; 214a640f031SKirill Batuzov 215cb25c80aSRichard Henderson CASE_OP_32_64(neg): 216cb25c80aSRichard Henderson return -x; 217cb25c80aSRichard Henderson 218cb25c80aSRichard Henderson CASE_OP_32_64(andc): 219cb25c80aSRichard Henderson return x & ~y; 220cb25c80aSRichard Henderson 221cb25c80aSRichard Henderson CASE_OP_32_64(orc): 222cb25c80aSRichard Henderson return x | ~y; 223cb25c80aSRichard Henderson 224cb25c80aSRichard Henderson CASE_OP_32_64(eqv): 225cb25c80aSRichard Henderson return ~(x ^ y); 226cb25c80aSRichard Henderson 227cb25c80aSRichard Henderson CASE_OP_32_64(nand): 228cb25c80aSRichard Henderson return ~(x & y); 229cb25c80aSRichard Henderson 230cb25c80aSRichard Henderson CASE_OP_32_64(nor): 231cb25c80aSRichard Henderson return ~(x | y); 232cb25c80aSRichard Henderson 23325c4d9ccSRichard Henderson CASE_OP_32_64(ext8s): 234a640f031SKirill Batuzov return (int8_t)x; 235a640f031SKirill Batuzov 23625c4d9ccSRichard Henderson CASE_OP_32_64(ext16s): 237a640f031SKirill Batuzov return (int16_t)x; 238a640f031SKirill Batuzov 23925c4d9ccSRichard Henderson CASE_OP_32_64(ext8u): 240a640f031SKirill Batuzov return (uint8_t)x; 241a640f031SKirill Batuzov 24225c4d9ccSRichard Henderson CASE_OP_32_64(ext16u): 243a640f031SKirill Batuzov return (uint16_t)x; 244a640f031SKirill Batuzov 245a640f031SKirill Batuzov case INDEX_op_ext32s_i64: 246a640f031SKirill Batuzov return (int32_t)x; 247a640f031SKirill Batuzov 248a640f031SKirill Batuzov case INDEX_op_ext32u_i64: 249a640f031SKirill Batuzov return (uint32_t)x; 250a640f031SKirill Batuzov 25153108fb5SKirill Batuzov default: 25253108fb5SKirill Batuzov fprintf(stderr, 25353108fb5SKirill Batuzov "Unrecognized operation %d in do_constant_folding.\n", op); 25453108fb5SKirill Batuzov tcg_abort(); 25553108fb5SKirill Batuzov } 25653108fb5SKirill Batuzov } 25753108fb5SKirill Batuzov 258fe0de7aaSBlue Swirl static TCGArg do_constant_folding(TCGOpcode op, TCGArg x, TCGArg y) 25953108fb5SKirill Batuzov { 26053108fb5SKirill Batuzov TCGArg res = do_constant_folding_2(op, x, y); 26153108fb5SKirill Batuzov if (op_bits(op) == 32) { 26253108fb5SKirill Batuzov res &= 0xffffffff; 26353108fb5SKirill Batuzov } 26453108fb5SKirill Batuzov return res; 26553108fb5SKirill Batuzov } 26653108fb5SKirill Batuzov 267f8dd19e5SAurelien Jarno static TCGArg do_constant_folding_cond(TCGOpcode op, TCGArg x, 268f8dd19e5SAurelien Jarno TCGArg y, TCGCond c) 269f8dd19e5SAurelien Jarno { 270f8dd19e5SAurelien Jarno switch (op_bits(op)) { 271f8dd19e5SAurelien Jarno case 32: 272f8dd19e5SAurelien Jarno switch (c) { 273f8dd19e5SAurelien Jarno case TCG_COND_EQ: 274f8dd19e5SAurelien Jarno return (uint32_t)x == (uint32_t)y; 275f8dd19e5SAurelien Jarno case TCG_COND_NE: 276f8dd19e5SAurelien Jarno return (uint32_t)x != (uint32_t)y; 277f8dd19e5SAurelien Jarno case TCG_COND_LT: 278f8dd19e5SAurelien Jarno return (int32_t)x < (int32_t)y; 279f8dd19e5SAurelien Jarno case TCG_COND_GE: 280f8dd19e5SAurelien Jarno return (int32_t)x >= (int32_t)y; 281f8dd19e5SAurelien Jarno case TCG_COND_LE: 282f8dd19e5SAurelien Jarno return (int32_t)x <= (int32_t)y; 283f8dd19e5SAurelien Jarno case TCG_COND_GT: 284f8dd19e5SAurelien Jarno return (int32_t)x > (int32_t)y; 285f8dd19e5SAurelien Jarno case TCG_COND_LTU: 286f8dd19e5SAurelien Jarno return (uint32_t)x < (uint32_t)y; 287f8dd19e5SAurelien Jarno case TCG_COND_GEU: 288f8dd19e5SAurelien Jarno return (uint32_t)x >= (uint32_t)y; 289f8dd19e5SAurelien Jarno case TCG_COND_LEU: 290f8dd19e5SAurelien Jarno return (uint32_t)x <= (uint32_t)y; 291f8dd19e5SAurelien Jarno case TCG_COND_GTU: 292f8dd19e5SAurelien Jarno return (uint32_t)x > (uint32_t)y; 293f8dd19e5SAurelien Jarno } 294f8dd19e5SAurelien Jarno break; 295f8dd19e5SAurelien Jarno case 64: 296f8dd19e5SAurelien Jarno switch (c) { 297f8dd19e5SAurelien Jarno case TCG_COND_EQ: 298f8dd19e5SAurelien Jarno return (uint64_t)x == (uint64_t)y; 299f8dd19e5SAurelien Jarno case TCG_COND_NE: 300f8dd19e5SAurelien Jarno return (uint64_t)x != (uint64_t)y; 301f8dd19e5SAurelien Jarno case TCG_COND_LT: 302f8dd19e5SAurelien Jarno return (int64_t)x < (int64_t)y; 303f8dd19e5SAurelien Jarno case TCG_COND_GE: 304f8dd19e5SAurelien Jarno return (int64_t)x >= (int64_t)y; 305f8dd19e5SAurelien Jarno case TCG_COND_LE: 306f8dd19e5SAurelien Jarno return (int64_t)x <= (int64_t)y; 307f8dd19e5SAurelien Jarno case TCG_COND_GT: 308f8dd19e5SAurelien Jarno return (int64_t)x > (int64_t)y; 309f8dd19e5SAurelien Jarno case TCG_COND_LTU: 310f8dd19e5SAurelien Jarno return (uint64_t)x < (uint64_t)y; 311f8dd19e5SAurelien Jarno case TCG_COND_GEU: 312f8dd19e5SAurelien Jarno return (uint64_t)x >= (uint64_t)y; 313f8dd19e5SAurelien Jarno case TCG_COND_LEU: 314f8dd19e5SAurelien Jarno return (uint64_t)x <= (uint64_t)y; 315f8dd19e5SAurelien Jarno case TCG_COND_GTU: 316f8dd19e5SAurelien Jarno return (uint64_t)x > (uint64_t)y; 317f8dd19e5SAurelien Jarno } 318f8dd19e5SAurelien Jarno break; 319f8dd19e5SAurelien Jarno } 320f8dd19e5SAurelien Jarno 321f8dd19e5SAurelien Jarno fprintf(stderr, 322f8dd19e5SAurelien Jarno "Unrecognized bitness %d or condition %d in " 323f8dd19e5SAurelien Jarno "do_constant_folding_cond.\n", op_bits(op), c); 324f8dd19e5SAurelien Jarno tcg_abort(); 325f8dd19e5SAurelien Jarno } 326f8dd19e5SAurelien Jarno 327f8dd19e5SAurelien Jarno 32822613af4SKirill Batuzov /* Propagate constants and copies, fold constant expressions. */ 3298f2e8c07SKirill Batuzov static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, 3308f2e8c07SKirill Batuzov TCGArg *args, TCGOpDef *tcg_op_defs) 3318f2e8c07SKirill Batuzov { 332fe0de7aaSBlue Swirl int i, nb_ops, op_index, nb_temps, nb_globals, nb_call_args; 333fe0de7aaSBlue Swirl TCGOpcode op; 3348f2e8c07SKirill Batuzov const TCGOpDef *def; 3358f2e8c07SKirill Batuzov TCGArg *gen_args; 33653108fb5SKirill Batuzov TCGArg tmp; 33722613af4SKirill Batuzov /* Array VALS has an element for each temp. 33822613af4SKirill Batuzov If this temp holds a constant then its value is kept in VALS' element. 33922613af4SKirill Batuzov If this temp is a copy of other ones then this equivalence class' 34022613af4SKirill Batuzov representative is kept in VALS' element. 34122613af4SKirill Batuzov If this temp is neither copy nor constant then corresponding VALS' 34222613af4SKirill Batuzov element is unused. */ 3438f2e8c07SKirill Batuzov 3448f2e8c07SKirill Batuzov nb_temps = s->nb_temps; 3458f2e8c07SKirill Batuzov nb_globals = s->nb_globals; 34622613af4SKirill Batuzov memset(temps, 0, nb_temps * sizeof(struct tcg_temp_info)); 3478f2e8c07SKirill Batuzov 3488f2e8c07SKirill Batuzov nb_ops = tcg_opc_ptr - gen_opc_buf; 3498f2e8c07SKirill Batuzov gen_args = args; 3508f2e8c07SKirill Batuzov for (op_index = 0; op_index < nb_ops; op_index++) { 3518f2e8c07SKirill Batuzov op = gen_opc_buf[op_index]; 3528f2e8c07SKirill Batuzov def = &tcg_op_defs[op]; 35322613af4SKirill Batuzov /* Do copy propagation */ 35422613af4SKirill Batuzov if (!(def->flags & (TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS))) { 35522613af4SKirill Batuzov assert(op != INDEX_op_call); 35622613af4SKirill Batuzov for (i = def->nb_oargs; i < def->nb_oargs + def->nb_iargs; i++) { 35722613af4SKirill Batuzov if (temps[args[i]].state == TCG_TEMP_COPY) { 35822613af4SKirill Batuzov args[i] = temps[args[i]].val; 35922613af4SKirill Batuzov } 36022613af4SKirill Batuzov } 36122613af4SKirill Batuzov } 36222613af4SKirill Batuzov 36353108fb5SKirill Batuzov /* For commutative operations make constant second argument */ 36453108fb5SKirill Batuzov switch (op) { 36553108fb5SKirill Batuzov CASE_OP_32_64(add): 36653108fb5SKirill Batuzov CASE_OP_32_64(mul): 3679a81090bSKirill Batuzov CASE_OP_32_64(and): 3689a81090bSKirill Batuzov CASE_OP_32_64(or): 3699a81090bSKirill Batuzov CASE_OP_32_64(xor): 370cb25c80aSRichard Henderson CASE_OP_32_64(eqv): 371cb25c80aSRichard Henderson CASE_OP_32_64(nand): 372cb25c80aSRichard Henderson CASE_OP_32_64(nor): 37353108fb5SKirill Batuzov if (temps[args[1]].state == TCG_TEMP_CONST) { 37453108fb5SKirill Batuzov tmp = args[1]; 37553108fb5SKirill Batuzov args[1] = args[2]; 37653108fb5SKirill Batuzov args[2] = tmp; 37753108fb5SKirill Batuzov } 37853108fb5SKirill Batuzov break; 37965a7cce1SAurelien Jarno CASE_OP_32_64(brcond): 38065a7cce1SAurelien Jarno if (temps[args[0]].state == TCG_TEMP_CONST 38165a7cce1SAurelien Jarno && temps[args[1]].state != TCG_TEMP_CONST) { 38265a7cce1SAurelien Jarno tmp = args[0]; 38365a7cce1SAurelien Jarno args[0] = args[1]; 38465a7cce1SAurelien Jarno args[1] = tmp; 38565a7cce1SAurelien Jarno args[2] = tcg_swap_cond(args[2]); 38665a7cce1SAurelien Jarno } 38765a7cce1SAurelien Jarno break; 38865a7cce1SAurelien Jarno CASE_OP_32_64(setcond): 38965a7cce1SAurelien Jarno if (temps[args[1]].state == TCG_TEMP_CONST 39065a7cce1SAurelien Jarno && temps[args[2]].state != TCG_TEMP_CONST) { 39165a7cce1SAurelien Jarno tmp = args[1]; 39265a7cce1SAurelien Jarno args[1] = args[2]; 39365a7cce1SAurelien Jarno args[2] = tmp; 39465a7cce1SAurelien Jarno args[3] = tcg_swap_cond(args[3]); 39565a7cce1SAurelien Jarno } 39665a7cce1SAurelien Jarno break; 39753108fb5SKirill Batuzov default: 39853108fb5SKirill Batuzov break; 39953108fb5SKirill Batuzov } 40053108fb5SKirill Batuzov 40101ee5282SAurelien Jarno /* Simplify expressions for "shift/rot r, 0, a => movi r, 0" */ 40201ee5282SAurelien Jarno switch (op) { 40301ee5282SAurelien Jarno CASE_OP_32_64(shl): 40401ee5282SAurelien Jarno CASE_OP_32_64(shr): 40501ee5282SAurelien Jarno CASE_OP_32_64(sar): 40601ee5282SAurelien Jarno CASE_OP_32_64(rotl): 40701ee5282SAurelien Jarno CASE_OP_32_64(rotr): 40801ee5282SAurelien Jarno if (temps[args[1]].state == TCG_TEMP_CONST 40901ee5282SAurelien Jarno && temps[args[1]].val == 0) { 41001ee5282SAurelien Jarno gen_opc_buf[op_index] = op_to_movi(op); 41101ee5282SAurelien Jarno tcg_opt_gen_movi(gen_args, args[0], 0, nb_temps, nb_globals); 41201ee5282SAurelien Jarno args += 3; 41301ee5282SAurelien Jarno gen_args += 2; 41401ee5282SAurelien Jarno continue; 41501ee5282SAurelien Jarno } 41601ee5282SAurelien Jarno break; 41701ee5282SAurelien Jarno default: 41801ee5282SAurelien Jarno break; 41901ee5282SAurelien Jarno } 42001ee5282SAurelien Jarno 42156e49438SAurelien Jarno /* Simplify expression for "op r, a, 0 => mov r, a" cases */ 42253108fb5SKirill Batuzov switch (op) { 42353108fb5SKirill Batuzov CASE_OP_32_64(add): 42453108fb5SKirill Batuzov CASE_OP_32_64(sub): 42555c0975cSKirill Batuzov CASE_OP_32_64(shl): 42655c0975cSKirill Batuzov CASE_OP_32_64(shr): 42755c0975cSKirill Batuzov CASE_OP_32_64(sar): 42825c4d9ccSRichard Henderson CASE_OP_32_64(rotl): 42925c4d9ccSRichard Henderson CASE_OP_32_64(rotr): 43038ee188bSAurelien Jarno CASE_OP_32_64(or): 43138ee188bSAurelien Jarno CASE_OP_32_64(xor): 43253108fb5SKirill Batuzov if (temps[args[1]].state == TCG_TEMP_CONST) { 43353108fb5SKirill Batuzov /* Proceed with possible constant folding. */ 43453108fb5SKirill Batuzov break; 43553108fb5SKirill Batuzov } 43653108fb5SKirill Batuzov if (temps[args[2]].state == TCG_TEMP_CONST 43753108fb5SKirill Batuzov && temps[args[2]].val == 0) { 43853108fb5SKirill Batuzov if ((temps[args[0]].state == TCG_TEMP_COPY 43953108fb5SKirill Batuzov && temps[args[0]].val == args[1]) 44053108fb5SKirill Batuzov || args[0] == args[1]) { 44153108fb5SKirill Batuzov gen_opc_buf[op_index] = INDEX_op_nop; 44253108fb5SKirill Batuzov } else { 44353108fb5SKirill Batuzov gen_opc_buf[op_index] = op_to_mov(op); 444d104bebdSAurelien Jarno tcg_opt_gen_mov(gen_args, args[0], args[1], 44553108fb5SKirill Batuzov nb_temps, nb_globals); 44653108fb5SKirill Batuzov gen_args += 2; 44753108fb5SKirill Batuzov } 448fedc0da2SAurelien Jarno args += 3; 44953108fb5SKirill Batuzov continue; 45053108fb5SKirill Batuzov } 45153108fb5SKirill Batuzov break; 45256e49438SAurelien Jarno default: 45356e49438SAurelien Jarno break; 45456e49438SAurelien Jarno } 45556e49438SAurelien Jarno 45656e49438SAurelien Jarno /* Simplify expression for "op r, a, 0 => movi r, 0" cases */ 45756e49438SAurelien Jarno switch (op) { 45861251c0cSAurelien Jarno CASE_OP_32_64(and): 45953108fb5SKirill Batuzov CASE_OP_32_64(mul): 46053108fb5SKirill Batuzov if ((temps[args[2]].state == TCG_TEMP_CONST 46153108fb5SKirill Batuzov && temps[args[2]].val == 0)) { 46253108fb5SKirill Batuzov gen_opc_buf[op_index] = op_to_movi(op); 46353108fb5SKirill Batuzov tcg_opt_gen_movi(gen_args, args[0], 0, nb_temps, nb_globals); 46453108fb5SKirill Batuzov args += 3; 46553108fb5SKirill Batuzov gen_args += 2; 46653108fb5SKirill Batuzov continue; 46753108fb5SKirill Batuzov } 46853108fb5SKirill Batuzov break; 46956e49438SAurelien Jarno default: 47056e49438SAurelien Jarno break; 47156e49438SAurelien Jarno } 47256e49438SAurelien Jarno 47356e49438SAurelien Jarno /* Simplify expression for "op r, a, a => mov r, a" cases */ 47456e49438SAurelien Jarno switch (op) { 4759a81090bSKirill Batuzov CASE_OP_32_64(or): 4769a81090bSKirill Batuzov CASE_OP_32_64(and): 4779a81090bSKirill Batuzov if (args[1] == args[2]) { 4789a81090bSKirill Batuzov if (args[1] == args[0]) { 4799a81090bSKirill Batuzov gen_opc_buf[op_index] = INDEX_op_nop; 4809a81090bSKirill Batuzov } else { 4819a81090bSKirill Batuzov gen_opc_buf[op_index] = op_to_mov(op); 482d104bebdSAurelien Jarno tcg_opt_gen_mov(gen_args, args[0], args[1], nb_temps, 4839a81090bSKirill Batuzov nb_globals); 4849a81090bSKirill Batuzov gen_args += 2; 4859a81090bSKirill Batuzov } 486fedc0da2SAurelien Jarno args += 3; 4879a81090bSKirill Batuzov continue; 4889a81090bSKirill Batuzov } 4899a81090bSKirill Batuzov break; 490fe0de7aaSBlue Swirl default: 491fe0de7aaSBlue Swirl break; 49253108fb5SKirill Batuzov } 49353108fb5SKirill Batuzov 49422613af4SKirill Batuzov /* Propagate constants through copy operations and do constant 49522613af4SKirill Batuzov folding. Constants will be substituted to arguments by register 49622613af4SKirill Batuzov allocator where needed and possible. Also detect copies. */ 4978f2e8c07SKirill Batuzov switch (op) { 49822613af4SKirill Batuzov CASE_OP_32_64(mov): 49922613af4SKirill Batuzov if ((temps[args[1]].state == TCG_TEMP_COPY 50022613af4SKirill Batuzov && temps[args[1]].val == args[0]) 50122613af4SKirill Batuzov || args[0] == args[1]) { 50222613af4SKirill Batuzov args += 2; 50322613af4SKirill Batuzov gen_opc_buf[op_index] = INDEX_op_nop; 50422613af4SKirill Batuzov break; 50522613af4SKirill Batuzov } 50622613af4SKirill Batuzov if (temps[args[1]].state != TCG_TEMP_CONST) { 507d104bebdSAurelien Jarno tcg_opt_gen_mov(gen_args, args[0], args[1], 50822613af4SKirill Batuzov nb_temps, nb_globals); 50922613af4SKirill Batuzov gen_args += 2; 51022613af4SKirill Batuzov args += 2; 51122613af4SKirill Batuzov break; 51222613af4SKirill Batuzov } 51322613af4SKirill Batuzov /* Source argument is constant. Rewrite the operation and 51422613af4SKirill Batuzov let movi case handle it. */ 51522613af4SKirill Batuzov op = op_to_movi(op); 51622613af4SKirill Batuzov gen_opc_buf[op_index] = op; 51722613af4SKirill Batuzov args[1] = temps[args[1]].val; 51822613af4SKirill Batuzov /* fallthrough */ 51922613af4SKirill Batuzov CASE_OP_32_64(movi): 52022613af4SKirill Batuzov tcg_opt_gen_movi(gen_args, args[0], args[1], nb_temps, nb_globals); 52122613af4SKirill Batuzov gen_args += 2; 52222613af4SKirill Batuzov args += 2; 52322613af4SKirill Batuzov break; 524a640f031SKirill Batuzov CASE_OP_32_64(not): 525cb25c80aSRichard Henderson CASE_OP_32_64(neg): 52625c4d9ccSRichard Henderson CASE_OP_32_64(ext8s): 52725c4d9ccSRichard Henderson CASE_OP_32_64(ext8u): 52825c4d9ccSRichard Henderson CASE_OP_32_64(ext16s): 52925c4d9ccSRichard Henderson CASE_OP_32_64(ext16u): 530a640f031SKirill Batuzov case INDEX_op_ext32s_i64: 531a640f031SKirill Batuzov case INDEX_op_ext32u_i64: 532a640f031SKirill Batuzov if (temps[args[1]].state == TCG_TEMP_CONST) { 533a640f031SKirill Batuzov gen_opc_buf[op_index] = op_to_movi(op); 534a640f031SKirill Batuzov tmp = do_constant_folding(op, temps[args[1]].val, 0); 535a640f031SKirill Batuzov tcg_opt_gen_movi(gen_args, args[0], tmp, nb_temps, nb_globals); 536a640f031SKirill Batuzov } else { 537a640f031SKirill Batuzov reset_temp(args[0], nb_temps, nb_globals); 538a640f031SKirill Batuzov gen_args[0] = args[0]; 539a640f031SKirill Batuzov gen_args[1] = args[1]; 540fedc0da2SAurelien Jarno } 541a640f031SKirill Batuzov gen_args += 2; 542a640f031SKirill Batuzov args += 2; 543a640f031SKirill Batuzov break; 54453108fb5SKirill Batuzov CASE_OP_32_64(add): 54553108fb5SKirill Batuzov CASE_OP_32_64(sub): 54653108fb5SKirill Batuzov CASE_OP_32_64(mul): 5479a81090bSKirill Batuzov CASE_OP_32_64(or): 5489a81090bSKirill Batuzov CASE_OP_32_64(and): 5499a81090bSKirill Batuzov CASE_OP_32_64(xor): 55055c0975cSKirill Batuzov CASE_OP_32_64(shl): 55155c0975cSKirill Batuzov CASE_OP_32_64(shr): 55255c0975cSKirill Batuzov CASE_OP_32_64(sar): 55325c4d9ccSRichard Henderson CASE_OP_32_64(rotl): 55425c4d9ccSRichard Henderson CASE_OP_32_64(rotr): 555cb25c80aSRichard Henderson CASE_OP_32_64(andc): 556cb25c80aSRichard Henderson CASE_OP_32_64(orc): 557cb25c80aSRichard Henderson CASE_OP_32_64(eqv): 558cb25c80aSRichard Henderson CASE_OP_32_64(nand): 559cb25c80aSRichard Henderson CASE_OP_32_64(nor): 56053108fb5SKirill Batuzov if (temps[args[1]].state == TCG_TEMP_CONST 56153108fb5SKirill Batuzov && temps[args[2]].state == TCG_TEMP_CONST) { 56253108fb5SKirill Batuzov gen_opc_buf[op_index] = op_to_movi(op); 56353108fb5SKirill Batuzov tmp = do_constant_folding(op, temps[args[1]].val, 56453108fb5SKirill Batuzov temps[args[2]].val); 56553108fb5SKirill Batuzov tcg_opt_gen_movi(gen_args, args[0], tmp, nb_temps, nb_globals); 56653108fb5SKirill Batuzov gen_args += 2; 56753108fb5SKirill Batuzov } else { 56853108fb5SKirill Batuzov reset_temp(args[0], nb_temps, nb_globals); 56953108fb5SKirill Batuzov gen_args[0] = args[0]; 57053108fb5SKirill Batuzov gen_args[1] = args[1]; 57153108fb5SKirill Batuzov gen_args[2] = args[2]; 57253108fb5SKirill Batuzov gen_args += 3; 573fedc0da2SAurelien Jarno } 57453108fb5SKirill Batuzov args += 3; 57553108fb5SKirill Batuzov break; 576f8dd19e5SAurelien Jarno CASE_OP_32_64(setcond): 577f8dd19e5SAurelien Jarno if (temps[args[1]].state == TCG_TEMP_CONST 578f8dd19e5SAurelien Jarno && temps[args[2]].state == TCG_TEMP_CONST) { 579f8dd19e5SAurelien Jarno gen_opc_buf[op_index] = op_to_movi(op); 580f8dd19e5SAurelien Jarno tmp = do_constant_folding_cond(op, temps[args[1]].val, 581f8dd19e5SAurelien Jarno temps[args[2]].val, args[3]); 582f8dd19e5SAurelien Jarno tcg_opt_gen_movi(gen_args, args[0], tmp, nb_temps, nb_globals); 583f8dd19e5SAurelien Jarno gen_args += 2; 584f8dd19e5SAurelien Jarno } else { 585f8dd19e5SAurelien Jarno reset_temp(args[0], nb_temps, nb_globals); 586f8dd19e5SAurelien Jarno gen_args[0] = args[0]; 587f8dd19e5SAurelien Jarno gen_args[1] = args[1]; 588f8dd19e5SAurelien Jarno gen_args[2] = args[2]; 589f8dd19e5SAurelien Jarno gen_args[3] = args[3]; 590f8dd19e5SAurelien Jarno gen_args += 4; 591fedc0da2SAurelien Jarno } 592f8dd19e5SAurelien Jarno args += 4; 593f8dd19e5SAurelien Jarno break; 594fbeaa26cSAurelien Jarno CASE_OP_32_64(brcond): 595fbeaa26cSAurelien Jarno if (temps[args[0]].state == TCG_TEMP_CONST 596fbeaa26cSAurelien Jarno && temps[args[1]].state == TCG_TEMP_CONST) { 597fbeaa26cSAurelien Jarno if (do_constant_folding_cond(op, temps[args[0]].val, 598fbeaa26cSAurelien Jarno temps[args[1]].val, args[2])) { 599fbeaa26cSAurelien Jarno memset(temps, 0, nb_temps * sizeof(struct tcg_temp_info)); 600fbeaa26cSAurelien Jarno gen_opc_buf[op_index] = INDEX_op_br; 601fbeaa26cSAurelien Jarno gen_args[0] = args[3]; 602fbeaa26cSAurelien Jarno gen_args += 1; 603fbeaa26cSAurelien Jarno } else { 604fbeaa26cSAurelien Jarno gen_opc_buf[op_index] = INDEX_op_nop; 605fbeaa26cSAurelien Jarno } 606fbeaa26cSAurelien Jarno } else { 607fbeaa26cSAurelien Jarno memset(temps, 0, nb_temps * sizeof(struct tcg_temp_info)); 608fbeaa26cSAurelien Jarno reset_temp(args[0], nb_temps, nb_globals); 609fbeaa26cSAurelien Jarno gen_args[0] = args[0]; 610fbeaa26cSAurelien Jarno gen_args[1] = args[1]; 611fbeaa26cSAurelien Jarno gen_args[2] = args[2]; 612fbeaa26cSAurelien Jarno gen_args[3] = args[3]; 613fbeaa26cSAurelien Jarno gen_args += 4; 614fedc0da2SAurelien Jarno } 615fbeaa26cSAurelien Jarno args += 4; 616fbeaa26cSAurelien Jarno break; 6178f2e8c07SKirill Batuzov case INDEX_op_call: 61822613af4SKirill Batuzov nb_call_args = (args[0] >> 16) + (args[0] & 0xffff); 61922613af4SKirill Batuzov if (!(args[nb_call_args + 1] & (TCG_CALL_CONST | TCG_CALL_PURE))) { 62022613af4SKirill Batuzov for (i = 0; i < nb_globals; i++) { 62122613af4SKirill Batuzov reset_temp(i, nb_temps, nb_globals); 62222613af4SKirill Batuzov } 62322613af4SKirill Batuzov } 62422613af4SKirill Batuzov for (i = 0; i < (args[0] >> 16); i++) { 62522613af4SKirill Batuzov reset_temp(args[i + 1], nb_temps, nb_globals); 62622613af4SKirill Batuzov } 62722613af4SKirill Batuzov i = nb_call_args + 3; 6288f2e8c07SKirill Batuzov while (i) { 6298f2e8c07SKirill Batuzov *gen_args = *args; 6308f2e8c07SKirill Batuzov args++; 6318f2e8c07SKirill Batuzov gen_args++; 6328f2e8c07SKirill Batuzov i--; 6338f2e8c07SKirill Batuzov } 6348f2e8c07SKirill Batuzov break; 6358f2e8c07SKirill Batuzov default: 63622613af4SKirill Batuzov /* Default case: we do know nothing about operation so no 637*a2550660SAurelien Jarno propagation is done. We trash everything if the operation 638*a2550660SAurelien Jarno is the end of a basic block, otherwise we only trash the 639*a2550660SAurelien Jarno output args. */ 640*a2550660SAurelien Jarno if (def->flags & TCG_OPF_BB_END) { 641*a2550660SAurelien Jarno memset(temps, 0, nb_temps * sizeof(struct tcg_temp_info)); 642*a2550660SAurelien Jarno } else { 64322613af4SKirill Batuzov for (i = 0; i < def->nb_oargs; i++) { 64422613af4SKirill Batuzov reset_temp(args[i], nb_temps, nb_globals); 64522613af4SKirill Batuzov } 646*a2550660SAurelien Jarno } 6478f2e8c07SKirill Batuzov for (i = 0; i < def->nb_args; i++) { 6488f2e8c07SKirill Batuzov gen_args[i] = args[i]; 6498f2e8c07SKirill Batuzov } 6508f2e8c07SKirill Batuzov args += def->nb_args; 6518f2e8c07SKirill Batuzov gen_args += def->nb_args; 6528f2e8c07SKirill Batuzov break; 6538f2e8c07SKirill Batuzov } 6548f2e8c07SKirill Batuzov } 6558f2e8c07SKirill Batuzov 6568f2e8c07SKirill Batuzov return gen_args; 6578f2e8c07SKirill Batuzov } 6588f2e8c07SKirill Batuzov 6598f2e8c07SKirill Batuzov TCGArg *tcg_optimize(TCGContext *s, uint16_t *tcg_opc_ptr, 6608f2e8c07SKirill Batuzov TCGArg *args, TCGOpDef *tcg_op_defs) 6618f2e8c07SKirill Batuzov { 6628f2e8c07SKirill Batuzov TCGArg *res; 6638f2e8c07SKirill Batuzov res = tcg_constant_folding(s, tcg_opc_ptr, args, tcg_op_defs); 6648f2e8c07SKirill Batuzov return res; 6658f2e8c07SKirill Batuzov } 666