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 #if TCG_TARGET_REG_BITS == 64 358f2e8c07SKirill Batuzov #define CASE_OP_32_64(x) \ 368f2e8c07SKirill Batuzov glue(glue(case INDEX_op_, x), _i32): \ 378f2e8c07SKirill Batuzov glue(glue(case INDEX_op_, x), _i64) 388f2e8c07SKirill Batuzov #else 398f2e8c07SKirill Batuzov #define CASE_OP_32_64(x) \ 408f2e8c07SKirill Batuzov glue(glue(case INDEX_op_, x), _i32) 418f2e8c07SKirill Batuzov #endif 428f2e8c07SKirill Batuzov 4322613af4SKirill Batuzov typedef enum { 4422613af4SKirill Batuzov TCG_TEMP_UNDEF = 0, 4522613af4SKirill Batuzov TCG_TEMP_CONST, 4622613af4SKirill Batuzov TCG_TEMP_COPY, 4722613af4SKirill Batuzov TCG_TEMP_HAS_COPY, 4822613af4SKirill Batuzov TCG_TEMP_ANY 4922613af4SKirill Batuzov } tcg_temp_state; 5022613af4SKirill Batuzov 5122613af4SKirill Batuzov struct tcg_temp_info { 5222613af4SKirill Batuzov tcg_temp_state state; 5322613af4SKirill Batuzov uint16_t prev_copy; 5422613af4SKirill Batuzov uint16_t next_copy; 5522613af4SKirill Batuzov tcg_target_ulong val; 5622613af4SKirill Batuzov }; 5722613af4SKirill Batuzov 5822613af4SKirill Batuzov static struct tcg_temp_info temps[TCG_MAX_TEMPS]; 5922613af4SKirill Batuzov 6022613af4SKirill Batuzov /* Reset TEMP's state to TCG_TEMP_ANY. If TEMP was a representative of some 6122613af4SKirill Batuzov class of equivalent temp's, a new representative should be chosen in this 6222613af4SKirill Batuzov class. */ 6322613af4SKirill Batuzov static void reset_temp(TCGArg temp, int nb_temps, int nb_globals) 6422613af4SKirill Batuzov { 6522613af4SKirill Batuzov int i; 6622613af4SKirill Batuzov TCGArg new_base = (TCGArg)-1; 6722613af4SKirill Batuzov if (temps[temp].state == TCG_TEMP_HAS_COPY) { 6822613af4SKirill Batuzov for (i = temps[temp].next_copy; i != temp; i = temps[i].next_copy) { 6922613af4SKirill Batuzov if (i >= nb_globals) { 7022613af4SKirill Batuzov temps[i].state = TCG_TEMP_HAS_COPY; 7122613af4SKirill Batuzov new_base = i; 7222613af4SKirill Batuzov break; 7322613af4SKirill Batuzov } 7422613af4SKirill Batuzov } 7522613af4SKirill Batuzov for (i = temps[temp].next_copy; i != temp; i = temps[i].next_copy) { 7622613af4SKirill Batuzov if (new_base == (TCGArg)-1) { 7722613af4SKirill Batuzov temps[i].state = TCG_TEMP_ANY; 7822613af4SKirill Batuzov } else { 7922613af4SKirill Batuzov temps[i].val = new_base; 8022613af4SKirill Batuzov } 8122613af4SKirill Batuzov } 8222613af4SKirill Batuzov temps[temps[temp].next_copy].prev_copy = temps[temp].prev_copy; 8322613af4SKirill Batuzov temps[temps[temp].prev_copy].next_copy = temps[temp].next_copy; 8422613af4SKirill Batuzov } else if (temps[temp].state == TCG_TEMP_COPY) { 8522613af4SKirill Batuzov temps[temps[temp].next_copy].prev_copy = temps[temp].prev_copy; 8622613af4SKirill Batuzov temps[temps[temp].prev_copy].next_copy = temps[temp].next_copy; 8722613af4SKirill Batuzov new_base = temps[temp].val; 8822613af4SKirill Batuzov } 8922613af4SKirill Batuzov temps[temp].state = TCG_TEMP_ANY; 9022613af4SKirill Batuzov if (new_base != (TCGArg)-1 && temps[new_base].next_copy == new_base) { 9122613af4SKirill Batuzov temps[new_base].state = TCG_TEMP_ANY; 9222613af4SKirill Batuzov } 9322613af4SKirill Batuzov } 9422613af4SKirill Batuzov 9522613af4SKirill Batuzov static int op_bits(int op) 9622613af4SKirill Batuzov { 9722613af4SKirill Batuzov switch (op) { 9822613af4SKirill Batuzov case INDEX_op_mov_i32: 9953108fb5SKirill Batuzov case INDEX_op_add_i32: 10053108fb5SKirill Batuzov case INDEX_op_sub_i32: 10153108fb5SKirill Batuzov case INDEX_op_mul_i32: 1029a81090bSKirill Batuzov case INDEX_op_and_i32: 1039a81090bSKirill Batuzov case INDEX_op_or_i32: 1049a81090bSKirill Batuzov case INDEX_op_xor_i32: 10555c0975cSKirill Batuzov case INDEX_op_shl_i32: 10655c0975cSKirill Batuzov case INDEX_op_shr_i32: 10755c0975cSKirill Batuzov case INDEX_op_sar_i32: 1081bfd07bdSBlue Swirl #ifdef TCG_TARGET_HAS_rot_i32 10955c0975cSKirill Batuzov case INDEX_op_rotl_i32: 11055c0975cSKirill Batuzov case INDEX_op_rotr_i32: 1111bfd07bdSBlue Swirl #endif 1121bfd07bdSBlue Swirl #ifdef TCG_TARGET_HAS_not_i32 113a640f031SKirill Batuzov case INDEX_op_not_i32: 1141bfd07bdSBlue Swirl #endif 1151bfd07bdSBlue Swirl #ifdef TCG_TARGET_HAS_ext8s_i32 116a640f031SKirill Batuzov case INDEX_op_ext8s_i32: 1171bfd07bdSBlue Swirl #endif 1181bfd07bdSBlue Swirl #ifdef TCG_TARGET_HAS_ext16s_i32 119a640f031SKirill Batuzov case INDEX_op_ext16s_i32: 1201bfd07bdSBlue Swirl #endif 1211bfd07bdSBlue Swirl #ifdef TCG_TARGET_HAS_ext8u_i32 122a640f031SKirill Batuzov case INDEX_op_ext8u_i32: 1231bfd07bdSBlue Swirl #endif 1241bfd07bdSBlue Swirl #ifdef TCG_TARGET_HAS_ext16u_i32 125a640f031SKirill Batuzov case INDEX_op_ext16u_i32: 1261bfd07bdSBlue Swirl #endif 12722613af4SKirill Batuzov return 32; 12822613af4SKirill Batuzov #if TCG_TARGET_REG_BITS == 64 12922613af4SKirill Batuzov case INDEX_op_mov_i64: 13053108fb5SKirill Batuzov case INDEX_op_add_i64: 13153108fb5SKirill Batuzov case INDEX_op_sub_i64: 13253108fb5SKirill Batuzov case INDEX_op_mul_i64: 1339a81090bSKirill Batuzov case INDEX_op_and_i64: 1349a81090bSKirill Batuzov case INDEX_op_or_i64: 1359a81090bSKirill Batuzov case INDEX_op_xor_i64: 13655c0975cSKirill Batuzov case INDEX_op_shl_i64: 13755c0975cSKirill Batuzov case INDEX_op_shr_i64: 13855c0975cSKirill Batuzov case INDEX_op_sar_i64: 1391bfd07bdSBlue Swirl #ifdef TCG_TARGET_HAS_rot_i64 14055c0975cSKirill Batuzov case INDEX_op_rotl_i64: 14155c0975cSKirill Batuzov case INDEX_op_rotr_i64: 1421bfd07bdSBlue Swirl #endif 1431bfd07bdSBlue Swirl #ifdef TCG_TARGET_HAS_not_i64 144a640f031SKirill Batuzov case INDEX_op_not_i64: 1451bfd07bdSBlue Swirl #endif 1461bfd07bdSBlue Swirl #ifdef TCG_TARGET_HAS_ext8s_i64 147a640f031SKirill Batuzov case INDEX_op_ext8s_i64: 1481bfd07bdSBlue Swirl #endif 1491bfd07bdSBlue Swirl #ifdef TCG_TARGET_HAS_ext16s_i64 150a640f031SKirill Batuzov case INDEX_op_ext16s_i64: 1511bfd07bdSBlue Swirl #endif 1521bfd07bdSBlue Swirl #ifdef TCG_TARGET_HAS_ext32s_i64 153a640f031SKirill Batuzov case INDEX_op_ext32s_i64: 1541bfd07bdSBlue Swirl #endif 1551bfd07bdSBlue Swirl #ifdef TCG_TARGET_HAS_ext8u_i64 156a640f031SKirill Batuzov case INDEX_op_ext8u_i64: 1571bfd07bdSBlue Swirl #endif 1581bfd07bdSBlue Swirl #ifdef TCG_TARGET_HAS_ext16u_i64 159a640f031SKirill Batuzov case INDEX_op_ext16u_i64: 1601bfd07bdSBlue Swirl #endif 1611bfd07bdSBlue Swirl #ifdef TCG_TARGET_HAS_ext32u_i64 162a640f031SKirill Batuzov case INDEX_op_ext32u_i64: 1631bfd07bdSBlue Swirl #endif 16422613af4SKirill Batuzov return 64; 16522613af4SKirill Batuzov #endif 16622613af4SKirill Batuzov default: 16722613af4SKirill Batuzov fprintf(stderr, "Unrecognized operation %d in op_bits.\n", op); 16822613af4SKirill Batuzov tcg_abort(); 16922613af4SKirill Batuzov } 17022613af4SKirill Batuzov } 17122613af4SKirill Batuzov 17222613af4SKirill Batuzov static int op_to_movi(int op) 17322613af4SKirill Batuzov { 17422613af4SKirill Batuzov switch (op_bits(op)) { 17522613af4SKirill Batuzov case 32: 17622613af4SKirill Batuzov return INDEX_op_movi_i32; 17722613af4SKirill Batuzov #if TCG_TARGET_REG_BITS == 64 17822613af4SKirill Batuzov case 64: 17922613af4SKirill Batuzov return INDEX_op_movi_i64; 18022613af4SKirill Batuzov #endif 18122613af4SKirill Batuzov default: 18222613af4SKirill Batuzov fprintf(stderr, "op_to_movi: unexpected return value of " 18322613af4SKirill Batuzov "function op_bits.\n"); 18422613af4SKirill Batuzov tcg_abort(); 18522613af4SKirill Batuzov } 18622613af4SKirill Batuzov } 18722613af4SKirill Batuzov 188*e31b0a7cSBlue Swirl static void tcg_opt_gen_mov(TCGContext *s, TCGArg *gen_args, TCGArg dst, 189*e31b0a7cSBlue Swirl TCGArg src, int nb_temps, int nb_globals) 19022613af4SKirill Batuzov { 19122613af4SKirill Batuzov reset_temp(dst, nb_temps, nb_globals); 19222613af4SKirill Batuzov assert(temps[src].state != TCG_TEMP_COPY); 193*e31b0a7cSBlue Swirl /* Don't try to copy if one of temps is a global or either one 194*e31b0a7cSBlue Swirl is local and another is register */ 195*e31b0a7cSBlue Swirl if (src >= nb_globals && dst >= nb_globals && 196*e31b0a7cSBlue Swirl tcg_arg_is_local(s, src) == tcg_arg_is_local(s, dst)) { 19722613af4SKirill Batuzov assert(temps[src].state != TCG_TEMP_CONST); 19822613af4SKirill Batuzov if (temps[src].state != TCG_TEMP_HAS_COPY) { 19922613af4SKirill Batuzov temps[src].state = TCG_TEMP_HAS_COPY; 20022613af4SKirill Batuzov temps[src].next_copy = src; 20122613af4SKirill Batuzov temps[src].prev_copy = src; 20222613af4SKirill Batuzov } 20322613af4SKirill Batuzov temps[dst].state = TCG_TEMP_COPY; 20422613af4SKirill Batuzov temps[dst].val = src; 20522613af4SKirill Batuzov temps[dst].next_copy = temps[src].next_copy; 20622613af4SKirill Batuzov temps[dst].prev_copy = src; 20722613af4SKirill Batuzov temps[temps[dst].next_copy].prev_copy = dst; 20822613af4SKirill Batuzov temps[src].next_copy = dst; 20922613af4SKirill Batuzov } 21022613af4SKirill Batuzov gen_args[0] = dst; 21122613af4SKirill Batuzov gen_args[1] = src; 21222613af4SKirill Batuzov } 21322613af4SKirill Batuzov 21422613af4SKirill Batuzov static void tcg_opt_gen_movi(TCGArg *gen_args, TCGArg dst, TCGArg val, 21522613af4SKirill Batuzov int nb_temps, int nb_globals) 21622613af4SKirill Batuzov { 21722613af4SKirill Batuzov reset_temp(dst, nb_temps, nb_globals); 21822613af4SKirill Batuzov temps[dst].state = TCG_TEMP_CONST; 21922613af4SKirill Batuzov temps[dst].val = val; 22022613af4SKirill Batuzov gen_args[0] = dst; 22122613af4SKirill Batuzov gen_args[1] = val; 22222613af4SKirill Batuzov } 22322613af4SKirill Batuzov 22453108fb5SKirill Batuzov static int op_to_mov(int op) 22553108fb5SKirill Batuzov { 22653108fb5SKirill Batuzov switch (op_bits(op)) { 22753108fb5SKirill Batuzov case 32: 22853108fb5SKirill Batuzov return INDEX_op_mov_i32; 22953108fb5SKirill Batuzov #if TCG_TARGET_REG_BITS == 64 23053108fb5SKirill Batuzov case 64: 23153108fb5SKirill Batuzov return INDEX_op_mov_i64; 23253108fb5SKirill Batuzov #endif 23353108fb5SKirill Batuzov default: 23453108fb5SKirill Batuzov fprintf(stderr, "op_to_mov: unexpected return value of " 23553108fb5SKirill Batuzov "function op_bits.\n"); 23653108fb5SKirill Batuzov tcg_abort(); 23753108fb5SKirill Batuzov } 23853108fb5SKirill Batuzov } 23953108fb5SKirill Batuzov 24053108fb5SKirill Batuzov static TCGArg do_constant_folding_2(int op, TCGArg x, TCGArg y) 24153108fb5SKirill Batuzov { 24253108fb5SKirill Batuzov switch (op) { 24353108fb5SKirill Batuzov CASE_OP_32_64(add): 24453108fb5SKirill Batuzov return x + y; 24553108fb5SKirill Batuzov 24653108fb5SKirill Batuzov CASE_OP_32_64(sub): 24753108fb5SKirill Batuzov return x - y; 24853108fb5SKirill Batuzov 24953108fb5SKirill Batuzov CASE_OP_32_64(mul): 25053108fb5SKirill Batuzov return x * y; 25153108fb5SKirill Batuzov 2529a81090bSKirill Batuzov CASE_OP_32_64(and): 2539a81090bSKirill Batuzov return x & y; 2549a81090bSKirill Batuzov 2559a81090bSKirill Batuzov CASE_OP_32_64(or): 2569a81090bSKirill Batuzov return x | y; 2579a81090bSKirill Batuzov 2589a81090bSKirill Batuzov CASE_OP_32_64(xor): 2599a81090bSKirill Batuzov return x ^ y; 2609a81090bSKirill Batuzov 26155c0975cSKirill Batuzov case INDEX_op_shl_i32: 26255c0975cSKirill Batuzov return (uint32_t)x << (uint32_t)y; 26355c0975cSKirill Batuzov 26455c0975cSKirill Batuzov #if TCG_TARGET_REG_BITS == 64 26555c0975cSKirill Batuzov case INDEX_op_shl_i64: 26655c0975cSKirill Batuzov return (uint64_t)x << (uint64_t)y; 26755c0975cSKirill Batuzov #endif 26855c0975cSKirill Batuzov 26955c0975cSKirill Batuzov case INDEX_op_shr_i32: 27055c0975cSKirill Batuzov return (uint32_t)x >> (uint32_t)y; 27155c0975cSKirill Batuzov 27255c0975cSKirill Batuzov #if TCG_TARGET_REG_BITS == 64 27355c0975cSKirill Batuzov case INDEX_op_shr_i64: 27455c0975cSKirill Batuzov return (uint64_t)x >> (uint64_t)y; 27555c0975cSKirill Batuzov #endif 27655c0975cSKirill Batuzov 27755c0975cSKirill Batuzov case INDEX_op_sar_i32: 27855c0975cSKirill Batuzov return (int32_t)x >> (int32_t)y; 27955c0975cSKirill Batuzov 28055c0975cSKirill Batuzov #if TCG_TARGET_REG_BITS == 64 28155c0975cSKirill Batuzov case INDEX_op_sar_i64: 28255c0975cSKirill Batuzov return (int64_t)x >> (int64_t)y; 28355c0975cSKirill Batuzov #endif 28455c0975cSKirill Batuzov 2851bfd07bdSBlue Swirl #ifdef TCG_TARGET_HAS_rot_i32 28655c0975cSKirill Batuzov case INDEX_op_rotr_i32: 28755c0975cSKirill Batuzov #if TCG_TARGET_REG_BITS == 64 28855c0975cSKirill Batuzov x &= 0xffffffff; 28955c0975cSKirill Batuzov y &= 0xffffffff; 29055c0975cSKirill Batuzov #endif 29155c0975cSKirill Batuzov x = (x << (32 - y)) | (x >> y); 29255c0975cSKirill Batuzov return x; 2931bfd07bdSBlue Swirl #endif 29455c0975cSKirill Batuzov 2951bfd07bdSBlue Swirl #ifdef TCG_TARGET_HAS_rot_i64 29655c0975cSKirill Batuzov #if TCG_TARGET_REG_BITS == 64 29755c0975cSKirill Batuzov case INDEX_op_rotr_i64: 29855c0975cSKirill Batuzov x = (x << (64 - y)) | (x >> y); 29955c0975cSKirill Batuzov return x; 30055c0975cSKirill Batuzov #endif 3011bfd07bdSBlue Swirl #endif 30255c0975cSKirill Batuzov 3031bfd07bdSBlue Swirl #ifdef TCG_TARGET_HAS_rot_i32 30455c0975cSKirill Batuzov case INDEX_op_rotl_i32: 30555c0975cSKirill Batuzov #if TCG_TARGET_REG_BITS == 64 30655c0975cSKirill Batuzov x &= 0xffffffff; 30755c0975cSKirill Batuzov y &= 0xffffffff; 30855c0975cSKirill Batuzov #endif 30955c0975cSKirill Batuzov x = (x << y) | (x >> (32 - y)); 31055c0975cSKirill Batuzov return x; 3111bfd07bdSBlue Swirl #endif 31255c0975cSKirill Batuzov 3131bfd07bdSBlue Swirl #ifdef TCG_TARGET_HAS_rot_i64 31455c0975cSKirill Batuzov #if TCG_TARGET_REG_BITS == 64 31555c0975cSKirill Batuzov case INDEX_op_rotl_i64: 31655c0975cSKirill Batuzov x = (x << y) | (x >> (64 - y)); 31755c0975cSKirill Batuzov return x; 31855c0975cSKirill Batuzov #endif 3191bfd07bdSBlue Swirl #endif 32055c0975cSKirill Batuzov 3211bfd07bdSBlue Swirl #if defined(TCG_TARGET_HAS_not_i32) || defined(TCG_TARGET_HAS_not_i64) 3221bfd07bdSBlue Swirl #ifdef TCG_TARGET_HAS_not_i32 3231bfd07bdSBlue Swirl case INDEX_op_not_i32: 3242ec00650SBlue Swirl #endif 3252ec00650SBlue Swirl #ifdef TCG_TARGET_HAS_not_i64 3261bfd07bdSBlue Swirl case INDEX_op_not_i64: 3271bfd07bdSBlue Swirl #endif 328a640f031SKirill Batuzov return ~x; 3291bfd07bdSBlue Swirl #endif 330a640f031SKirill Batuzov 3311bfd07bdSBlue Swirl #if defined(TCG_TARGET_HAS_ext8s_i32) || defined(TCG_TARGET_HAS_ext8s_i64) 3321bfd07bdSBlue Swirl #ifdef TCG_TARGET_HAS_ext8s_i32 3331bfd07bdSBlue Swirl case INDEX_op_ext8s_i32: 3342ec00650SBlue Swirl #endif 3352ec00650SBlue Swirl #ifdef TCG_TARGET_HAS_ext8s_i64 3361bfd07bdSBlue Swirl case INDEX_op_ext8s_i64: 3371bfd07bdSBlue Swirl #endif 338a640f031SKirill Batuzov return (int8_t)x; 3391bfd07bdSBlue Swirl #endif 340a640f031SKirill Batuzov 3411bfd07bdSBlue Swirl #if defined(TCG_TARGET_HAS_ext16s_i32) || defined(TCG_TARGET_HAS_ext16s_i64) 3421bfd07bdSBlue Swirl #ifdef TCG_TARGET_HAS_ext16s_i32 3431bfd07bdSBlue Swirl case INDEX_op_ext16s_i32: 3442ec00650SBlue Swirl #endif 3452ec00650SBlue Swirl #ifdef TCG_TARGET_HAS_ext16s_i64 3461bfd07bdSBlue Swirl case INDEX_op_ext16s_i64: 3471bfd07bdSBlue Swirl #endif 348a640f031SKirill Batuzov return (int16_t)x; 3491bfd07bdSBlue Swirl #endif 350a640f031SKirill Batuzov 3511bfd07bdSBlue Swirl #if defined(TCG_TARGET_HAS_ext8u_i32) || defined(TCG_TARGET_HAS_ext8u_i64) 3521bfd07bdSBlue Swirl #ifdef TCG_TARGET_HAS_ext8u_i32 3531bfd07bdSBlue Swirl case INDEX_op_ext8u_i32: 3542ec00650SBlue Swirl #endif 3552ec00650SBlue Swirl #ifdef TCG_TARGET_HAS_ext8u_i64 3561bfd07bdSBlue Swirl case INDEX_op_ext8u_i64: 3571bfd07bdSBlue Swirl #endif 358a640f031SKirill Batuzov return (uint8_t)x; 3591bfd07bdSBlue Swirl #endif 360a640f031SKirill Batuzov 3611bfd07bdSBlue Swirl #if defined(TCG_TARGET_HAS_ext16u_i32) || defined(TCG_TARGET_HAS_ext16u_i64) 3621bfd07bdSBlue Swirl #ifdef TCG_TARGET_HAS_ext16u_i32 3631bfd07bdSBlue Swirl case INDEX_op_ext16u_i32: 3642ec00650SBlue Swirl #endif 3652ec00650SBlue Swirl #ifdef TCG_TARGET_HAS_ext16u_i64 3661bfd07bdSBlue Swirl case INDEX_op_ext16u_i64: 3671bfd07bdSBlue Swirl #endif 368a640f031SKirill Batuzov return (uint16_t)x; 3691bfd07bdSBlue Swirl #endif 370a640f031SKirill Batuzov 371a640f031SKirill Batuzov #if TCG_TARGET_REG_BITS == 64 3722ec00650SBlue Swirl #ifdef TCG_TARGET_HAS_ext32s_i64 373a640f031SKirill Batuzov case INDEX_op_ext32s_i64: 374a640f031SKirill Batuzov return (int32_t)x; 3751bfd07bdSBlue Swirl #endif 376a640f031SKirill Batuzov 3772ec00650SBlue Swirl #ifdef TCG_TARGET_HAS_ext32u_i64 378a640f031SKirill Batuzov case INDEX_op_ext32u_i64: 379a640f031SKirill Batuzov return (uint32_t)x; 380a640f031SKirill Batuzov #endif 3811bfd07bdSBlue Swirl #endif 382a640f031SKirill Batuzov 38353108fb5SKirill Batuzov default: 38453108fb5SKirill Batuzov fprintf(stderr, 38553108fb5SKirill Batuzov "Unrecognized operation %d in do_constant_folding.\n", op); 38653108fb5SKirill Batuzov tcg_abort(); 38753108fb5SKirill Batuzov } 38853108fb5SKirill Batuzov } 38953108fb5SKirill Batuzov 39053108fb5SKirill Batuzov static TCGArg do_constant_folding(int op, TCGArg x, TCGArg y) 39153108fb5SKirill Batuzov { 39253108fb5SKirill Batuzov TCGArg res = do_constant_folding_2(op, x, y); 39353108fb5SKirill Batuzov #if TCG_TARGET_REG_BITS == 64 39453108fb5SKirill Batuzov if (op_bits(op) == 32) { 39553108fb5SKirill Batuzov res &= 0xffffffff; 39653108fb5SKirill Batuzov } 39753108fb5SKirill Batuzov #endif 39853108fb5SKirill Batuzov return res; 39953108fb5SKirill Batuzov } 40053108fb5SKirill Batuzov 40122613af4SKirill Batuzov /* Propagate constants and copies, fold constant expressions. */ 4028f2e8c07SKirill Batuzov static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, 4038f2e8c07SKirill Batuzov TCGArg *args, TCGOpDef *tcg_op_defs) 4048f2e8c07SKirill Batuzov { 40522613af4SKirill Batuzov int i, nb_ops, op_index, op, nb_temps, nb_globals, nb_call_args; 4068f2e8c07SKirill Batuzov const TCGOpDef *def; 4078f2e8c07SKirill Batuzov TCGArg *gen_args; 40853108fb5SKirill Batuzov TCGArg tmp; 40922613af4SKirill Batuzov /* Array VALS has an element for each temp. 41022613af4SKirill Batuzov If this temp holds a constant then its value is kept in VALS' element. 41122613af4SKirill Batuzov If this temp is a copy of other ones then this equivalence class' 41222613af4SKirill Batuzov representative is kept in VALS' element. 41322613af4SKirill Batuzov If this temp is neither copy nor constant then corresponding VALS' 41422613af4SKirill Batuzov element is unused. */ 4158f2e8c07SKirill Batuzov 4168f2e8c07SKirill Batuzov nb_temps = s->nb_temps; 4178f2e8c07SKirill Batuzov nb_globals = s->nb_globals; 41822613af4SKirill Batuzov memset(temps, 0, nb_temps * sizeof(struct tcg_temp_info)); 4198f2e8c07SKirill Batuzov 4208f2e8c07SKirill Batuzov nb_ops = tcg_opc_ptr - gen_opc_buf; 4218f2e8c07SKirill Batuzov gen_args = args; 4228f2e8c07SKirill Batuzov for (op_index = 0; op_index < nb_ops; op_index++) { 4238f2e8c07SKirill Batuzov op = gen_opc_buf[op_index]; 4248f2e8c07SKirill Batuzov def = &tcg_op_defs[op]; 42522613af4SKirill Batuzov /* Do copy propagation */ 42622613af4SKirill Batuzov if (!(def->flags & (TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS))) { 42722613af4SKirill Batuzov assert(op != INDEX_op_call); 42822613af4SKirill Batuzov for (i = def->nb_oargs; i < def->nb_oargs + def->nb_iargs; i++) { 42922613af4SKirill Batuzov if (temps[args[i]].state == TCG_TEMP_COPY) { 43022613af4SKirill Batuzov args[i] = temps[args[i]].val; 43122613af4SKirill Batuzov } 43222613af4SKirill Batuzov } 43322613af4SKirill Batuzov } 43422613af4SKirill Batuzov 43553108fb5SKirill Batuzov /* For commutative operations make constant second argument */ 43653108fb5SKirill Batuzov switch (op) { 43753108fb5SKirill Batuzov CASE_OP_32_64(add): 43853108fb5SKirill Batuzov CASE_OP_32_64(mul): 4399a81090bSKirill Batuzov CASE_OP_32_64(and): 4409a81090bSKirill Batuzov CASE_OP_32_64(or): 4419a81090bSKirill Batuzov CASE_OP_32_64(xor): 44253108fb5SKirill Batuzov if (temps[args[1]].state == TCG_TEMP_CONST) { 44353108fb5SKirill Batuzov tmp = args[1]; 44453108fb5SKirill Batuzov args[1] = args[2]; 44553108fb5SKirill Batuzov args[2] = tmp; 44653108fb5SKirill Batuzov } 44753108fb5SKirill Batuzov break; 44853108fb5SKirill Batuzov default: 44953108fb5SKirill Batuzov break; 45053108fb5SKirill Batuzov } 45153108fb5SKirill Batuzov 45253108fb5SKirill Batuzov /* Simplify expression if possible. */ 45353108fb5SKirill Batuzov switch (op) { 45453108fb5SKirill Batuzov CASE_OP_32_64(add): 45553108fb5SKirill Batuzov CASE_OP_32_64(sub): 45655c0975cSKirill Batuzov CASE_OP_32_64(shl): 45755c0975cSKirill Batuzov CASE_OP_32_64(shr): 45855c0975cSKirill Batuzov CASE_OP_32_64(sar): 4591bfd07bdSBlue Swirl #ifdef TCG_TARGET_HAS_rot_i32 4601bfd07bdSBlue Swirl case INDEX_op_rotl_i32: 4611bfd07bdSBlue Swirl case INDEX_op_rotr_i32: 4621bfd07bdSBlue Swirl #endif 4631bfd07bdSBlue Swirl #ifdef TCG_TARGET_HAS_rot_i64 4641bfd07bdSBlue Swirl case INDEX_op_rotl_i64: 4651bfd07bdSBlue Swirl case INDEX_op_rotr_i64: 4661bfd07bdSBlue Swirl #endif 46753108fb5SKirill Batuzov if (temps[args[1]].state == TCG_TEMP_CONST) { 46853108fb5SKirill Batuzov /* Proceed with possible constant folding. */ 46953108fb5SKirill Batuzov break; 47053108fb5SKirill Batuzov } 47153108fb5SKirill Batuzov if (temps[args[2]].state == TCG_TEMP_CONST 47253108fb5SKirill Batuzov && temps[args[2]].val == 0) { 47353108fb5SKirill Batuzov if ((temps[args[0]].state == TCG_TEMP_COPY 47453108fb5SKirill Batuzov && temps[args[0]].val == args[1]) 47553108fb5SKirill Batuzov || args[0] == args[1]) { 47653108fb5SKirill Batuzov args += 3; 47753108fb5SKirill Batuzov gen_opc_buf[op_index] = INDEX_op_nop; 47853108fb5SKirill Batuzov } else { 47953108fb5SKirill Batuzov gen_opc_buf[op_index] = op_to_mov(op); 480*e31b0a7cSBlue Swirl tcg_opt_gen_mov(s, gen_args, args[0], args[1], 48153108fb5SKirill Batuzov nb_temps, nb_globals); 48253108fb5SKirill Batuzov gen_args += 2; 48353108fb5SKirill Batuzov args += 3; 48453108fb5SKirill Batuzov } 48553108fb5SKirill Batuzov continue; 48653108fb5SKirill Batuzov } 48753108fb5SKirill Batuzov break; 48853108fb5SKirill Batuzov CASE_OP_32_64(mul): 48953108fb5SKirill Batuzov if ((temps[args[2]].state == TCG_TEMP_CONST 49053108fb5SKirill Batuzov && temps[args[2]].val == 0)) { 49153108fb5SKirill Batuzov gen_opc_buf[op_index] = op_to_movi(op); 49253108fb5SKirill Batuzov tcg_opt_gen_movi(gen_args, args[0], 0, nb_temps, nb_globals); 49353108fb5SKirill Batuzov args += 3; 49453108fb5SKirill Batuzov gen_args += 2; 49553108fb5SKirill Batuzov continue; 49653108fb5SKirill Batuzov } 49753108fb5SKirill Batuzov break; 4989a81090bSKirill Batuzov CASE_OP_32_64(or): 4999a81090bSKirill Batuzov CASE_OP_32_64(and): 5009a81090bSKirill Batuzov if (args[1] == args[2]) { 5019a81090bSKirill Batuzov if (args[1] == args[0]) { 5029a81090bSKirill Batuzov args += 3; 5039a81090bSKirill Batuzov gen_opc_buf[op_index] = INDEX_op_nop; 5049a81090bSKirill Batuzov } else { 5059a81090bSKirill Batuzov gen_opc_buf[op_index] = op_to_mov(op); 506*e31b0a7cSBlue Swirl tcg_opt_gen_mov(s, gen_args, args[0], args[1], nb_temps, 5079a81090bSKirill Batuzov nb_globals); 5089a81090bSKirill Batuzov gen_args += 2; 5099a81090bSKirill Batuzov args += 3; 5109a81090bSKirill Batuzov } 5119a81090bSKirill Batuzov continue; 5129a81090bSKirill Batuzov } 5139a81090bSKirill Batuzov break; 51453108fb5SKirill Batuzov } 51553108fb5SKirill Batuzov 51622613af4SKirill Batuzov /* Propagate constants through copy operations and do constant 51722613af4SKirill Batuzov folding. Constants will be substituted to arguments by register 51822613af4SKirill Batuzov allocator where needed and possible. Also detect copies. */ 5198f2e8c07SKirill Batuzov switch (op) { 52022613af4SKirill Batuzov CASE_OP_32_64(mov): 52122613af4SKirill Batuzov if ((temps[args[1]].state == TCG_TEMP_COPY 52222613af4SKirill Batuzov && temps[args[1]].val == args[0]) 52322613af4SKirill Batuzov || args[0] == args[1]) { 52422613af4SKirill Batuzov args += 2; 52522613af4SKirill Batuzov gen_opc_buf[op_index] = INDEX_op_nop; 52622613af4SKirill Batuzov break; 52722613af4SKirill Batuzov } 52822613af4SKirill Batuzov if (temps[args[1]].state != TCG_TEMP_CONST) { 529*e31b0a7cSBlue Swirl tcg_opt_gen_mov(s, gen_args, args[0], args[1], 53022613af4SKirill Batuzov nb_temps, nb_globals); 53122613af4SKirill Batuzov gen_args += 2; 53222613af4SKirill Batuzov args += 2; 53322613af4SKirill Batuzov break; 53422613af4SKirill Batuzov } 53522613af4SKirill Batuzov /* Source argument is constant. Rewrite the operation and 53622613af4SKirill Batuzov let movi case handle it. */ 53722613af4SKirill Batuzov op = op_to_movi(op); 53822613af4SKirill Batuzov gen_opc_buf[op_index] = op; 53922613af4SKirill Batuzov args[1] = temps[args[1]].val; 54022613af4SKirill Batuzov /* fallthrough */ 54122613af4SKirill Batuzov CASE_OP_32_64(movi): 54222613af4SKirill Batuzov tcg_opt_gen_movi(gen_args, args[0], args[1], nb_temps, nb_globals); 54322613af4SKirill Batuzov gen_args += 2; 54422613af4SKirill Batuzov args += 2; 54522613af4SKirill Batuzov break; 546a640f031SKirill Batuzov CASE_OP_32_64(not): 5471bfd07bdSBlue Swirl #ifdef TCG_TARGET_HAS_ext8s_i32 5481bfd07bdSBlue Swirl case INDEX_op_ext8s_i32: 5491bfd07bdSBlue Swirl #endif 5501bfd07bdSBlue Swirl #ifdef TCG_TARGET_HAS_ext8s_i64 5511bfd07bdSBlue Swirl case INDEX_op_ext8s_i64: 5521bfd07bdSBlue Swirl #endif 5531bfd07bdSBlue Swirl #ifdef TCG_TARGET_HAS_ext16s_i32 5541bfd07bdSBlue Swirl case INDEX_op_ext16s_i32: 5551bfd07bdSBlue Swirl #endif 5561bfd07bdSBlue Swirl #ifdef TCG_TARGET_HAS_ext16s_i64 5571bfd07bdSBlue Swirl case INDEX_op_ext16s_i64: 5581bfd07bdSBlue Swirl #endif 5591bfd07bdSBlue Swirl #ifdef TCG_TARGET_HAS_ext8u_i32 5601bfd07bdSBlue Swirl case INDEX_op_ext8u_i32: 5611bfd07bdSBlue Swirl #endif 5621bfd07bdSBlue Swirl #ifdef TCG_TARGET_HAS_ext8u_i64 5631bfd07bdSBlue Swirl case INDEX_op_ext8u_i64: 5641bfd07bdSBlue Swirl #endif 5651bfd07bdSBlue Swirl #ifdef TCG_TARGET_HAS_ext16u_i32 5661bfd07bdSBlue Swirl case INDEX_op_ext16u_i32: 5671bfd07bdSBlue Swirl #endif 5681bfd07bdSBlue Swirl #ifdef TCG_TARGET_HAS_ext16u_i64 5691bfd07bdSBlue Swirl case INDEX_op_ext16u_i64: 5701bfd07bdSBlue Swirl #endif 571a640f031SKirill Batuzov #if TCG_TARGET_REG_BITS == 64 572a640f031SKirill Batuzov case INDEX_op_ext32s_i64: 573a640f031SKirill Batuzov case INDEX_op_ext32u_i64: 574a640f031SKirill Batuzov #endif 575a640f031SKirill Batuzov if (temps[args[1]].state == TCG_TEMP_CONST) { 576a640f031SKirill Batuzov gen_opc_buf[op_index] = op_to_movi(op); 577a640f031SKirill Batuzov tmp = do_constant_folding(op, temps[args[1]].val, 0); 578a640f031SKirill Batuzov tcg_opt_gen_movi(gen_args, args[0], tmp, nb_temps, nb_globals); 579a640f031SKirill Batuzov gen_args += 2; 580a640f031SKirill Batuzov args += 2; 581a640f031SKirill Batuzov break; 582a640f031SKirill Batuzov } else { 583a640f031SKirill Batuzov reset_temp(args[0], nb_temps, nb_globals); 584a640f031SKirill Batuzov gen_args[0] = args[0]; 585a640f031SKirill Batuzov gen_args[1] = args[1]; 586a640f031SKirill Batuzov gen_args += 2; 587a640f031SKirill Batuzov args += 2; 588a640f031SKirill Batuzov break; 589a640f031SKirill Batuzov } 59053108fb5SKirill Batuzov CASE_OP_32_64(add): 59153108fb5SKirill Batuzov CASE_OP_32_64(sub): 59253108fb5SKirill Batuzov CASE_OP_32_64(mul): 5939a81090bSKirill Batuzov CASE_OP_32_64(or): 5949a81090bSKirill Batuzov CASE_OP_32_64(and): 5959a81090bSKirill Batuzov CASE_OP_32_64(xor): 59655c0975cSKirill Batuzov CASE_OP_32_64(shl): 59755c0975cSKirill Batuzov CASE_OP_32_64(shr): 59855c0975cSKirill Batuzov CASE_OP_32_64(sar): 5991bfd07bdSBlue Swirl #ifdef TCG_TARGET_HAS_rot_i32 6001bfd07bdSBlue Swirl case INDEX_op_rotl_i32: 6011bfd07bdSBlue Swirl case INDEX_op_rotr_i32: 6021bfd07bdSBlue Swirl #endif 6031bfd07bdSBlue Swirl #ifdef TCG_TARGET_HAS_rot_i64 6041bfd07bdSBlue Swirl case INDEX_op_rotl_i64: 6051bfd07bdSBlue Swirl case INDEX_op_rotr_i64: 6061bfd07bdSBlue Swirl #endif 60753108fb5SKirill Batuzov if (temps[args[1]].state == TCG_TEMP_CONST 60853108fb5SKirill Batuzov && temps[args[2]].state == TCG_TEMP_CONST) { 60953108fb5SKirill Batuzov gen_opc_buf[op_index] = op_to_movi(op); 61053108fb5SKirill Batuzov tmp = do_constant_folding(op, temps[args[1]].val, 61153108fb5SKirill Batuzov temps[args[2]].val); 61253108fb5SKirill Batuzov tcg_opt_gen_movi(gen_args, args[0], tmp, nb_temps, nb_globals); 61353108fb5SKirill Batuzov gen_args += 2; 61453108fb5SKirill Batuzov args += 3; 61553108fb5SKirill Batuzov break; 61653108fb5SKirill Batuzov } else { 61753108fb5SKirill Batuzov reset_temp(args[0], nb_temps, nb_globals); 61853108fb5SKirill Batuzov gen_args[0] = args[0]; 61953108fb5SKirill Batuzov gen_args[1] = args[1]; 62053108fb5SKirill Batuzov gen_args[2] = args[2]; 62153108fb5SKirill Batuzov gen_args += 3; 62253108fb5SKirill Batuzov args += 3; 62353108fb5SKirill Batuzov break; 62453108fb5SKirill Batuzov } 6258f2e8c07SKirill Batuzov case INDEX_op_call: 62622613af4SKirill Batuzov nb_call_args = (args[0] >> 16) + (args[0] & 0xffff); 62722613af4SKirill Batuzov if (!(args[nb_call_args + 1] & (TCG_CALL_CONST | TCG_CALL_PURE))) { 62822613af4SKirill Batuzov for (i = 0; i < nb_globals; i++) { 62922613af4SKirill Batuzov reset_temp(i, nb_temps, nb_globals); 63022613af4SKirill Batuzov } 63122613af4SKirill Batuzov } 63222613af4SKirill Batuzov for (i = 0; i < (args[0] >> 16); i++) { 63322613af4SKirill Batuzov reset_temp(args[i + 1], nb_temps, nb_globals); 63422613af4SKirill Batuzov } 63522613af4SKirill Batuzov i = nb_call_args + 3; 6368f2e8c07SKirill Batuzov while (i) { 6378f2e8c07SKirill Batuzov *gen_args = *args; 6388f2e8c07SKirill Batuzov args++; 6398f2e8c07SKirill Batuzov gen_args++; 6408f2e8c07SKirill Batuzov i--; 6418f2e8c07SKirill Batuzov } 6428f2e8c07SKirill Batuzov break; 6438f2e8c07SKirill Batuzov case INDEX_op_set_label: 6448f2e8c07SKirill Batuzov case INDEX_op_jmp: 6458f2e8c07SKirill Batuzov case INDEX_op_br: 6468f2e8c07SKirill Batuzov CASE_OP_32_64(brcond): 64722613af4SKirill Batuzov memset(temps, 0, nb_temps * sizeof(struct tcg_temp_info)); 6488f2e8c07SKirill Batuzov for (i = 0; i < def->nb_args; i++) { 6498f2e8c07SKirill Batuzov *gen_args = *args; 6508f2e8c07SKirill Batuzov args++; 6518f2e8c07SKirill Batuzov gen_args++; 6528f2e8c07SKirill Batuzov } 6538f2e8c07SKirill Batuzov break; 6548f2e8c07SKirill Batuzov default: 65522613af4SKirill Batuzov /* Default case: we do know nothing about operation so no 65622613af4SKirill Batuzov propagation is done. We only trash output args. */ 65722613af4SKirill Batuzov for (i = 0; i < def->nb_oargs; i++) { 65822613af4SKirill Batuzov reset_temp(args[i], nb_temps, nb_globals); 65922613af4SKirill Batuzov } 6608f2e8c07SKirill Batuzov for (i = 0; i < def->nb_args; i++) { 6618f2e8c07SKirill Batuzov gen_args[i] = args[i]; 6628f2e8c07SKirill Batuzov } 6638f2e8c07SKirill Batuzov args += def->nb_args; 6648f2e8c07SKirill Batuzov gen_args += def->nb_args; 6658f2e8c07SKirill Batuzov break; 6668f2e8c07SKirill Batuzov } 6678f2e8c07SKirill Batuzov } 6688f2e8c07SKirill Batuzov 6698f2e8c07SKirill Batuzov return gen_args; 6708f2e8c07SKirill Batuzov } 6718f2e8c07SKirill Batuzov 6728f2e8c07SKirill Batuzov TCGArg *tcg_optimize(TCGContext *s, uint16_t *tcg_opc_ptr, 6738f2e8c07SKirill Batuzov TCGArg *args, TCGOpDef *tcg_op_defs) 6748f2e8c07SKirill Batuzov { 6758f2e8c07SKirill Batuzov TCGArg *res; 6768f2e8c07SKirill Batuzov res = tcg_constant_folding(s, tcg_opc_ptr, args, tcg_op_defs); 6778f2e8c07SKirill Batuzov return res; 6788f2e8c07SKirill Batuzov } 679