xref: /openbmc/qemu/tcg/optimize.c (revision e31b0a7c)
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