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; 49*3a9d8b17SPaolo Bonzini tcg_target_ulong mask; 5022613af4SKirill Batuzov }; 5122613af4SKirill Batuzov 5222613af4SKirill Batuzov static struct tcg_temp_info temps[TCG_MAX_TEMPS]; 5322613af4SKirill Batuzov 54e590d4e6SAurelien Jarno /* Reset TEMP's state to TCG_TEMP_UNDEF. If TEMP only had one copy, remove 55e590d4e6SAurelien Jarno the copy flag from the left temp. */ 56e590d4e6SAurelien Jarno static void reset_temp(TCGArg temp) 5722613af4SKirill Batuzov { 58e590d4e6SAurelien Jarno if (temps[temp].state == TCG_TEMP_COPY) { 59e590d4e6SAurelien Jarno if (temps[temp].prev_copy == temps[temp].next_copy) { 60e590d4e6SAurelien Jarno temps[temps[temp].next_copy].state = TCG_TEMP_UNDEF; 6122613af4SKirill Batuzov } else { 6222613af4SKirill Batuzov temps[temps[temp].next_copy].prev_copy = temps[temp].prev_copy; 6322613af4SKirill Batuzov temps[temps[temp].prev_copy].next_copy = temps[temp].next_copy; 64e590d4e6SAurelien Jarno } 6522613af4SKirill Batuzov } 6648b56ce1SAurelien Jarno temps[temp].state = TCG_TEMP_UNDEF; 67*3a9d8b17SPaolo Bonzini temps[temp].mask = -1; 6822613af4SKirill Batuzov } 6922613af4SKirill Batuzov 70d193a14aSPaolo Bonzini /* Reset all temporaries, given that there are NB_TEMPS of them. */ 71d193a14aSPaolo Bonzini static void reset_all_temps(int nb_temps) 72d193a14aSPaolo Bonzini { 73d193a14aSPaolo Bonzini int i; 74d193a14aSPaolo Bonzini for (i = 0; i < nb_temps; i++) { 75d193a14aSPaolo Bonzini temps[i].state = TCG_TEMP_UNDEF; 76*3a9d8b17SPaolo Bonzini temps[i].mask = -1; 77d193a14aSPaolo Bonzini } 78d193a14aSPaolo Bonzini } 79d193a14aSPaolo Bonzini 80fe0de7aaSBlue Swirl static int op_bits(TCGOpcode op) 8122613af4SKirill Batuzov { 828399ad59SRichard Henderson const TCGOpDef *def = &tcg_op_defs[op]; 838399ad59SRichard Henderson return def->flags & TCG_OPF_64BIT ? 64 : 32; 8422613af4SKirill Batuzov } 8522613af4SKirill Batuzov 86fe0de7aaSBlue Swirl static TCGOpcode op_to_movi(TCGOpcode op) 8722613af4SKirill Batuzov { 8822613af4SKirill Batuzov switch (op_bits(op)) { 8922613af4SKirill Batuzov case 32: 9022613af4SKirill Batuzov return INDEX_op_movi_i32; 9122613af4SKirill Batuzov case 64: 9222613af4SKirill Batuzov return INDEX_op_movi_i64; 9322613af4SKirill Batuzov default: 9422613af4SKirill Batuzov fprintf(stderr, "op_to_movi: unexpected return value of " 9522613af4SKirill Batuzov "function op_bits.\n"); 9622613af4SKirill Batuzov tcg_abort(); 9722613af4SKirill Batuzov } 9822613af4SKirill Batuzov } 9922613af4SKirill Batuzov 100e590d4e6SAurelien Jarno static TCGArg find_better_copy(TCGContext *s, TCGArg temp) 101e590d4e6SAurelien Jarno { 102e590d4e6SAurelien Jarno TCGArg i; 103e590d4e6SAurelien Jarno 104e590d4e6SAurelien Jarno /* If this is already a global, we can't do better. */ 105e590d4e6SAurelien Jarno if (temp < s->nb_globals) { 106e590d4e6SAurelien Jarno return temp; 107e590d4e6SAurelien Jarno } 108e590d4e6SAurelien Jarno 109e590d4e6SAurelien Jarno /* Search for a global first. */ 110e590d4e6SAurelien Jarno for (i = temps[temp].next_copy ; i != temp ; i = temps[i].next_copy) { 111e590d4e6SAurelien Jarno if (i < s->nb_globals) { 112e590d4e6SAurelien Jarno return i; 113e590d4e6SAurelien Jarno } 114e590d4e6SAurelien Jarno } 115e590d4e6SAurelien Jarno 116e590d4e6SAurelien Jarno /* If it is a temp, search for a temp local. */ 117e590d4e6SAurelien Jarno if (!s->temps[temp].temp_local) { 118e590d4e6SAurelien Jarno for (i = temps[temp].next_copy ; i != temp ; i = temps[i].next_copy) { 119e590d4e6SAurelien Jarno if (s->temps[i].temp_local) { 120e590d4e6SAurelien Jarno return i; 121e590d4e6SAurelien Jarno } 122e590d4e6SAurelien Jarno } 123e590d4e6SAurelien Jarno } 124e590d4e6SAurelien Jarno 125e590d4e6SAurelien Jarno /* Failure to find a better representation, return the same temp. */ 126e590d4e6SAurelien Jarno return temp; 127e590d4e6SAurelien Jarno } 128e590d4e6SAurelien Jarno 129e590d4e6SAurelien Jarno static bool temps_are_copies(TCGArg arg1, TCGArg arg2) 130e590d4e6SAurelien Jarno { 131e590d4e6SAurelien Jarno TCGArg i; 132e590d4e6SAurelien Jarno 133e590d4e6SAurelien Jarno if (arg1 == arg2) { 134e590d4e6SAurelien Jarno return true; 135e590d4e6SAurelien Jarno } 136e590d4e6SAurelien Jarno 137e590d4e6SAurelien Jarno if (temps[arg1].state != TCG_TEMP_COPY 138e590d4e6SAurelien Jarno || temps[arg2].state != TCG_TEMP_COPY) { 139e590d4e6SAurelien Jarno return false; 140e590d4e6SAurelien Jarno } 141e590d4e6SAurelien Jarno 142e590d4e6SAurelien Jarno for (i = temps[arg1].next_copy ; i != arg1 ; i = temps[i].next_copy) { 143e590d4e6SAurelien Jarno if (i == arg2) { 144e590d4e6SAurelien Jarno return true; 145e590d4e6SAurelien Jarno } 146e590d4e6SAurelien Jarno } 147e590d4e6SAurelien Jarno 148e590d4e6SAurelien Jarno return false; 149e590d4e6SAurelien Jarno } 150e590d4e6SAurelien Jarno 151b80bb016SAurelien Jarno static void tcg_opt_gen_mov(TCGContext *s, TCGArg *gen_args, 152b80bb016SAurelien Jarno TCGArg dst, TCGArg src) 15322613af4SKirill Batuzov { 154e590d4e6SAurelien Jarno reset_temp(dst); 155*3a9d8b17SPaolo Bonzini temps[dst].mask = temps[src].mask; 15622613af4SKirill Batuzov assert(temps[src].state != TCG_TEMP_CONST); 157e590d4e6SAurelien Jarno 158e590d4e6SAurelien Jarno if (s->temps[src].type == s->temps[dst].type) { 159e590d4e6SAurelien Jarno if (temps[src].state != TCG_TEMP_COPY) { 160e590d4e6SAurelien Jarno temps[src].state = TCG_TEMP_COPY; 16122613af4SKirill Batuzov temps[src].next_copy = src; 16222613af4SKirill Batuzov temps[src].prev_copy = src; 16322613af4SKirill Batuzov } 16422613af4SKirill Batuzov temps[dst].state = TCG_TEMP_COPY; 16522613af4SKirill Batuzov temps[dst].next_copy = temps[src].next_copy; 16622613af4SKirill Batuzov temps[dst].prev_copy = src; 16722613af4SKirill Batuzov temps[temps[dst].next_copy].prev_copy = dst; 16822613af4SKirill Batuzov temps[src].next_copy = dst; 16922613af4SKirill Batuzov } 170e590d4e6SAurelien Jarno 17122613af4SKirill Batuzov gen_args[0] = dst; 17222613af4SKirill Batuzov gen_args[1] = src; 17322613af4SKirill Batuzov } 17422613af4SKirill Batuzov 175e590d4e6SAurelien Jarno static void tcg_opt_gen_movi(TCGArg *gen_args, TCGArg dst, TCGArg val) 17622613af4SKirill Batuzov { 177e590d4e6SAurelien Jarno reset_temp(dst); 17822613af4SKirill Batuzov temps[dst].state = TCG_TEMP_CONST; 17922613af4SKirill Batuzov temps[dst].val = val; 180*3a9d8b17SPaolo Bonzini temps[dst].mask = val; 18122613af4SKirill Batuzov gen_args[0] = dst; 18222613af4SKirill Batuzov gen_args[1] = val; 18322613af4SKirill Batuzov } 18422613af4SKirill Batuzov 185fe0de7aaSBlue Swirl static TCGOpcode op_to_mov(TCGOpcode op) 18653108fb5SKirill Batuzov { 18753108fb5SKirill Batuzov switch (op_bits(op)) { 18853108fb5SKirill Batuzov case 32: 18953108fb5SKirill Batuzov return INDEX_op_mov_i32; 19053108fb5SKirill Batuzov case 64: 19153108fb5SKirill Batuzov return INDEX_op_mov_i64; 19253108fb5SKirill Batuzov default: 19353108fb5SKirill Batuzov fprintf(stderr, "op_to_mov: unexpected return value of " 19453108fb5SKirill Batuzov "function op_bits.\n"); 19553108fb5SKirill Batuzov tcg_abort(); 19653108fb5SKirill Batuzov } 19753108fb5SKirill Batuzov } 19853108fb5SKirill Batuzov 199fe0de7aaSBlue Swirl static TCGArg do_constant_folding_2(TCGOpcode op, TCGArg x, TCGArg y) 20053108fb5SKirill Batuzov { 20153108fb5SKirill Batuzov switch (op) { 20253108fb5SKirill Batuzov CASE_OP_32_64(add): 20353108fb5SKirill Batuzov return x + y; 20453108fb5SKirill Batuzov 20553108fb5SKirill Batuzov CASE_OP_32_64(sub): 20653108fb5SKirill Batuzov return x - y; 20753108fb5SKirill Batuzov 20853108fb5SKirill Batuzov CASE_OP_32_64(mul): 20953108fb5SKirill Batuzov return x * y; 21053108fb5SKirill Batuzov 2119a81090bSKirill Batuzov CASE_OP_32_64(and): 2129a81090bSKirill Batuzov return x & y; 2139a81090bSKirill Batuzov 2149a81090bSKirill Batuzov CASE_OP_32_64(or): 2159a81090bSKirill Batuzov return x | y; 2169a81090bSKirill Batuzov 2179a81090bSKirill Batuzov CASE_OP_32_64(xor): 2189a81090bSKirill Batuzov return x ^ y; 2199a81090bSKirill Batuzov 22055c0975cSKirill Batuzov case INDEX_op_shl_i32: 22155c0975cSKirill Batuzov return (uint32_t)x << (uint32_t)y; 22255c0975cSKirill Batuzov 22355c0975cSKirill Batuzov case INDEX_op_shl_i64: 22455c0975cSKirill Batuzov return (uint64_t)x << (uint64_t)y; 22555c0975cSKirill Batuzov 22655c0975cSKirill Batuzov case INDEX_op_shr_i32: 22755c0975cSKirill Batuzov return (uint32_t)x >> (uint32_t)y; 22855c0975cSKirill Batuzov 22955c0975cSKirill Batuzov case INDEX_op_shr_i64: 23055c0975cSKirill Batuzov return (uint64_t)x >> (uint64_t)y; 23155c0975cSKirill Batuzov 23255c0975cSKirill Batuzov case INDEX_op_sar_i32: 23355c0975cSKirill Batuzov return (int32_t)x >> (int32_t)y; 23455c0975cSKirill Batuzov 23555c0975cSKirill Batuzov case INDEX_op_sar_i64: 23655c0975cSKirill Batuzov return (int64_t)x >> (int64_t)y; 23755c0975cSKirill Batuzov 23855c0975cSKirill Batuzov case INDEX_op_rotr_i32: 23925c4d9ccSRichard Henderson x = ((uint32_t)x << (32 - y)) | ((uint32_t)x >> y); 24055c0975cSKirill Batuzov return x; 24155c0975cSKirill Batuzov 24255c0975cSKirill Batuzov case INDEX_op_rotr_i64: 24325c4d9ccSRichard Henderson x = ((uint64_t)x << (64 - y)) | ((uint64_t)x >> y); 24455c0975cSKirill Batuzov return x; 24555c0975cSKirill Batuzov 24655c0975cSKirill Batuzov case INDEX_op_rotl_i32: 24725c4d9ccSRichard Henderson x = ((uint32_t)x << y) | ((uint32_t)x >> (32 - y)); 24855c0975cSKirill Batuzov return x; 24955c0975cSKirill Batuzov 25055c0975cSKirill Batuzov case INDEX_op_rotl_i64: 25125c4d9ccSRichard Henderson x = ((uint64_t)x << y) | ((uint64_t)x >> (64 - y)); 25255c0975cSKirill Batuzov return x; 25355c0975cSKirill Batuzov 25425c4d9ccSRichard Henderson CASE_OP_32_64(not): 255a640f031SKirill Batuzov return ~x; 256a640f031SKirill Batuzov 257cb25c80aSRichard Henderson CASE_OP_32_64(neg): 258cb25c80aSRichard Henderson return -x; 259cb25c80aSRichard Henderson 260cb25c80aSRichard Henderson CASE_OP_32_64(andc): 261cb25c80aSRichard Henderson return x & ~y; 262cb25c80aSRichard Henderson 263cb25c80aSRichard Henderson CASE_OP_32_64(orc): 264cb25c80aSRichard Henderson return x | ~y; 265cb25c80aSRichard Henderson 266cb25c80aSRichard Henderson CASE_OP_32_64(eqv): 267cb25c80aSRichard Henderson return ~(x ^ y); 268cb25c80aSRichard Henderson 269cb25c80aSRichard Henderson CASE_OP_32_64(nand): 270cb25c80aSRichard Henderson return ~(x & y); 271cb25c80aSRichard Henderson 272cb25c80aSRichard Henderson CASE_OP_32_64(nor): 273cb25c80aSRichard Henderson return ~(x | y); 274cb25c80aSRichard Henderson 27525c4d9ccSRichard Henderson CASE_OP_32_64(ext8s): 276a640f031SKirill Batuzov return (int8_t)x; 277a640f031SKirill Batuzov 27825c4d9ccSRichard Henderson CASE_OP_32_64(ext16s): 279a640f031SKirill Batuzov return (int16_t)x; 280a640f031SKirill Batuzov 28125c4d9ccSRichard Henderson CASE_OP_32_64(ext8u): 282a640f031SKirill Batuzov return (uint8_t)x; 283a640f031SKirill Batuzov 28425c4d9ccSRichard Henderson CASE_OP_32_64(ext16u): 285a640f031SKirill Batuzov return (uint16_t)x; 286a640f031SKirill Batuzov 287a640f031SKirill Batuzov case INDEX_op_ext32s_i64: 288a640f031SKirill Batuzov return (int32_t)x; 289a640f031SKirill Batuzov 290a640f031SKirill Batuzov case INDEX_op_ext32u_i64: 291a640f031SKirill Batuzov return (uint32_t)x; 292a640f031SKirill Batuzov 29353108fb5SKirill Batuzov default: 29453108fb5SKirill Batuzov fprintf(stderr, 29553108fb5SKirill Batuzov "Unrecognized operation %d in do_constant_folding.\n", op); 29653108fb5SKirill Batuzov tcg_abort(); 29753108fb5SKirill Batuzov } 29853108fb5SKirill Batuzov } 29953108fb5SKirill Batuzov 300fe0de7aaSBlue Swirl static TCGArg do_constant_folding(TCGOpcode op, TCGArg x, TCGArg y) 30153108fb5SKirill Batuzov { 30253108fb5SKirill Batuzov TCGArg res = do_constant_folding_2(op, x, y); 30353108fb5SKirill Batuzov if (op_bits(op) == 32) { 30453108fb5SKirill Batuzov res &= 0xffffffff; 30553108fb5SKirill Batuzov } 30653108fb5SKirill Batuzov return res; 30753108fb5SKirill Batuzov } 30853108fb5SKirill Batuzov 3099519da7eSRichard Henderson static bool do_constant_folding_cond_32(uint32_t x, uint32_t y, TCGCond c) 310f8dd19e5SAurelien Jarno { 311f8dd19e5SAurelien Jarno switch (c) { 312f8dd19e5SAurelien Jarno case TCG_COND_EQ: 3139519da7eSRichard Henderson return x == y; 314f8dd19e5SAurelien Jarno case TCG_COND_NE: 3159519da7eSRichard Henderson return x != y; 316f8dd19e5SAurelien Jarno case TCG_COND_LT: 3179519da7eSRichard Henderson return (int32_t)x < (int32_t)y; 318f8dd19e5SAurelien Jarno case TCG_COND_GE: 3199519da7eSRichard Henderson return (int32_t)x >= (int32_t)y; 320f8dd19e5SAurelien Jarno case TCG_COND_LE: 3219519da7eSRichard Henderson return (int32_t)x <= (int32_t)y; 322f8dd19e5SAurelien Jarno case TCG_COND_GT: 3239519da7eSRichard Henderson return (int32_t)x > (int32_t)y; 324f8dd19e5SAurelien Jarno case TCG_COND_LTU: 3259519da7eSRichard Henderson return x < y; 326f8dd19e5SAurelien Jarno case TCG_COND_GEU: 3279519da7eSRichard Henderson return x >= y; 328f8dd19e5SAurelien Jarno case TCG_COND_LEU: 3299519da7eSRichard Henderson return x <= y; 330f8dd19e5SAurelien Jarno case TCG_COND_GTU: 3319519da7eSRichard Henderson return x > y; 3320aed257fSRichard Henderson default: 3339519da7eSRichard Henderson tcg_abort(); 334f8dd19e5SAurelien Jarno } 3359519da7eSRichard Henderson } 3369519da7eSRichard Henderson 3379519da7eSRichard Henderson static bool do_constant_folding_cond_64(uint64_t x, uint64_t y, TCGCond c) 3389519da7eSRichard Henderson { 339f8dd19e5SAurelien Jarno switch (c) { 340f8dd19e5SAurelien Jarno case TCG_COND_EQ: 3419519da7eSRichard Henderson return x == y; 342f8dd19e5SAurelien Jarno case TCG_COND_NE: 3439519da7eSRichard Henderson return x != y; 344f8dd19e5SAurelien Jarno case TCG_COND_LT: 3459519da7eSRichard Henderson return (int64_t)x < (int64_t)y; 346f8dd19e5SAurelien Jarno case TCG_COND_GE: 3479519da7eSRichard Henderson return (int64_t)x >= (int64_t)y; 348f8dd19e5SAurelien Jarno case TCG_COND_LE: 3499519da7eSRichard Henderson return (int64_t)x <= (int64_t)y; 350f8dd19e5SAurelien Jarno case TCG_COND_GT: 3519519da7eSRichard Henderson return (int64_t)x > (int64_t)y; 352f8dd19e5SAurelien Jarno case TCG_COND_LTU: 3539519da7eSRichard Henderson return x < y; 354f8dd19e5SAurelien Jarno case TCG_COND_GEU: 3559519da7eSRichard Henderson return x >= y; 356f8dd19e5SAurelien Jarno case TCG_COND_LEU: 3579519da7eSRichard Henderson return x <= y; 358f8dd19e5SAurelien Jarno case TCG_COND_GTU: 3599519da7eSRichard Henderson return x > y; 3600aed257fSRichard Henderson default: 3619519da7eSRichard Henderson tcg_abort(); 362f8dd19e5SAurelien Jarno } 363f8dd19e5SAurelien Jarno } 3649519da7eSRichard Henderson 3659519da7eSRichard Henderson static bool do_constant_folding_cond_eq(TCGCond c) 3669519da7eSRichard Henderson { 367b336ceb6SAurelien Jarno switch (c) { 368b336ceb6SAurelien Jarno case TCG_COND_GT: 369b336ceb6SAurelien Jarno case TCG_COND_LTU: 370b336ceb6SAurelien Jarno case TCG_COND_LT: 371b336ceb6SAurelien Jarno case TCG_COND_GTU: 372b336ceb6SAurelien Jarno case TCG_COND_NE: 373b336ceb6SAurelien Jarno return 0; 374b336ceb6SAurelien Jarno case TCG_COND_GE: 375b336ceb6SAurelien Jarno case TCG_COND_GEU: 376b336ceb6SAurelien Jarno case TCG_COND_LE: 377b336ceb6SAurelien Jarno case TCG_COND_LEU: 378b336ceb6SAurelien Jarno case TCG_COND_EQ: 379b336ceb6SAurelien Jarno return 1; 3800aed257fSRichard Henderson default: 3819519da7eSRichard Henderson tcg_abort(); 382b336ceb6SAurelien Jarno } 3839519da7eSRichard Henderson } 3849519da7eSRichard Henderson 3859519da7eSRichard Henderson /* Return 2 if the condition can't be simplified, and the result 3869519da7eSRichard Henderson of the condition (0 or 1) if it can */ 3879519da7eSRichard Henderson static TCGArg do_constant_folding_cond(TCGOpcode op, TCGArg x, 3889519da7eSRichard Henderson TCGArg y, TCGCond c) 3899519da7eSRichard Henderson { 3909519da7eSRichard Henderson if (temps[x].state == TCG_TEMP_CONST && temps[y].state == TCG_TEMP_CONST) { 3919519da7eSRichard Henderson switch (op_bits(op)) { 3929519da7eSRichard Henderson case 32: 3939519da7eSRichard Henderson return do_constant_folding_cond_32(temps[x].val, temps[y].val, c); 3949519da7eSRichard Henderson case 64: 3959519da7eSRichard Henderson return do_constant_folding_cond_64(temps[x].val, temps[y].val, c); 3969519da7eSRichard Henderson default: 3979519da7eSRichard Henderson tcg_abort(); 3989519da7eSRichard Henderson } 3999519da7eSRichard Henderson } else if (temps_are_copies(x, y)) { 4009519da7eSRichard Henderson return do_constant_folding_cond_eq(c); 401b336ceb6SAurelien Jarno } else if (temps[y].state == TCG_TEMP_CONST && temps[y].val == 0) { 402b336ceb6SAurelien Jarno switch (c) { 403b336ceb6SAurelien Jarno case TCG_COND_LTU: 404b336ceb6SAurelien Jarno return 0; 405b336ceb6SAurelien Jarno case TCG_COND_GEU: 406b336ceb6SAurelien Jarno return 1; 407b336ceb6SAurelien Jarno default: 408b336ceb6SAurelien Jarno return 2; 409b336ceb6SAurelien Jarno } 410b336ceb6SAurelien Jarno } else { 411b336ceb6SAurelien Jarno return 2; 412b336ceb6SAurelien Jarno } 413f8dd19e5SAurelien Jarno } 414f8dd19e5SAurelien Jarno 4156c4382f8SRichard Henderson /* Return 2 if the condition can't be simplified, and the result 4166c4382f8SRichard Henderson of the condition (0 or 1) if it can */ 4176c4382f8SRichard Henderson static TCGArg do_constant_folding_cond2(TCGArg *p1, TCGArg *p2, TCGCond c) 4186c4382f8SRichard Henderson { 4196c4382f8SRichard Henderson TCGArg al = p1[0], ah = p1[1]; 4206c4382f8SRichard Henderson TCGArg bl = p2[0], bh = p2[1]; 4216c4382f8SRichard Henderson 4226c4382f8SRichard Henderson if (temps[bl].state == TCG_TEMP_CONST 4236c4382f8SRichard Henderson && temps[bh].state == TCG_TEMP_CONST) { 4246c4382f8SRichard Henderson uint64_t b = ((uint64_t)temps[bh].val << 32) | (uint32_t)temps[bl].val; 4256c4382f8SRichard Henderson 4266c4382f8SRichard Henderson if (temps[al].state == TCG_TEMP_CONST 4276c4382f8SRichard Henderson && temps[ah].state == TCG_TEMP_CONST) { 4286c4382f8SRichard Henderson uint64_t a; 4296c4382f8SRichard Henderson a = ((uint64_t)temps[ah].val << 32) | (uint32_t)temps[al].val; 4306c4382f8SRichard Henderson return do_constant_folding_cond_64(a, b, c); 4316c4382f8SRichard Henderson } 4326c4382f8SRichard Henderson if (b == 0) { 4336c4382f8SRichard Henderson switch (c) { 4346c4382f8SRichard Henderson case TCG_COND_LTU: 4356c4382f8SRichard Henderson return 0; 4366c4382f8SRichard Henderson case TCG_COND_GEU: 4376c4382f8SRichard Henderson return 1; 4386c4382f8SRichard Henderson default: 4396c4382f8SRichard Henderson break; 4406c4382f8SRichard Henderson } 4416c4382f8SRichard Henderson } 4426c4382f8SRichard Henderson } 4436c4382f8SRichard Henderson if (temps_are_copies(al, bl) && temps_are_copies(ah, bh)) { 4446c4382f8SRichard Henderson return do_constant_folding_cond_eq(c); 4456c4382f8SRichard Henderson } 4466c4382f8SRichard Henderson return 2; 4476c4382f8SRichard Henderson } 4486c4382f8SRichard Henderson 44924c9ae4eSRichard Henderson static bool swap_commutative(TCGArg dest, TCGArg *p1, TCGArg *p2) 45024c9ae4eSRichard Henderson { 45124c9ae4eSRichard Henderson TCGArg a1 = *p1, a2 = *p2; 45224c9ae4eSRichard Henderson int sum = 0; 45324c9ae4eSRichard Henderson sum += temps[a1].state == TCG_TEMP_CONST; 45424c9ae4eSRichard Henderson sum -= temps[a2].state == TCG_TEMP_CONST; 45524c9ae4eSRichard Henderson 45624c9ae4eSRichard Henderson /* Prefer the constant in second argument, and then the form 45724c9ae4eSRichard Henderson op a, a, b, which is better handled on non-RISC hosts. */ 45824c9ae4eSRichard Henderson if (sum > 0 || (sum == 0 && dest == a2)) { 45924c9ae4eSRichard Henderson *p1 = a2; 46024c9ae4eSRichard Henderson *p2 = a1; 46124c9ae4eSRichard Henderson return true; 46224c9ae4eSRichard Henderson } 46324c9ae4eSRichard Henderson return false; 46424c9ae4eSRichard Henderson } 46524c9ae4eSRichard Henderson 4660bfcb865SRichard Henderson static bool swap_commutative2(TCGArg *p1, TCGArg *p2) 4670bfcb865SRichard Henderson { 4680bfcb865SRichard Henderson int sum = 0; 4690bfcb865SRichard Henderson sum += temps[p1[0]].state == TCG_TEMP_CONST; 4700bfcb865SRichard Henderson sum += temps[p1[1]].state == TCG_TEMP_CONST; 4710bfcb865SRichard Henderson sum -= temps[p2[0]].state == TCG_TEMP_CONST; 4720bfcb865SRichard Henderson sum -= temps[p2[1]].state == TCG_TEMP_CONST; 4730bfcb865SRichard Henderson if (sum > 0) { 4740bfcb865SRichard Henderson TCGArg t; 4750bfcb865SRichard Henderson t = p1[0], p1[0] = p2[0], p2[0] = t; 4760bfcb865SRichard Henderson t = p1[1], p1[1] = p2[1], p2[1] = t; 4770bfcb865SRichard Henderson return true; 4780bfcb865SRichard Henderson } 4790bfcb865SRichard Henderson return false; 4800bfcb865SRichard Henderson } 4810bfcb865SRichard Henderson 48222613af4SKirill Batuzov /* Propagate constants and copies, fold constant expressions. */ 4838f2e8c07SKirill Batuzov static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, 4848f2e8c07SKirill Batuzov TCGArg *args, TCGOpDef *tcg_op_defs) 4858f2e8c07SKirill Batuzov { 486fe0de7aaSBlue Swirl int i, nb_ops, op_index, nb_temps, nb_globals, nb_call_args; 487*3a9d8b17SPaolo Bonzini tcg_target_ulong mask; 488fe0de7aaSBlue Swirl TCGOpcode op; 4898f2e8c07SKirill Batuzov const TCGOpDef *def; 4908f2e8c07SKirill Batuzov TCGArg *gen_args; 49153108fb5SKirill Batuzov TCGArg tmp; 4925d8f5363SRichard Henderson 49322613af4SKirill Batuzov /* Array VALS has an element for each temp. 49422613af4SKirill Batuzov If this temp holds a constant then its value is kept in VALS' element. 495e590d4e6SAurelien Jarno If this temp is a copy of other ones then the other copies are 496e590d4e6SAurelien Jarno available through the doubly linked circular list. */ 4978f2e8c07SKirill Batuzov 4988f2e8c07SKirill Batuzov nb_temps = s->nb_temps; 4998f2e8c07SKirill Batuzov nb_globals = s->nb_globals; 500d193a14aSPaolo Bonzini reset_all_temps(nb_temps); 5018f2e8c07SKirill Batuzov 50292414b31SEvgeny Voevodin nb_ops = tcg_opc_ptr - s->gen_opc_buf; 5038f2e8c07SKirill Batuzov gen_args = args; 5048f2e8c07SKirill Batuzov for (op_index = 0; op_index < nb_ops; op_index++) { 50592414b31SEvgeny Voevodin op = s->gen_opc_buf[op_index]; 5068f2e8c07SKirill Batuzov def = &tcg_op_defs[op]; 50722613af4SKirill Batuzov /* Do copy propagation */ 5081ff8c541SAurelien Jarno if (op == INDEX_op_call) { 5091ff8c541SAurelien Jarno int nb_oargs = args[0] >> 16; 5101ff8c541SAurelien Jarno int nb_iargs = args[0] & 0xffff; 5111ff8c541SAurelien Jarno for (i = nb_oargs + 1; i < nb_oargs + nb_iargs + 1; i++) { 5121ff8c541SAurelien Jarno if (temps[args[i]].state == TCG_TEMP_COPY) { 5131ff8c541SAurelien Jarno args[i] = find_better_copy(s, args[i]); 5141ff8c541SAurelien Jarno } 5151ff8c541SAurelien Jarno } 5161ff8c541SAurelien Jarno } else { 51722613af4SKirill Batuzov for (i = def->nb_oargs; i < def->nb_oargs + def->nb_iargs; i++) { 51822613af4SKirill Batuzov if (temps[args[i]].state == TCG_TEMP_COPY) { 519e590d4e6SAurelien Jarno args[i] = find_better_copy(s, args[i]); 52022613af4SKirill Batuzov } 52122613af4SKirill Batuzov } 52222613af4SKirill Batuzov } 52322613af4SKirill Batuzov 52453108fb5SKirill Batuzov /* For commutative operations make constant second argument */ 52553108fb5SKirill Batuzov switch (op) { 52653108fb5SKirill Batuzov CASE_OP_32_64(add): 52753108fb5SKirill Batuzov CASE_OP_32_64(mul): 5289a81090bSKirill Batuzov CASE_OP_32_64(and): 5299a81090bSKirill Batuzov CASE_OP_32_64(or): 5309a81090bSKirill Batuzov CASE_OP_32_64(xor): 531cb25c80aSRichard Henderson CASE_OP_32_64(eqv): 532cb25c80aSRichard Henderson CASE_OP_32_64(nand): 533cb25c80aSRichard Henderson CASE_OP_32_64(nor): 53424c9ae4eSRichard Henderson swap_commutative(args[0], &args[1], &args[2]); 53553108fb5SKirill Batuzov break; 53665a7cce1SAurelien Jarno CASE_OP_32_64(brcond): 53724c9ae4eSRichard Henderson if (swap_commutative(-1, &args[0], &args[1])) { 53865a7cce1SAurelien Jarno args[2] = tcg_swap_cond(args[2]); 53965a7cce1SAurelien Jarno } 54065a7cce1SAurelien Jarno break; 54165a7cce1SAurelien Jarno CASE_OP_32_64(setcond): 54224c9ae4eSRichard Henderson if (swap_commutative(args[0], &args[1], &args[2])) { 54365a7cce1SAurelien Jarno args[3] = tcg_swap_cond(args[3]); 54465a7cce1SAurelien Jarno } 54565a7cce1SAurelien Jarno break; 546fa01a208SRichard Henderson CASE_OP_32_64(movcond): 54724c9ae4eSRichard Henderson if (swap_commutative(-1, &args[1], &args[2])) { 54824c9ae4eSRichard Henderson args[5] = tcg_swap_cond(args[5]); 549fa01a208SRichard Henderson } 5505d8f5363SRichard Henderson /* For movcond, we canonicalize the "false" input reg to match 5515d8f5363SRichard Henderson the destination reg so that the tcg backend can implement 5525d8f5363SRichard Henderson a "move if true" operation. */ 55324c9ae4eSRichard Henderson if (swap_commutative(args[0], &args[4], &args[3])) { 55424c9ae4eSRichard Henderson args[5] = tcg_invert_cond(args[5]); 5555d8f5363SRichard Henderson } 5561e484e61SRichard Henderson break; 5571e484e61SRichard Henderson case INDEX_op_add2_i32: 5581e484e61SRichard Henderson swap_commutative(args[0], &args[2], &args[4]); 5591e484e61SRichard Henderson swap_commutative(args[1], &args[3], &args[5]); 5601e484e61SRichard Henderson break; 5611414968aSRichard Henderson case INDEX_op_mulu2_i32: 5621414968aSRichard Henderson swap_commutative(args[0], &args[2], &args[3]); 5631414968aSRichard Henderson break; 5640bfcb865SRichard Henderson case INDEX_op_brcond2_i32: 5650bfcb865SRichard Henderson if (swap_commutative2(&args[0], &args[2])) { 5660bfcb865SRichard Henderson args[4] = tcg_swap_cond(args[4]); 5670bfcb865SRichard Henderson } 5680bfcb865SRichard Henderson break; 5690bfcb865SRichard Henderson case INDEX_op_setcond2_i32: 5700bfcb865SRichard Henderson if (swap_commutative2(&args[1], &args[3])) { 5710bfcb865SRichard Henderson args[5] = tcg_swap_cond(args[5]); 5720bfcb865SRichard Henderson } 5730bfcb865SRichard Henderson break; 57453108fb5SKirill Batuzov default: 57553108fb5SKirill Batuzov break; 57653108fb5SKirill Batuzov } 57753108fb5SKirill Batuzov 57801ee5282SAurelien Jarno /* Simplify expressions for "shift/rot r, 0, a => movi r, 0" */ 57901ee5282SAurelien Jarno switch (op) { 58001ee5282SAurelien Jarno CASE_OP_32_64(shl): 58101ee5282SAurelien Jarno CASE_OP_32_64(shr): 58201ee5282SAurelien Jarno CASE_OP_32_64(sar): 58301ee5282SAurelien Jarno CASE_OP_32_64(rotl): 58401ee5282SAurelien Jarno CASE_OP_32_64(rotr): 58501ee5282SAurelien Jarno if (temps[args[1]].state == TCG_TEMP_CONST 58601ee5282SAurelien Jarno && temps[args[1]].val == 0) { 58792414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = op_to_movi(op); 588e590d4e6SAurelien Jarno tcg_opt_gen_movi(gen_args, args[0], 0); 58901ee5282SAurelien Jarno args += 3; 59001ee5282SAurelien Jarno gen_args += 2; 59101ee5282SAurelien Jarno continue; 59201ee5282SAurelien Jarno } 59301ee5282SAurelien Jarno break; 59401ee5282SAurelien Jarno default: 59501ee5282SAurelien Jarno break; 59601ee5282SAurelien Jarno } 59701ee5282SAurelien Jarno 59856e49438SAurelien Jarno /* Simplify expression for "op r, a, 0 => mov r, a" cases */ 59953108fb5SKirill Batuzov switch (op) { 60053108fb5SKirill Batuzov CASE_OP_32_64(add): 60153108fb5SKirill Batuzov CASE_OP_32_64(sub): 60255c0975cSKirill Batuzov CASE_OP_32_64(shl): 60355c0975cSKirill Batuzov CASE_OP_32_64(shr): 60455c0975cSKirill Batuzov CASE_OP_32_64(sar): 60525c4d9ccSRichard Henderson CASE_OP_32_64(rotl): 60625c4d9ccSRichard Henderson CASE_OP_32_64(rotr): 60738ee188bSAurelien Jarno CASE_OP_32_64(or): 60838ee188bSAurelien Jarno CASE_OP_32_64(xor): 60953108fb5SKirill Batuzov if (temps[args[1]].state == TCG_TEMP_CONST) { 61053108fb5SKirill Batuzov /* Proceed with possible constant folding. */ 61153108fb5SKirill Batuzov break; 61253108fb5SKirill Batuzov } 61353108fb5SKirill Batuzov if (temps[args[2]].state == TCG_TEMP_CONST 61453108fb5SKirill Batuzov && temps[args[2]].val == 0) { 615e590d4e6SAurelien Jarno if (temps_are_copies(args[0], args[1])) { 61692414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = INDEX_op_nop; 61753108fb5SKirill Batuzov } else { 61892414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = op_to_mov(op); 619b80bb016SAurelien Jarno tcg_opt_gen_mov(s, gen_args, args[0], args[1]); 62053108fb5SKirill Batuzov gen_args += 2; 62153108fb5SKirill Batuzov } 622fedc0da2SAurelien Jarno args += 3; 62353108fb5SKirill Batuzov continue; 62453108fb5SKirill Batuzov } 62553108fb5SKirill Batuzov break; 62656e49438SAurelien Jarno default: 62756e49438SAurelien Jarno break; 62856e49438SAurelien Jarno } 62956e49438SAurelien Jarno 630*3a9d8b17SPaolo Bonzini /* Simplify using known-zero bits */ 631*3a9d8b17SPaolo Bonzini mask = -1; 632*3a9d8b17SPaolo Bonzini switch (op) { 633*3a9d8b17SPaolo Bonzini CASE_OP_32_64(ext8s): 634*3a9d8b17SPaolo Bonzini if ((temps[args[1]].mask & 0x80) != 0) { 635*3a9d8b17SPaolo Bonzini break; 636*3a9d8b17SPaolo Bonzini } 637*3a9d8b17SPaolo Bonzini CASE_OP_32_64(ext8u): 638*3a9d8b17SPaolo Bonzini mask = 0xff; 639*3a9d8b17SPaolo Bonzini goto and_const; 640*3a9d8b17SPaolo Bonzini CASE_OP_32_64(ext16s): 641*3a9d8b17SPaolo Bonzini if ((temps[args[1]].mask & 0x8000) != 0) { 642*3a9d8b17SPaolo Bonzini break; 643*3a9d8b17SPaolo Bonzini } 644*3a9d8b17SPaolo Bonzini CASE_OP_32_64(ext16u): 645*3a9d8b17SPaolo Bonzini mask = 0xffff; 646*3a9d8b17SPaolo Bonzini goto and_const; 647*3a9d8b17SPaolo Bonzini case INDEX_op_ext32s_i64: 648*3a9d8b17SPaolo Bonzini if ((temps[args[1]].mask & 0x80000000) != 0) { 649*3a9d8b17SPaolo Bonzini break; 650*3a9d8b17SPaolo Bonzini } 651*3a9d8b17SPaolo Bonzini case INDEX_op_ext32u_i64: 652*3a9d8b17SPaolo Bonzini mask = 0xffffffffU; 653*3a9d8b17SPaolo Bonzini goto and_const; 654*3a9d8b17SPaolo Bonzini 655*3a9d8b17SPaolo Bonzini CASE_OP_32_64(and): 656*3a9d8b17SPaolo Bonzini mask = temps[args[2]].mask; 657*3a9d8b17SPaolo Bonzini if (temps[args[2]].state == TCG_TEMP_CONST) { 658*3a9d8b17SPaolo Bonzini and_const: 659*3a9d8b17SPaolo Bonzini ; 660*3a9d8b17SPaolo Bonzini } 661*3a9d8b17SPaolo Bonzini mask = temps[args[1]].mask & mask; 662*3a9d8b17SPaolo Bonzini break; 663*3a9d8b17SPaolo Bonzini 664*3a9d8b17SPaolo Bonzini CASE_OP_32_64(sar): 665*3a9d8b17SPaolo Bonzini if (temps[args[2]].state == TCG_TEMP_CONST) { 666*3a9d8b17SPaolo Bonzini mask = ((tcg_target_long)temps[args[1]].mask 667*3a9d8b17SPaolo Bonzini >> temps[args[2]].val); 668*3a9d8b17SPaolo Bonzini } 669*3a9d8b17SPaolo Bonzini break; 670*3a9d8b17SPaolo Bonzini 671*3a9d8b17SPaolo Bonzini CASE_OP_32_64(shr): 672*3a9d8b17SPaolo Bonzini if (temps[args[2]].state == TCG_TEMP_CONST) { 673*3a9d8b17SPaolo Bonzini mask = temps[args[1]].mask >> temps[args[2]].val; 674*3a9d8b17SPaolo Bonzini } 675*3a9d8b17SPaolo Bonzini break; 676*3a9d8b17SPaolo Bonzini 677*3a9d8b17SPaolo Bonzini CASE_OP_32_64(shl): 678*3a9d8b17SPaolo Bonzini if (temps[args[2]].state == TCG_TEMP_CONST) { 679*3a9d8b17SPaolo Bonzini mask = temps[args[1]].mask << temps[args[2]].val; 680*3a9d8b17SPaolo Bonzini } 681*3a9d8b17SPaolo Bonzini break; 682*3a9d8b17SPaolo Bonzini 683*3a9d8b17SPaolo Bonzini CASE_OP_32_64(neg): 684*3a9d8b17SPaolo Bonzini /* Set to 1 all bits to the left of the rightmost. */ 685*3a9d8b17SPaolo Bonzini mask = -(temps[args[1]].mask & -temps[args[1]].mask); 686*3a9d8b17SPaolo Bonzini break; 687*3a9d8b17SPaolo Bonzini 688*3a9d8b17SPaolo Bonzini CASE_OP_32_64(deposit): 689*3a9d8b17SPaolo Bonzini tmp = ((1ull << args[4]) - 1); 690*3a9d8b17SPaolo Bonzini mask = ((temps[args[1]].mask & ~(tmp << args[3])) 691*3a9d8b17SPaolo Bonzini | ((temps[args[2]].mask & tmp) << args[3])); 692*3a9d8b17SPaolo Bonzini break; 693*3a9d8b17SPaolo Bonzini 694*3a9d8b17SPaolo Bonzini CASE_OP_32_64(or): 695*3a9d8b17SPaolo Bonzini CASE_OP_32_64(xor): 696*3a9d8b17SPaolo Bonzini mask = temps[args[1]].mask | temps[args[2]].mask; 697*3a9d8b17SPaolo Bonzini break; 698*3a9d8b17SPaolo Bonzini 699*3a9d8b17SPaolo Bonzini CASE_OP_32_64(setcond): 700*3a9d8b17SPaolo Bonzini mask = 1; 701*3a9d8b17SPaolo Bonzini break; 702*3a9d8b17SPaolo Bonzini 703*3a9d8b17SPaolo Bonzini CASE_OP_32_64(movcond): 704*3a9d8b17SPaolo Bonzini mask = temps[args[3]].mask | temps[args[4]].mask; 705*3a9d8b17SPaolo Bonzini break; 706*3a9d8b17SPaolo Bonzini 707*3a9d8b17SPaolo Bonzini default: 708*3a9d8b17SPaolo Bonzini break; 709*3a9d8b17SPaolo Bonzini } 710*3a9d8b17SPaolo Bonzini 71156e49438SAurelien Jarno /* Simplify expression for "op r, a, 0 => movi r, 0" cases */ 71256e49438SAurelien Jarno switch (op) { 71361251c0cSAurelien Jarno CASE_OP_32_64(and): 71453108fb5SKirill Batuzov CASE_OP_32_64(mul): 71553108fb5SKirill Batuzov if ((temps[args[2]].state == TCG_TEMP_CONST 71653108fb5SKirill Batuzov && temps[args[2]].val == 0)) { 71792414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = op_to_movi(op); 718e590d4e6SAurelien Jarno tcg_opt_gen_movi(gen_args, args[0], 0); 71953108fb5SKirill Batuzov args += 3; 72053108fb5SKirill Batuzov gen_args += 2; 72153108fb5SKirill Batuzov continue; 72253108fb5SKirill Batuzov } 72353108fb5SKirill Batuzov break; 72456e49438SAurelien Jarno default: 72556e49438SAurelien Jarno break; 72656e49438SAurelien Jarno } 72756e49438SAurelien Jarno 72856e49438SAurelien Jarno /* Simplify expression for "op r, a, a => mov r, a" cases */ 72956e49438SAurelien Jarno switch (op) { 7309a81090bSKirill Batuzov CASE_OP_32_64(or): 7319a81090bSKirill Batuzov CASE_OP_32_64(and): 7320aba1c73SAurelien Jarno if (temps_are_copies(args[1], args[2])) { 733e590d4e6SAurelien Jarno if (temps_are_copies(args[0], args[1])) { 73492414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = INDEX_op_nop; 7359a81090bSKirill Batuzov } else { 73692414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = op_to_mov(op); 737b80bb016SAurelien Jarno tcg_opt_gen_mov(s, gen_args, args[0], args[1]); 7389a81090bSKirill Batuzov gen_args += 2; 7399a81090bSKirill Batuzov } 740fedc0da2SAurelien Jarno args += 3; 7419a81090bSKirill Batuzov continue; 7429a81090bSKirill Batuzov } 7439a81090bSKirill Batuzov break; 744fe0de7aaSBlue Swirl default: 745fe0de7aaSBlue Swirl break; 74653108fb5SKirill Batuzov } 74753108fb5SKirill Batuzov 7483c94193eSAurelien Jarno /* Simplify expression for "op r, a, a => movi r, 0" cases */ 7493c94193eSAurelien Jarno switch (op) { 7503c94193eSAurelien Jarno CASE_OP_32_64(sub): 7513c94193eSAurelien Jarno CASE_OP_32_64(xor): 7523c94193eSAurelien Jarno if (temps_are_copies(args[1], args[2])) { 75392414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = op_to_movi(op); 7543c94193eSAurelien Jarno tcg_opt_gen_movi(gen_args, args[0], 0); 7553c94193eSAurelien Jarno gen_args += 2; 7563c94193eSAurelien Jarno args += 3; 7573c94193eSAurelien Jarno continue; 7583c94193eSAurelien Jarno } 7593c94193eSAurelien Jarno break; 7603c94193eSAurelien Jarno default: 7613c94193eSAurelien Jarno break; 7623c94193eSAurelien Jarno } 7633c94193eSAurelien Jarno 76422613af4SKirill Batuzov /* Propagate constants through copy operations and do constant 76522613af4SKirill Batuzov folding. Constants will be substituted to arguments by register 76622613af4SKirill Batuzov allocator where needed and possible. Also detect copies. */ 7678f2e8c07SKirill Batuzov switch (op) { 76822613af4SKirill Batuzov CASE_OP_32_64(mov): 769e590d4e6SAurelien Jarno if (temps_are_copies(args[0], args[1])) { 77022613af4SKirill Batuzov args += 2; 77192414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = INDEX_op_nop; 77222613af4SKirill Batuzov break; 77322613af4SKirill Batuzov } 77422613af4SKirill Batuzov if (temps[args[1]].state != TCG_TEMP_CONST) { 775b80bb016SAurelien Jarno tcg_opt_gen_mov(s, gen_args, args[0], args[1]); 77622613af4SKirill Batuzov gen_args += 2; 77722613af4SKirill Batuzov args += 2; 77822613af4SKirill Batuzov break; 77922613af4SKirill Batuzov } 78022613af4SKirill Batuzov /* Source argument is constant. Rewrite the operation and 78122613af4SKirill Batuzov let movi case handle it. */ 78222613af4SKirill Batuzov op = op_to_movi(op); 78392414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = op; 78422613af4SKirill Batuzov args[1] = temps[args[1]].val; 78522613af4SKirill Batuzov /* fallthrough */ 78622613af4SKirill Batuzov CASE_OP_32_64(movi): 787e590d4e6SAurelien Jarno tcg_opt_gen_movi(gen_args, args[0], args[1]); 78822613af4SKirill Batuzov gen_args += 2; 78922613af4SKirill Batuzov args += 2; 79022613af4SKirill Batuzov break; 7916e14e91bSRichard Henderson 792a640f031SKirill Batuzov CASE_OP_32_64(not): 793cb25c80aSRichard Henderson CASE_OP_32_64(neg): 79425c4d9ccSRichard Henderson CASE_OP_32_64(ext8s): 79525c4d9ccSRichard Henderson CASE_OP_32_64(ext8u): 79625c4d9ccSRichard Henderson CASE_OP_32_64(ext16s): 79725c4d9ccSRichard Henderson CASE_OP_32_64(ext16u): 798a640f031SKirill Batuzov case INDEX_op_ext32s_i64: 799a640f031SKirill Batuzov case INDEX_op_ext32u_i64: 800a640f031SKirill Batuzov if (temps[args[1]].state == TCG_TEMP_CONST) { 80192414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = op_to_movi(op); 802a640f031SKirill Batuzov tmp = do_constant_folding(op, temps[args[1]].val, 0); 803e590d4e6SAurelien Jarno tcg_opt_gen_movi(gen_args, args[0], tmp); 804a640f031SKirill Batuzov gen_args += 2; 805a640f031SKirill Batuzov args += 2; 806a640f031SKirill Batuzov break; 8076e14e91bSRichard Henderson } 8086e14e91bSRichard Henderson goto do_default; 8096e14e91bSRichard Henderson 81053108fb5SKirill Batuzov CASE_OP_32_64(add): 81153108fb5SKirill Batuzov CASE_OP_32_64(sub): 81253108fb5SKirill Batuzov CASE_OP_32_64(mul): 8139a81090bSKirill Batuzov CASE_OP_32_64(or): 8149a81090bSKirill Batuzov CASE_OP_32_64(and): 8159a81090bSKirill Batuzov CASE_OP_32_64(xor): 81655c0975cSKirill Batuzov CASE_OP_32_64(shl): 81755c0975cSKirill Batuzov CASE_OP_32_64(shr): 81855c0975cSKirill Batuzov CASE_OP_32_64(sar): 81925c4d9ccSRichard Henderson CASE_OP_32_64(rotl): 82025c4d9ccSRichard Henderson CASE_OP_32_64(rotr): 821cb25c80aSRichard Henderson CASE_OP_32_64(andc): 822cb25c80aSRichard Henderson CASE_OP_32_64(orc): 823cb25c80aSRichard Henderson CASE_OP_32_64(eqv): 824cb25c80aSRichard Henderson CASE_OP_32_64(nand): 825cb25c80aSRichard Henderson CASE_OP_32_64(nor): 82653108fb5SKirill Batuzov if (temps[args[1]].state == TCG_TEMP_CONST 82753108fb5SKirill Batuzov && temps[args[2]].state == TCG_TEMP_CONST) { 82892414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = op_to_movi(op); 82953108fb5SKirill Batuzov tmp = do_constant_folding(op, temps[args[1]].val, 83053108fb5SKirill Batuzov temps[args[2]].val); 831e590d4e6SAurelien Jarno tcg_opt_gen_movi(gen_args, args[0], tmp); 83253108fb5SKirill Batuzov gen_args += 2; 83353108fb5SKirill Batuzov args += 3; 83453108fb5SKirill Batuzov break; 8356e14e91bSRichard Henderson } 8366e14e91bSRichard Henderson goto do_default; 8376e14e91bSRichard Henderson 8387ef55fc9SAurelien Jarno CASE_OP_32_64(deposit): 8397ef55fc9SAurelien Jarno if (temps[args[1]].state == TCG_TEMP_CONST 8407ef55fc9SAurelien Jarno && temps[args[2]].state == TCG_TEMP_CONST) { 84192414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = op_to_movi(op); 8427ef55fc9SAurelien Jarno tmp = ((1ull << args[4]) - 1); 8437ef55fc9SAurelien Jarno tmp = (temps[args[1]].val & ~(tmp << args[3])) 8447ef55fc9SAurelien Jarno | ((temps[args[2]].val & tmp) << args[3]); 8457ef55fc9SAurelien Jarno tcg_opt_gen_movi(gen_args, args[0], tmp); 8467ef55fc9SAurelien Jarno gen_args += 2; 8477ef55fc9SAurelien Jarno args += 5; 8487ef55fc9SAurelien Jarno break; 8496e14e91bSRichard Henderson } 8506e14e91bSRichard Henderson goto do_default; 8516e14e91bSRichard Henderson 852f8dd19e5SAurelien Jarno CASE_OP_32_64(setcond): 853b336ceb6SAurelien Jarno tmp = do_constant_folding_cond(op, args[1], args[2], args[3]); 854b336ceb6SAurelien Jarno if (tmp != 2) { 85592414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = op_to_movi(op); 856e590d4e6SAurelien Jarno tcg_opt_gen_movi(gen_args, args[0], tmp); 857f8dd19e5SAurelien Jarno gen_args += 2; 858f8dd19e5SAurelien Jarno args += 4; 859f8dd19e5SAurelien Jarno break; 8606e14e91bSRichard Henderson } 8616e14e91bSRichard Henderson goto do_default; 8626e14e91bSRichard Henderson 863fbeaa26cSAurelien Jarno CASE_OP_32_64(brcond): 864b336ceb6SAurelien Jarno tmp = do_constant_folding_cond(op, args[0], args[1], args[2]); 865b336ceb6SAurelien Jarno if (tmp != 2) { 866b336ceb6SAurelien Jarno if (tmp) { 867d193a14aSPaolo Bonzini reset_all_temps(nb_temps); 86892414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = INDEX_op_br; 869fbeaa26cSAurelien Jarno gen_args[0] = args[3]; 870fbeaa26cSAurelien Jarno gen_args += 1; 871fbeaa26cSAurelien Jarno } else { 87292414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = INDEX_op_nop; 873fbeaa26cSAurelien Jarno } 874fbeaa26cSAurelien Jarno args += 4; 875fbeaa26cSAurelien Jarno break; 8766e14e91bSRichard Henderson } 8776e14e91bSRichard Henderson goto do_default; 8786e14e91bSRichard Henderson 879fa01a208SRichard Henderson CASE_OP_32_64(movcond): 880b336ceb6SAurelien Jarno tmp = do_constant_folding_cond(op, args[1], args[2], args[5]); 881b336ceb6SAurelien Jarno if (tmp != 2) { 882e590d4e6SAurelien Jarno if (temps_are_copies(args[0], args[4-tmp])) { 88392414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = INDEX_op_nop; 884fa01a208SRichard Henderson } else if (temps[args[4-tmp]].state == TCG_TEMP_CONST) { 88592414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = op_to_movi(op); 886e590d4e6SAurelien Jarno tcg_opt_gen_movi(gen_args, args[0], temps[args[4-tmp]].val); 887fa01a208SRichard Henderson gen_args += 2; 888fa01a208SRichard Henderson } else { 88992414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = op_to_mov(op); 890e590d4e6SAurelien Jarno tcg_opt_gen_mov(s, gen_args, args[0], args[4-tmp]); 891fa01a208SRichard Henderson gen_args += 2; 892fa01a208SRichard Henderson } 893fa01a208SRichard Henderson args += 6; 894fa01a208SRichard Henderson break; 8956e14e91bSRichard Henderson } 8966e14e91bSRichard Henderson goto do_default; 8976e14e91bSRichard Henderson 898212c328dSRichard Henderson case INDEX_op_add2_i32: 899212c328dSRichard Henderson case INDEX_op_sub2_i32: 900212c328dSRichard Henderson if (temps[args[2]].state == TCG_TEMP_CONST 901212c328dSRichard Henderson && temps[args[3]].state == TCG_TEMP_CONST 902212c328dSRichard Henderson && temps[args[4]].state == TCG_TEMP_CONST 903212c328dSRichard Henderson && temps[args[5]].state == TCG_TEMP_CONST) { 904212c328dSRichard Henderson uint32_t al = temps[args[2]].val; 905212c328dSRichard Henderson uint32_t ah = temps[args[3]].val; 906212c328dSRichard Henderson uint32_t bl = temps[args[4]].val; 907212c328dSRichard Henderson uint32_t bh = temps[args[5]].val; 908212c328dSRichard Henderson uint64_t a = ((uint64_t)ah << 32) | al; 909212c328dSRichard Henderson uint64_t b = ((uint64_t)bh << 32) | bl; 910212c328dSRichard Henderson TCGArg rl, rh; 911212c328dSRichard Henderson 912212c328dSRichard Henderson if (op == INDEX_op_add2_i32) { 913212c328dSRichard Henderson a += b; 914212c328dSRichard Henderson } else { 915212c328dSRichard Henderson a -= b; 916212c328dSRichard Henderson } 917212c328dSRichard Henderson 918212c328dSRichard Henderson /* We emit the extra nop when we emit the add2/sub2. */ 91992414b31SEvgeny Voevodin assert(s->gen_opc_buf[op_index + 1] == INDEX_op_nop); 920212c328dSRichard Henderson 921212c328dSRichard Henderson rl = args[0]; 922212c328dSRichard Henderson rh = args[1]; 92392414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = INDEX_op_movi_i32; 92492414b31SEvgeny Voevodin s->gen_opc_buf[++op_index] = INDEX_op_movi_i32; 925212c328dSRichard Henderson tcg_opt_gen_movi(&gen_args[0], rl, (uint32_t)a); 926212c328dSRichard Henderson tcg_opt_gen_movi(&gen_args[2], rh, (uint32_t)(a >> 32)); 927212c328dSRichard Henderson gen_args += 4; 928212c328dSRichard Henderson args += 6; 929212c328dSRichard Henderson break; 930212c328dSRichard Henderson } 931212c328dSRichard Henderson goto do_default; 932212c328dSRichard Henderson 9331414968aSRichard Henderson case INDEX_op_mulu2_i32: 9341414968aSRichard Henderson if (temps[args[2]].state == TCG_TEMP_CONST 9351414968aSRichard Henderson && temps[args[3]].state == TCG_TEMP_CONST) { 9361414968aSRichard Henderson uint32_t a = temps[args[2]].val; 9371414968aSRichard Henderson uint32_t b = temps[args[3]].val; 9381414968aSRichard Henderson uint64_t r = (uint64_t)a * b; 9391414968aSRichard Henderson TCGArg rl, rh; 9401414968aSRichard Henderson 9411414968aSRichard Henderson /* We emit the extra nop when we emit the mulu2. */ 94292414b31SEvgeny Voevodin assert(s->gen_opc_buf[op_index + 1] == INDEX_op_nop); 9431414968aSRichard Henderson 9441414968aSRichard Henderson rl = args[0]; 9451414968aSRichard Henderson rh = args[1]; 94692414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = INDEX_op_movi_i32; 94792414b31SEvgeny Voevodin s->gen_opc_buf[++op_index] = INDEX_op_movi_i32; 9481414968aSRichard Henderson tcg_opt_gen_movi(&gen_args[0], rl, (uint32_t)r); 9491414968aSRichard Henderson tcg_opt_gen_movi(&gen_args[2], rh, (uint32_t)(r >> 32)); 9501414968aSRichard Henderson gen_args += 4; 9511414968aSRichard Henderson args += 4; 9521414968aSRichard Henderson break; 9531414968aSRichard Henderson } 9541414968aSRichard Henderson goto do_default; 9551414968aSRichard Henderson 956bc1473efSRichard Henderson case INDEX_op_brcond2_i32: 9576c4382f8SRichard Henderson tmp = do_constant_folding_cond2(&args[0], &args[2], args[4]); 9586c4382f8SRichard Henderson if (tmp != 2) { 9596c4382f8SRichard Henderson if (tmp) { 960d193a14aSPaolo Bonzini reset_all_temps(nb_temps); 96192414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = INDEX_op_br; 9626c4382f8SRichard Henderson gen_args[0] = args[5]; 9636c4382f8SRichard Henderson gen_args += 1; 9646c4382f8SRichard Henderson } else { 96592414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = INDEX_op_nop; 9666c4382f8SRichard Henderson } 9676c4382f8SRichard Henderson } else if ((args[4] == TCG_COND_LT || args[4] == TCG_COND_GE) 968bc1473efSRichard Henderson && temps[args[2]].state == TCG_TEMP_CONST 969bc1473efSRichard Henderson && temps[args[3]].state == TCG_TEMP_CONST 970bc1473efSRichard Henderson && temps[args[2]].val == 0 971bc1473efSRichard Henderson && temps[args[3]].val == 0) { 9726c4382f8SRichard Henderson /* Simplify LT/GE comparisons vs zero to a single compare 9736c4382f8SRichard Henderson vs the high word of the input. */ 974d193a14aSPaolo Bonzini reset_all_temps(nb_temps); 97592414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = INDEX_op_brcond_i32; 976bc1473efSRichard Henderson gen_args[0] = args[1]; 977bc1473efSRichard Henderson gen_args[1] = args[3]; 978bc1473efSRichard Henderson gen_args[2] = args[4]; 979bc1473efSRichard Henderson gen_args[3] = args[5]; 980bc1473efSRichard Henderson gen_args += 4; 9816c4382f8SRichard Henderson } else { 982bc1473efSRichard Henderson goto do_default; 9836c4382f8SRichard Henderson } 9846c4382f8SRichard Henderson args += 6; 9856c4382f8SRichard Henderson break; 986bc1473efSRichard Henderson 987bc1473efSRichard Henderson case INDEX_op_setcond2_i32: 9886c4382f8SRichard Henderson tmp = do_constant_folding_cond2(&args[1], &args[3], args[5]); 9896c4382f8SRichard Henderson if (tmp != 2) { 99092414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = INDEX_op_movi_i32; 9916c4382f8SRichard Henderson tcg_opt_gen_movi(gen_args, args[0], tmp); 9926c4382f8SRichard Henderson gen_args += 2; 9936c4382f8SRichard Henderson } else if ((args[5] == TCG_COND_LT || args[5] == TCG_COND_GE) 994bc1473efSRichard Henderson && temps[args[3]].state == TCG_TEMP_CONST 995bc1473efSRichard Henderson && temps[args[4]].state == TCG_TEMP_CONST 996bc1473efSRichard Henderson && temps[args[3]].val == 0 997bc1473efSRichard Henderson && temps[args[4]].val == 0) { 9986c4382f8SRichard Henderson /* Simplify LT/GE comparisons vs zero to a single compare 9996c4382f8SRichard Henderson vs the high word of the input. */ 100092414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = INDEX_op_setcond_i32; 1001bc1473efSRichard Henderson gen_args[0] = args[0]; 1002bc1473efSRichard Henderson gen_args[1] = args[2]; 1003bc1473efSRichard Henderson gen_args[2] = args[4]; 1004bc1473efSRichard Henderson gen_args[3] = args[5]; 1005bc1473efSRichard Henderson gen_args += 4; 10066c4382f8SRichard Henderson } else { 10076c4382f8SRichard Henderson goto do_default; 10086c4382f8SRichard Henderson } 1009bc1473efSRichard Henderson args += 6; 1010bc1473efSRichard Henderson break; 1011bc1473efSRichard Henderson 10128f2e8c07SKirill Batuzov case INDEX_op_call: 101322613af4SKirill Batuzov nb_call_args = (args[0] >> 16) + (args[0] & 0xffff); 101478505279SAurelien Jarno if (!(args[nb_call_args + 1] & (TCG_CALL_NO_READ_GLOBALS | 101578505279SAurelien Jarno TCG_CALL_NO_WRITE_GLOBALS))) { 101622613af4SKirill Batuzov for (i = 0; i < nb_globals; i++) { 1017e590d4e6SAurelien Jarno reset_temp(i); 101822613af4SKirill Batuzov } 101922613af4SKirill Batuzov } 102022613af4SKirill Batuzov for (i = 0; i < (args[0] >> 16); i++) { 1021e590d4e6SAurelien Jarno reset_temp(args[i + 1]); 102222613af4SKirill Batuzov } 102322613af4SKirill Batuzov i = nb_call_args + 3; 10248f2e8c07SKirill Batuzov while (i) { 10258f2e8c07SKirill Batuzov *gen_args = *args; 10268f2e8c07SKirill Batuzov args++; 10278f2e8c07SKirill Batuzov gen_args++; 10288f2e8c07SKirill Batuzov i--; 10298f2e8c07SKirill Batuzov } 10308f2e8c07SKirill Batuzov break; 10316e14e91bSRichard Henderson 10328f2e8c07SKirill Batuzov default: 10336e14e91bSRichard Henderson do_default: 10346e14e91bSRichard Henderson /* Default case: we know nothing about operation (or were unable 10356e14e91bSRichard Henderson to compute the operation result) so no propagation is done. 10366e14e91bSRichard Henderson We trash everything if the operation is the end of a basic 1037*3a9d8b17SPaolo Bonzini block, otherwise we only trash the output args. "mask" is 1038*3a9d8b17SPaolo Bonzini the non-zero bits mask for the first output arg. */ 1039a2550660SAurelien Jarno if (def->flags & TCG_OPF_BB_END) { 1040d193a14aSPaolo Bonzini reset_all_temps(nb_temps); 1041a2550660SAurelien Jarno } else { 104222613af4SKirill Batuzov for (i = 0; i < def->nb_oargs; i++) { 1043e590d4e6SAurelien Jarno reset_temp(args[i]); 104422613af4SKirill Batuzov } 1045a2550660SAurelien Jarno } 10468f2e8c07SKirill Batuzov for (i = 0; i < def->nb_args; i++) { 10478f2e8c07SKirill Batuzov gen_args[i] = args[i]; 10488f2e8c07SKirill Batuzov } 10498f2e8c07SKirill Batuzov args += def->nb_args; 10508f2e8c07SKirill Batuzov gen_args += def->nb_args; 10518f2e8c07SKirill Batuzov break; 10528f2e8c07SKirill Batuzov } 10538f2e8c07SKirill Batuzov } 10548f2e8c07SKirill Batuzov 10558f2e8c07SKirill Batuzov return gen_args; 10568f2e8c07SKirill Batuzov } 10578f2e8c07SKirill Batuzov 10588f2e8c07SKirill Batuzov TCGArg *tcg_optimize(TCGContext *s, uint16_t *tcg_opc_ptr, 10598f2e8c07SKirill Batuzov TCGArg *args, TCGOpDef *tcg_op_defs) 10608f2e8c07SKirill Batuzov { 10618f2e8c07SKirill Batuzov TCGArg *res; 10628f2e8c07SKirill Batuzov res = tcg_constant_folding(s, tcg_opc_ptr, args, tcg_op_defs); 10638f2e8c07SKirill Batuzov return res; 10648f2e8c07SKirill Batuzov } 1065