xref: /openbmc/qemu/tcg/optimize.c (revision fedc0da2)
18f2e8c07SKirill Batuzov /*
28f2e8c07SKirill Batuzov  * Optimizations for Tiny Code Generator for QEMU
38f2e8c07SKirill Batuzov  *
48f2e8c07SKirill Batuzov  * Copyright (c) 2010 Samsung Electronics.
58f2e8c07SKirill Batuzov  * Contributed by Kirill Batuzov <batuzovk@ispras.ru>
68f2e8c07SKirill Batuzov  *
78f2e8c07SKirill Batuzov  * Permission is hereby granted, free of charge, to any person obtaining a copy
88f2e8c07SKirill Batuzov  * of this software and associated documentation files (the "Software"), to deal
98f2e8c07SKirill Batuzov  * in the Software without restriction, including without limitation the rights
108f2e8c07SKirill Batuzov  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
118f2e8c07SKirill Batuzov  * copies of the Software, and to permit persons to whom the Software is
128f2e8c07SKirill Batuzov  * furnished to do so, subject to the following conditions:
138f2e8c07SKirill Batuzov  *
148f2e8c07SKirill Batuzov  * The above copyright notice and this permission notice shall be included in
158f2e8c07SKirill Batuzov  * all copies or substantial portions of the Software.
168f2e8c07SKirill Batuzov  *
178f2e8c07SKirill Batuzov  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
188f2e8c07SKirill Batuzov  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
198f2e8c07SKirill Batuzov  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
208f2e8c07SKirill Batuzov  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
218f2e8c07SKirill Batuzov  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
228f2e8c07SKirill Batuzov  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
238f2e8c07SKirill Batuzov  * THE SOFTWARE.
248f2e8c07SKirill Batuzov  */
258f2e8c07SKirill Batuzov 
268f2e8c07SKirill Batuzov #include "config.h"
278f2e8c07SKirill Batuzov 
288f2e8c07SKirill Batuzov #include <stdlib.h>
298f2e8c07SKirill Batuzov #include <stdio.h>
308f2e8c07SKirill Batuzov 
318f2e8c07SKirill Batuzov #include "qemu-common.h"
328f2e8c07SKirill Batuzov #include "tcg-op.h"
338f2e8c07SKirill Batuzov 
348f2e8c07SKirill Batuzov #define CASE_OP_32_64(x)                        \
358f2e8c07SKirill Batuzov         glue(glue(case INDEX_op_, x), _i32):    \
368f2e8c07SKirill Batuzov         glue(glue(case INDEX_op_, x), _i64)
378f2e8c07SKirill Batuzov 
3822613af4SKirill Batuzov typedef enum {
3922613af4SKirill Batuzov     TCG_TEMP_UNDEF = 0,
4022613af4SKirill Batuzov     TCG_TEMP_CONST,
4122613af4SKirill Batuzov     TCG_TEMP_COPY,
4222613af4SKirill Batuzov     TCG_TEMP_HAS_COPY,
4322613af4SKirill Batuzov     TCG_TEMP_ANY
4422613af4SKirill Batuzov } tcg_temp_state;
4522613af4SKirill Batuzov 
4622613af4SKirill Batuzov struct tcg_temp_info {
4722613af4SKirill Batuzov     tcg_temp_state state;
4822613af4SKirill Batuzov     uint16_t prev_copy;
4922613af4SKirill Batuzov     uint16_t next_copy;
5022613af4SKirill Batuzov     tcg_target_ulong val;
5122613af4SKirill Batuzov };
5222613af4SKirill Batuzov 
5322613af4SKirill Batuzov static struct tcg_temp_info temps[TCG_MAX_TEMPS];
5422613af4SKirill Batuzov 
5522613af4SKirill Batuzov /* Reset TEMP's state to TCG_TEMP_ANY.  If TEMP was a representative of some
5622613af4SKirill Batuzov    class of equivalent temp's, a new representative should be chosen in this
5722613af4SKirill Batuzov    class. */
5822613af4SKirill Batuzov static void reset_temp(TCGArg temp, int nb_temps, int nb_globals)
5922613af4SKirill Batuzov {
6022613af4SKirill Batuzov     int i;
6122613af4SKirill Batuzov     TCGArg new_base = (TCGArg)-1;
6222613af4SKirill Batuzov     if (temps[temp].state == TCG_TEMP_HAS_COPY) {
6322613af4SKirill Batuzov         for (i = temps[temp].next_copy; i != temp; i = temps[i].next_copy) {
6422613af4SKirill Batuzov             if (i >= nb_globals) {
6522613af4SKirill Batuzov                 temps[i].state = TCG_TEMP_HAS_COPY;
6622613af4SKirill Batuzov                 new_base = i;
6722613af4SKirill Batuzov                 break;
6822613af4SKirill Batuzov             }
6922613af4SKirill Batuzov         }
7022613af4SKirill Batuzov         for (i = temps[temp].next_copy; i != temp; i = temps[i].next_copy) {
7122613af4SKirill Batuzov             if (new_base == (TCGArg)-1) {
7222613af4SKirill Batuzov                 temps[i].state = TCG_TEMP_ANY;
7322613af4SKirill Batuzov             } else {
7422613af4SKirill Batuzov                 temps[i].val = new_base;
7522613af4SKirill Batuzov             }
7622613af4SKirill Batuzov         }
7722613af4SKirill Batuzov         temps[temps[temp].next_copy].prev_copy = temps[temp].prev_copy;
7822613af4SKirill Batuzov         temps[temps[temp].prev_copy].next_copy = temps[temp].next_copy;
7922613af4SKirill Batuzov     } else if (temps[temp].state == TCG_TEMP_COPY) {
8022613af4SKirill Batuzov         temps[temps[temp].next_copy].prev_copy = temps[temp].prev_copy;
8122613af4SKirill Batuzov         temps[temps[temp].prev_copy].next_copy = temps[temp].next_copy;
8222613af4SKirill Batuzov         new_base = temps[temp].val;
8322613af4SKirill Batuzov     }
8422613af4SKirill Batuzov     temps[temp].state = TCG_TEMP_ANY;
8522613af4SKirill Batuzov     if (new_base != (TCGArg)-1 && temps[new_base].next_copy == new_base) {
8622613af4SKirill Batuzov         temps[new_base].state = TCG_TEMP_ANY;
8722613af4SKirill Batuzov     }
8822613af4SKirill Batuzov }
8922613af4SKirill Batuzov 
90fe0de7aaSBlue Swirl static int op_bits(TCGOpcode op)
9122613af4SKirill Batuzov {
928399ad59SRichard Henderson     const TCGOpDef *def = &tcg_op_defs[op];
938399ad59SRichard Henderson     return def->flags & TCG_OPF_64BIT ? 64 : 32;
9422613af4SKirill Batuzov }
9522613af4SKirill Batuzov 
96fe0de7aaSBlue Swirl static TCGOpcode op_to_movi(TCGOpcode op)
9722613af4SKirill Batuzov {
9822613af4SKirill Batuzov     switch (op_bits(op)) {
9922613af4SKirill Batuzov     case 32:
10022613af4SKirill Batuzov         return INDEX_op_movi_i32;
10122613af4SKirill Batuzov     case 64:
10222613af4SKirill Batuzov         return INDEX_op_movi_i64;
10322613af4SKirill Batuzov     default:
10422613af4SKirill Batuzov         fprintf(stderr, "op_to_movi: unexpected return value of "
10522613af4SKirill Batuzov                 "function op_bits.\n");
10622613af4SKirill Batuzov         tcg_abort();
10722613af4SKirill Batuzov     }
10822613af4SKirill Batuzov }
10922613af4SKirill Batuzov 
110e31b0a7cSBlue Swirl static void tcg_opt_gen_mov(TCGContext *s, TCGArg *gen_args, TCGArg dst,
111e31b0a7cSBlue Swirl                             TCGArg src, int nb_temps, int nb_globals)
11222613af4SKirill Batuzov {
11322613af4SKirill Batuzov         reset_temp(dst, nb_temps, nb_globals);
11422613af4SKirill Batuzov         assert(temps[src].state != TCG_TEMP_COPY);
115e31b0a7cSBlue Swirl         /* Don't try to copy if one of temps is a global or either one
116e31b0a7cSBlue Swirl            is local and another is register */
117e31b0a7cSBlue Swirl         if (src >= nb_globals && dst >= nb_globals &&
118e31b0a7cSBlue Swirl             tcg_arg_is_local(s, src) == tcg_arg_is_local(s, dst)) {
11922613af4SKirill Batuzov             assert(temps[src].state != TCG_TEMP_CONST);
12022613af4SKirill Batuzov             if (temps[src].state != TCG_TEMP_HAS_COPY) {
12122613af4SKirill Batuzov                 temps[src].state = TCG_TEMP_HAS_COPY;
12222613af4SKirill Batuzov                 temps[src].next_copy = src;
12322613af4SKirill Batuzov                 temps[src].prev_copy = src;
12422613af4SKirill Batuzov             }
12522613af4SKirill Batuzov             temps[dst].state = TCG_TEMP_COPY;
12622613af4SKirill Batuzov             temps[dst].val = src;
12722613af4SKirill Batuzov             temps[dst].next_copy = temps[src].next_copy;
12822613af4SKirill Batuzov             temps[dst].prev_copy = src;
12922613af4SKirill Batuzov             temps[temps[dst].next_copy].prev_copy = dst;
13022613af4SKirill Batuzov             temps[src].next_copy = dst;
13122613af4SKirill Batuzov         }
13222613af4SKirill Batuzov         gen_args[0] = dst;
13322613af4SKirill Batuzov         gen_args[1] = src;
13422613af4SKirill Batuzov }
13522613af4SKirill Batuzov 
13622613af4SKirill Batuzov static void tcg_opt_gen_movi(TCGArg *gen_args, TCGArg dst, TCGArg val,
13722613af4SKirill Batuzov                              int nb_temps, int nb_globals)
13822613af4SKirill Batuzov {
13922613af4SKirill Batuzov         reset_temp(dst, nb_temps, nb_globals);
14022613af4SKirill Batuzov         temps[dst].state = TCG_TEMP_CONST;
14122613af4SKirill Batuzov         temps[dst].val = val;
14222613af4SKirill Batuzov         gen_args[0] = dst;
14322613af4SKirill Batuzov         gen_args[1] = val;
14422613af4SKirill Batuzov }
14522613af4SKirill Batuzov 
146fe0de7aaSBlue Swirl static TCGOpcode op_to_mov(TCGOpcode op)
14753108fb5SKirill Batuzov {
14853108fb5SKirill Batuzov     switch (op_bits(op)) {
14953108fb5SKirill Batuzov     case 32:
15053108fb5SKirill Batuzov         return INDEX_op_mov_i32;
15153108fb5SKirill Batuzov     case 64:
15253108fb5SKirill Batuzov         return INDEX_op_mov_i64;
15353108fb5SKirill Batuzov     default:
15453108fb5SKirill Batuzov         fprintf(stderr, "op_to_mov: unexpected return value of "
15553108fb5SKirill Batuzov                 "function op_bits.\n");
15653108fb5SKirill Batuzov         tcg_abort();
15753108fb5SKirill Batuzov     }
15853108fb5SKirill Batuzov }
15953108fb5SKirill Batuzov 
160fe0de7aaSBlue Swirl static TCGArg do_constant_folding_2(TCGOpcode op, TCGArg x, TCGArg y)
16153108fb5SKirill Batuzov {
16253108fb5SKirill Batuzov     switch (op) {
16353108fb5SKirill Batuzov     CASE_OP_32_64(add):
16453108fb5SKirill Batuzov         return x + y;
16553108fb5SKirill Batuzov 
16653108fb5SKirill Batuzov     CASE_OP_32_64(sub):
16753108fb5SKirill Batuzov         return x - y;
16853108fb5SKirill Batuzov 
16953108fb5SKirill Batuzov     CASE_OP_32_64(mul):
17053108fb5SKirill Batuzov         return x * y;
17153108fb5SKirill Batuzov 
1729a81090bSKirill Batuzov     CASE_OP_32_64(and):
1739a81090bSKirill Batuzov         return x & y;
1749a81090bSKirill Batuzov 
1759a81090bSKirill Batuzov     CASE_OP_32_64(or):
1769a81090bSKirill Batuzov         return x | y;
1779a81090bSKirill Batuzov 
1789a81090bSKirill Batuzov     CASE_OP_32_64(xor):
1799a81090bSKirill Batuzov         return x ^ y;
1809a81090bSKirill Batuzov 
18155c0975cSKirill Batuzov     case INDEX_op_shl_i32:
18255c0975cSKirill Batuzov         return (uint32_t)x << (uint32_t)y;
18355c0975cSKirill Batuzov 
18455c0975cSKirill Batuzov     case INDEX_op_shl_i64:
18555c0975cSKirill Batuzov         return (uint64_t)x << (uint64_t)y;
18655c0975cSKirill Batuzov 
18755c0975cSKirill Batuzov     case INDEX_op_shr_i32:
18855c0975cSKirill Batuzov         return (uint32_t)x >> (uint32_t)y;
18955c0975cSKirill Batuzov 
19055c0975cSKirill Batuzov     case INDEX_op_shr_i64:
19155c0975cSKirill Batuzov         return (uint64_t)x >> (uint64_t)y;
19255c0975cSKirill Batuzov 
19355c0975cSKirill Batuzov     case INDEX_op_sar_i32:
19455c0975cSKirill Batuzov         return (int32_t)x >> (int32_t)y;
19555c0975cSKirill Batuzov 
19655c0975cSKirill Batuzov     case INDEX_op_sar_i64:
19755c0975cSKirill Batuzov         return (int64_t)x >> (int64_t)y;
19855c0975cSKirill Batuzov 
19955c0975cSKirill Batuzov     case INDEX_op_rotr_i32:
20025c4d9ccSRichard Henderson         x = ((uint32_t)x << (32 - y)) | ((uint32_t)x >> y);
20155c0975cSKirill Batuzov         return x;
20255c0975cSKirill Batuzov 
20355c0975cSKirill Batuzov     case INDEX_op_rotr_i64:
20425c4d9ccSRichard Henderson         x = ((uint64_t)x << (64 - y)) | ((uint64_t)x >> y);
20555c0975cSKirill Batuzov         return x;
20655c0975cSKirill Batuzov 
20755c0975cSKirill Batuzov     case INDEX_op_rotl_i32:
20825c4d9ccSRichard Henderson         x = ((uint32_t)x << y) | ((uint32_t)x >> (32 - y));
20955c0975cSKirill Batuzov         return x;
21055c0975cSKirill Batuzov 
21155c0975cSKirill Batuzov     case INDEX_op_rotl_i64:
21225c4d9ccSRichard Henderson         x = ((uint64_t)x << y) | ((uint64_t)x >> (64 - y));
21355c0975cSKirill Batuzov         return x;
21455c0975cSKirill Batuzov 
21525c4d9ccSRichard Henderson     CASE_OP_32_64(not):
216a640f031SKirill Batuzov         return ~x;
217a640f031SKirill Batuzov 
218cb25c80aSRichard Henderson     CASE_OP_32_64(neg):
219cb25c80aSRichard Henderson         return -x;
220cb25c80aSRichard Henderson 
221cb25c80aSRichard Henderson     CASE_OP_32_64(andc):
222cb25c80aSRichard Henderson         return x & ~y;
223cb25c80aSRichard Henderson 
224cb25c80aSRichard Henderson     CASE_OP_32_64(orc):
225cb25c80aSRichard Henderson         return x | ~y;
226cb25c80aSRichard Henderson 
227cb25c80aSRichard Henderson     CASE_OP_32_64(eqv):
228cb25c80aSRichard Henderson         return ~(x ^ y);
229cb25c80aSRichard Henderson 
230cb25c80aSRichard Henderson     CASE_OP_32_64(nand):
231cb25c80aSRichard Henderson         return ~(x & y);
232cb25c80aSRichard Henderson 
233cb25c80aSRichard Henderson     CASE_OP_32_64(nor):
234cb25c80aSRichard Henderson         return ~(x | y);
235cb25c80aSRichard Henderson 
23625c4d9ccSRichard Henderson     CASE_OP_32_64(ext8s):
237a640f031SKirill Batuzov         return (int8_t)x;
238a640f031SKirill Batuzov 
23925c4d9ccSRichard Henderson     CASE_OP_32_64(ext16s):
240a640f031SKirill Batuzov         return (int16_t)x;
241a640f031SKirill Batuzov 
24225c4d9ccSRichard Henderson     CASE_OP_32_64(ext8u):
243a640f031SKirill Batuzov         return (uint8_t)x;
244a640f031SKirill Batuzov 
24525c4d9ccSRichard Henderson     CASE_OP_32_64(ext16u):
246a640f031SKirill Batuzov         return (uint16_t)x;
247a640f031SKirill Batuzov 
248a640f031SKirill Batuzov     case INDEX_op_ext32s_i64:
249a640f031SKirill Batuzov         return (int32_t)x;
250a640f031SKirill Batuzov 
251a640f031SKirill Batuzov     case INDEX_op_ext32u_i64:
252a640f031SKirill Batuzov         return (uint32_t)x;
253a640f031SKirill Batuzov 
25453108fb5SKirill Batuzov     default:
25553108fb5SKirill Batuzov         fprintf(stderr,
25653108fb5SKirill Batuzov                 "Unrecognized operation %d in do_constant_folding.\n", op);
25753108fb5SKirill Batuzov         tcg_abort();
25853108fb5SKirill Batuzov     }
25953108fb5SKirill Batuzov }
26053108fb5SKirill Batuzov 
261fe0de7aaSBlue Swirl static TCGArg do_constant_folding(TCGOpcode op, TCGArg x, TCGArg y)
26253108fb5SKirill Batuzov {
26353108fb5SKirill Batuzov     TCGArg res = do_constant_folding_2(op, x, y);
26453108fb5SKirill Batuzov     if (op_bits(op) == 32) {
26553108fb5SKirill Batuzov         res &= 0xffffffff;
26653108fb5SKirill Batuzov     }
26753108fb5SKirill Batuzov     return res;
26853108fb5SKirill Batuzov }
26953108fb5SKirill Batuzov 
270f8dd19e5SAurelien Jarno static TCGArg do_constant_folding_cond(TCGOpcode op, TCGArg x,
271f8dd19e5SAurelien Jarno                                        TCGArg y, TCGCond c)
272f8dd19e5SAurelien Jarno {
273f8dd19e5SAurelien Jarno     switch (op_bits(op)) {
274f8dd19e5SAurelien Jarno     case 32:
275f8dd19e5SAurelien Jarno         switch (c) {
276f8dd19e5SAurelien Jarno         case TCG_COND_EQ:
277f8dd19e5SAurelien Jarno             return (uint32_t)x == (uint32_t)y;
278f8dd19e5SAurelien Jarno         case TCG_COND_NE:
279f8dd19e5SAurelien Jarno             return (uint32_t)x != (uint32_t)y;
280f8dd19e5SAurelien Jarno         case TCG_COND_LT:
281f8dd19e5SAurelien Jarno             return (int32_t)x < (int32_t)y;
282f8dd19e5SAurelien Jarno         case TCG_COND_GE:
283f8dd19e5SAurelien Jarno             return (int32_t)x >= (int32_t)y;
284f8dd19e5SAurelien Jarno         case TCG_COND_LE:
285f8dd19e5SAurelien Jarno             return (int32_t)x <= (int32_t)y;
286f8dd19e5SAurelien Jarno         case TCG_COND_GT:
287f8dd19e5SAurelien Jarno             return (int32_t)x > (int32_t)y;
288f8dd19e5SAurelien Jarno         case TCG_COND_LTU:
289f8dd19e5SAurelien Jarno             return (uint32_t)x < (uint32_t)y;
290f8dd19e5SAurelien Jarno         case TCG_COND_GEU:
291f8dd19e5SAurelien Jarno             return (uint32_t)x >= (uint32_t)y;
292f8dd19e5SAurelien Jarno         case TCG_COND_LEU:
293f8dd19e5SAurelien Jarno             return (uint32_t)x <= (uint32_t)y;
294f8dd19e5SAurelien Jarno         case TCG_COND_GTU:
295f8dd19e5SAurelien Jarno             return (uint32_t)x > (uint32_t)y;
296f8dd19e5SAurelien Jarno         }
297f8dd19e5SAurelien Jarno         break;
298f8dd19e5SAurelien Jarno     case 64:
299f8dd19e5SAurelien Jarno         switch (c) {
300f8dd19e5SAurelien Jarno         case TCG_COND_EQ:
301f8dd19e5SAurelien Jarno             return (uint64_t)x == (uint64_t)y;
302f8dd19e5SAurelien Jarno         case TCG_COND_NE:
303f8dd19e5SAurelien Jarno             return (uint64_t)x != (uint64_t)y;
304f8dd19e5SAurelien Jarno         case TCG_COND_LT:
305f8dd19e5SAurelien Jarno             return (int64_t)x < (int64_t)y;
306f8dd19e5SAurelien Jarno         case TCG_COND_GE:
307f8dd19e5SAurelien Jarno             return (int64_t)x >= (int64_t)y;
308f8dd19e5SAurelien Jarno         case TCG_COND_LE:
309f8dd19e5SAurelien Jarno             return (int64_t)x <= (int64_t)y;
310f8dd19e5SAurelien Jarno         case TCG_COND_GT:
311f8dd19e5SAurelien Jarno             return (int64_t)x > (int64_t)y;
312f8dd19e5SAurelien Jarno         case TCG_COND_LTU:
313f8dd19e5SAurelien Jarno             return (uint64_t)x < (uint64_t)y;
314f8dd19e5SAurelien Jarno         case TCG_COND_GEU:
315f8dd19e5SAurelien Jarno             return (uint64_t)x >= (uint64_t)y;
316f8dd19e5SAurelien Jarno         case TCG_COND_LEU:
317f8dd19e5SAurelien Jarno             return (uint64_t)x <= (uint64_t)y;
318f8dd19e5SAurelien Jarno         case TCG_COND_GTU:
319f8dd19e5SAurelien Jarno             return (uint64_t)x > (uint64_t)y;
320f8dd19e5SAurelien Jarno         }
321f8dd19e5SAurelien Jarno         break;
322f8dd19e5SAurelien Jarno     }
323f8dd19e5SAurelien Jarno 
324f8dd19e5SAurelien Jarno     fprintf(stderr,
325f8dd19e5SAurelien Jarno             "Unrecognized bitness %d or condition %d in "
326f8dd19e5SAurelien Jarno             "do_constant_folding_cond.\n", op_bits(op), c);
327f8dd19e5SAurelien Jarno     tcg_abort();
328f8dd19e5SAurelien Jarno }
329f8dd19e5SAurelien Jarno 
330f8dd19e5SAurelien Jarno 
33122613af4SKirill Batuzov /* Propagate constants and copies, fold constant expressions. */
3328f2e8c07SKirill Batuzov static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
3338f2e8c07SKirill Batuzov                                     TCGArg *args, TCGOpDef *tcg_op_defs)
3348f2e8c07SKirill Batuzov {
335fe0de7aaSBlue Swirl     int i, nb_ops, op_index, nb_temps, nb_globals, nb_call_args;
336fe0de7aaSBlue Swirl     TCGOpcode op;
3378f2e8c07SKirill Batuzov     const TCGOpDef *def;
3388f2e8c07SKirill Batuzov     TCGArg *gen_args;
33953108fb5SKirill Batuzov     TCGArg tmp;
34022613af4SKirill Batuzov     /* Array VALS has an element for each temp.
34122613af4SKirill Batuzov        If this temp holds a constant then its value is kept in VALS' element.
34222613af4SKirill Batuzov        If this temp is a copy of other ones then this equivalence class'
34322613af4SKirill Batuzov        representative is kept in VALS' element.
34422613af4SKirill Batuzov        If this temp is neither copy nor constant then corresponding VALS'
34522613af4SKirill Batuzov        element is unused. */
3468f2e8c07SKirill Batuzov 
3478f2e8c07SKirill Batuzov     nb_temps = s->nb_temps;
3488f2e8c07SKirill Batuzov     nb_globals = s->nb_globals;
34922613af4SKirill Batuzov     memset(temps, 0, nb_temps * sizeof(struct tcg_temp_info));
3508f2e8c07SKirill Batuzov 
3518f2e8c07SKirill Batuzov     nb_ops = tcg_opc_ptr - gen_opc_buf;
3528f2e8c07SKirill Batuzov     gen_args = args;
3538f2e8c07SKirill Batuzov     for (op_index = 0; op_index < nb_ops; op_index++) {
3548f2e8c07SKirill Batuzov         op = gen_opc_buf[op_index];
3558f2e8c07SKirill Batuzov         def = &tcg_op_defs[op];
35622613af4SKirill Batuzov         /* Do copy propagation */
35722613af4SKirill Batuzov         if (!(def->flags & (TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS))) {
35822613af4SKirill Batuzov             assert(op != INDEX_op_call);
35922613af4SKirill Batuzov             for (i = def->nb_oargs; i < def->nb_oargs + def->nb_iargs; i++) {
36022613af4SKirill Batuzov                 if (temps[args[i]].state == TCG_TEMP_COPY) {
36122613af4SKirill Batuzov                     args[i] = temps[args[i]].val;
36222613af4SKirill Batuzov                 }
36322613af4SKirill Batuzov             }
36422613af4SKirill Batuzov         }
36522613af4SKirill Batuzov 
36653108fb5SKirill Batuzov         /* For commutative operations make constant second argument */
36753108fb5SKirill Batuzov         switch (op) {
36853108fb5SKirill Batuzov         CASE_OP_32_64(add):
36953108fb5SKirill Batuzov         CASE_OP_32_64(mul):
3709a81090bSKirill Batuzov         CASE_OP_32_64(and):
3719a81090bSKirill Batuzov         CASE_OP_32_64(or):
3729a81090bSKirill Batuzov         CASE_OP_32_64(xor):
373cb25c80aSRichard Henderson         CASE_OP_32_64(eqv):
374cb25c80aSRichard Henderson         CASE_OP_32_64(nand):
375cb25c80aSRichard Henderson         CASE_OP_32_64(nor):
37653108fb5SKirill Batuzov             if (temps[args[1]].state == TCG_TEMP_CONST) {
37753108fb5SKirill Batuzov                 tmp = args[1];
37853108fb5SKirill Batuzov                 args[1] = args[2];
37953108fb5SKirill Batuzov                 args[2] = tmp;
38053108fb5SKirill Batuzov             }
38153108fb5SKirill Batuzov             break;
38265a7cce1SAurelien Jarno         CASE_OP_32_64(brcond):
38365a7cce1SAurelien Jarno             if (temps[args[0]].state == TCG_TEMP_CONST
38465a7cce1SAurelien Jarno                 && temps[args[1]].state != TCG_TEMP_CONST) {
38565a7cce1SAurelien Jarno                 tmp = args[0];
38665a7cce1SAurelien Jarno                 args[0] = args[1];
38765a7cce1SAurelien Jarno                 args[1] = tmp;
38865a7cce1SAurelien Jarno                 args[2] = tcg_swap_cond(args[2]);
38965a7cce1SAurelien Jarno             }
39065a7cce1SAurelien Jarno             break;
39165a7cce1SAurelien Jarno         CASE_OP_32_64(setcond):
39265a7cce1SAurelien Jarno             if (temps[args[1]].state == TCG_TEMP_CONST
39365a7cce1SAurelien Jarno                 && temps[args[2]].state != TCG_TEMP_CONST) {
39465a7cce1SAurelien Jarno                 tmp = args[1];
39565a7cce1SAurelien Jarno                 args[1] = args[2];
39665a7cce1SAurelien Jarno                 args[2] = tmp;
39765a7cce1SAurelien Jarno                 args[3] = tcg_swap_cond(args[3]);
39865a7cce1SAurelien Jarno             }
39965a7cce1SAurelien Jarno             break;
40053108fb5SKirill Batuzov         default:
40153108fb5SKirill Batuzov             break;
40253108fb5SKirill Batuzov         }
40353108fb5SKirill Batuzov 
40401ee5282SAurelien Jarno         /* Simplify expressions for "shift/rot r, 0, a => movi r, 0" */
40501ee5282SAurelien Jarno         switch (op) {
40601ee5282SAurelien Jarno         CASE_OP_32_64(shl):
40701ee5282SAurelien Jarno         CASE_OP_32_64(shr):
40801ee5282SAurelien Jarno         CASE_OP_32_64(sar):
40901ee5282SAurelien Jarno         CASE_OP_32_64(rotl):
41001ee5282SAurelien Jarno         CASE_OP_32_64(rotr):
41101ee5282SAurelien Jarno             if (temps[args[1]].state == TCG_TEMP_CONST
41201ee5282SAurelien Jarno                 && temps[args[1]].val == 0) {
41301ee5282SAurelien Jarno                 gen_opc_buf[op_index] = op_to_movi(op);
41401ee5282SAurelien Jarno                 tcg_opt_gen_movi(gen_args, args[0], 0, nb_temps, nb_globals);
41501ee5282SAurelien Jarno                 args += 3;
41601ee5282SAurelien Jarno                 gen_args += 2;
41701ee5282SAurelien Jarno                 continue;
41801ee5282SAurelien Jarno             }
41901ee5282SAurelien Jarno             break;
42001ee5282SAurelien Jarno         default:
42101ee5282SAurelien Jarno             break;
42201ee5282SAurelien Jarno         }
42301ee5282SAurelien Jarno 
42456e49438SAurelien Jarno         /* Simplify expression for "op r, a, 0 => mov r, a" cases */
42553108fb5SKirill Batuzov         switch (op) {
42653108fb5SKirill Batuzov         CASE_OP_32_64(add):
42753108fb5SKirill Batuzov         CASE_OP_32_64(sub):
42855c0975cSKirill Batuzov         CASE_OP_32_64(shl):
42955c0975cSKirill Batuzov         CASE_OP_32_64(shr):
43055c0975cSKirill Batuzov         CASE_OP_32_64(sar):
43125c4d9ccSRichard Henderson         CASE_OP_32_64(rotl):
43225c4d9ccSRichard Henderson         CASE_OP_32_64(rotr):
43338ee188bSAurelien Jarno         CASE_OP_32_64(or):
43438ee188bSAurelien Jarno         CASE_OP_32_64(xor):
43553108fb5SKirill Batuzov             if (temps[args[1]].state == TCG_TEMP_CONST) {
43653108fb5SKirill Batuzov                 /* Proceed with possible constant folding. */
43753108fb5SKirill Batuzov                 break;
43853108fb5SKirill Batuzov             }
43953108fb5SKirill Batuzov             if (temps[args[2]].state == TCG_TEMP_CONST
44053108fb5SKirill Batuzov                 && temps[args[2]].val == 0) {
44153108fb5SKirill Batuzov                 if ((temps[args[0]].state == TCG_TEMP_COPY
44253108fb5SKirill Batuzov                     && temps[args[0]].val == args[1])
44353108fb5SKirill Batuzov                     || args[0] == args[1]) {
44453108fb5SKirill Batuzov                     gen_opc_buf[op_index] = INDEX_op_nop;
44553108fb5SKirill Batuzov                 } else {
44653108fb5SKirill Batuzov                     gen_opc_buf[op_index] = op_to_mov(op);
447e31b0a7cSBlue Swirl                     tcg_opt_gen_mov(s, gen_args, args[0], args[1],
44853108fb5SKirill Batuzov                                     nb_temps, nb_globals);
44953108fb5SKirill Batuzov                     gen_args += 2;
45053108fb5SKirill Batuzov                 }
451*fedc0da2SAurelien Jarno                 args += 3;
45253108fb5SKirill Batuzov                 continue;
45353108fb5SKirill Batuzov             }
45453108fb5SKirill Batuzov             break;
45556e49438SAurelien Jarno         default:
45656e49438SAurelien Jarno             break;
45756e49438SAurelien Jarno         }
45856e49438SAurelien Jarno 
45956e49438SAurelien Jarno         /* Simplify expression for "op r, a, 0 => movi r, 0" cases */
46056e49438SAurelien Jarno         switch (op) {
46161251c0cSAurelien Jarno         CASE_OP_32_64(and):
46253108fb5SKirill Batuzov         CASE_OP_32_64(mul):
46353108fb5SKirill Batuzov             if ((temps[args[2]].state == TCG_TEMP_CONST
46453108fb5SKirill Batuzov                 && temps[args[2]].val == 0)) {
46553108fb5SKirill Batuzov                 gen_opc_buf[op_index] = op_to_movi(op);
46653108fb5SKirill Batuzov                 tcg_opt_gen_movi(gen_args, args[0], 0, nb_temps, nb_globals);
46753108fb5SKirill Batuzov                 args += 3;
46853108fb5SKirill Batuzov                 gen_args += 2;
46953108fb5SKirill Batuzov                 continue;
47053108fb5SKirill Batuzov             }
47153108fb5SKirill Batuzov             break;
47256e49438SAurelien Jarno         default:
47356e49438SAurelien Jarno             break;
47456e49438SAurelien Jarno         }
47556e49438SAurelien Jarno 
47656e49438SAurelien Jarno         /* Simplify expression for "op r, a, a => mov r, a" cases */
47756e49438SAurelien Jarno         switch (op) {
4789a81090bSKirill Batuzov         CASE_OP_32_64(or):
4799a81090bSKirill Batuzov         CASE_OP_32_64(and):
4809a81090bSKirill Batuzov             if (args[1] == args[2]) {
4819a81090bSKirill Batuzov                 if (args[1] == args[0]) {
4829a81090bSKirill Batuzov                     gen_opc_buf[op_index] = INDEX_op_nop;
4839a81090bSKirill Batuzov                 } else {
4849a81090bSKirill Batuzov                     gen_opc_buf[op_index] = op_to_mov(op);
485e31b0a7cSBlue Swirl                     tcg_opt_gen_mov(s, gen_args, args[0], args[1], nb_temps,
4869a81090bSKirill Batuzov                                     nb_globals);
4879a81090bSKirill Batuzov                     gen_args += 2;
4889a81090bSKirill Batuzov                 }
489*fedc0da2SAurelien Jarno                 args += 3;
4909a81090bSKirill Batuzov                 continue;
4919a81090bSKirill Batuzov             }
4929a81090bSKirill Batuzov             break;
493fe0de7aaSBlue Swirl         default:
494fe0de7aaSBlue Swirl             break;
49553108fb5SKirill Batuzov         }
49653108fb5SKirill Batuzov 
49722613af4SKirill Batuzov         /* Propagate constants through copy operations and do constant
49822613af4SKirill Batuzov            folding.  Constants will be substituted to arguments by register
49922613af4SKirill Batuzov            allocator where needed and possible.  Also detect copies. */
5008f2e8c07SKirill Batuzov         switch (op) {
50122613af4SKirill Batuzov         CASE_OP_32_64(mov):
50222613af4SKirill Batuzov             if ((temps[args[1]].state == TCG_TEMP_COPY
50322613af4SKirill Batuzov                 && temps[args[1]].val == args[0])
50422613af4SKirill Batuzov                 || args[0] == args[1]) {
50522613af4SKirill Batuzov                 args += 2;
50622613af4SKirill Batuzov                 gen_opc_buf[op_index] = INDEX_op_nop;
50722613af4SKirill Batuzov                 break;
50822613af4SKirill Batuzov             }
50922613af4SKirill Batuzov             if (temps[args[1]].state != TCG_TEMP_CONST) {
510e31b0a7cSBlue Swirl                 tcg_opt_gen_mov(s, gen_args, args[0], args[1],
51122613af4SKirill Batuzov                                 nb_temps, nb_globals);
51222613af4SKirill Batuzov                 gen_args += 2;
51322613af4SKirill Batuzov                 args += 2;
51422613af4SKirill Batuzov                 break;
51522613af4SKirill Batuzov             }
51622613af4SKirill Batuzov             /* Source argument is constant.  Rewrite the operation and
51722613af4SKirill Batuzov                let movi case handle it. */
51822613af4SKirill Batuzov             op = op_to_movi(op);
51922613af4SKirill Batuzov             gen_opc_buf[op_index] = op;
52022613af4SKirill Batuzov             args[1] = temps[args[1]].val;
52122613af4SKirill Batuzov             /* fallthrough */
52222613af4SKirill Batuzov         CASE_OP_32_64(movi):
52322613af4SKirill Batuzov             tcg_opt_gen_movi(gen_args, args[0], args[1], nb_temps, nb_globals);
52422613af4SKirill Batuzov             gen_args += 2;
52522613af4SKirill Batuzov             args += 2;
52622613af4SKirill Batuzov             break;
527a640f031SKirill Batuzov         CASE_OP_32_64(not):
528cb25c80aSRichard Henderson         CASE_OP_32_64(neg):
52925c4d9ccSRichard Henderson         CASE_OP_32_64(ext8s):
53025c4d9ccSRichard Henderson         CASE_OP_32_64(ext8u):
53125c4d9ccSRichard Henderson         CASE_OP_32_64(ext16s):
53225c4d9ccSRichard Henderson         CASE_OP_32_64(ext16u):
533a640f031SKirill Batuzov         case INDEX_op_ext32s_i64:
534a640f031SKirill Batuzov         case INDEX_op_ext32u_i64:
535a640f031SKirill Batuzov             if (temps[args[1]].state == TCG_TEMP_CONST) {
536a640f031SKirill Batuzov                 gen_opc_buf[op_index] = op_to_movi(op);
537a640f031SKirill Batuzov                 tmp = do_constant_folding(op, temps[args[1]].val, 0);
538a640f031SKirill Batuzov                 tcg_opt_gen_movi(gen_args, args[0], tmp, nb_temps, nb_globals);
539a640f031SKirill Batuzov             } else {
540a640f031SKirill Batuzov                 reset_temp(args[0], nb_temps, nb_globals);
541a640f031SKirill Batuzov                 gen_args[0] = args[0];
542a640f031SKirill Batuzov                 gen_args[1] = args[1];
543*fedc0da2SAurelien Jarno             }
544a640f031SKirill Batuzov             gen_args += 2;
545a640f031SKirill Batuzov             args += 2;
546a640f031SKirill Batuzov             break;
54753108fb5SKirill Batuzov         CASE_OP_32_64(add):
54853108fb5SKirill Batuzov         CASE_OP_32_64(sub):
54953108fb5SKirill Batuzov         CASE_OP_32_64(mul):
5509a81090bSKirill Batuzov         CASE_OP_32_64(or):
5519a81090bSKirill Batuzov         CASE_OP_32_64(and):
5529a81090bSKirill Batuzov         CASE_OP_32_64(xor):
55355c0975cSKirill Batuzov         CASE_OP_32_64(shl):
55455c0975cSKirill Batuzov         CASE_OP_32_64(shr):
55555c0975cSKirill Batuzov         CASE_OP_32_64(sar):
55625c4d9ccSRichard Henderson         CASE_OP_32_64(rotl):
55725c4d9ccSRichard Henderson         CASE_OP_32_64(rotr):
558cb25c80aSRichard Henderson         CASE_OP_32_64(andc):
559cb25c80aSRichard Henderson         CASE_OP_32_64(orc):
560cb25c80aSRichard Henderson         CASE_OP_32_64(eqv):
561cb25c80aSRichard Henderson         CASE_OP_32_64(nand):
562cb25c80aSRichard Henderson         CASE_OP_32_64(nor):
56353108fb5SKirill Batuzov             if (temps[args[1]].state == TCG_TEMP_CONST
56453108fb5SKirill Batuzov                 && temps[args[2]].state == TCG_TEMP_CONST) {
56553108fb5SKirill Batuzov                 gen_opc_buf[op_index] = op_to_movi(op);
56653108fb5SKirill Batuzov                 tmp = do_constant_folding(op, temps[args[1]].val,
56753108fb5SKirill Batuzov                                           temps[args[2]].val);
56853108fb5SKirill Batuzov                 tcg_opt_gen_movi(gen_args, args[0], tmp, nb_temps, nb_globals);
56953108fb5SKirill Batuzov                 gen_args += 2;
57053108fb5SKirill Batuzov             } else {
57153108fb5SKirill Batuzov                 reset_temp(args[0], nb_temps, nb_globals);
57253108fb5SKirill Batuzov                 gen_args[0] = args[0];
57353108fb5SKirill Batuzov                 gen_args[1] = args[1];
57453108fb5SKirill Batuzov                 gen_args[2] = args[2];
57553108fb5SKirill Batuzov                 gen_args += 3;
576*fedc0da2SAurelien Jarno             }
57753108fb5SKirill Batuzov             args += 3;
57853108fb5SKirill Batuzov             break;
579f8dd19e5SAurelien Jarno         CASE_OP_32_64(setcond):
580f8dd19e5SAurelien Jarno             if (temps[args[1]].state == TCG_TEMP_CONST
581f8dd19e5SAurelien Jarno                 && temps[args[2]].state == TCG_TEMP_CONST) {
582f8dd19e5SAurelien Jarno                 gen_opc_buf[op_index] = op_to_movi(op);
583f8dd19e5SAurelien Jarno                 tmp = do_constant_folding_cond(op, temps[args[1]].val,
584f8dd19e5SAurelien Jarno                                                temps[args[2]].val, args[3]);
585f8dd19e5SAurelien Jarno                 tcg_opt_gen_movi(gen_args, args[0], tmp, nb_temps, nb_globals);
586f8dd19e5SAurelien Jarno                 gen_args += 2;
587f8dd19e5SAurelien Jarno             } else {
588f8dd19e5SAurelien Jarno                 reset_temp(args[0], nb_temps, nb_globals);
589f8dd19e5SAurelien Jarno                 gen_args[0] = args[0];
590f8dd19e5SAurelien Jarno                 gen_args[1] = args[1];
591f8dd19e5SAurelien Jarno                 gen_args[2] = args[2];
592f8dd19e5SAurelien Jarno                 gen_args[3] = args[3];
593f8dd19e5SAurelien Jarno                 gen_args += 4;
594*fedc0da2SAurelien Jarno             }
595f8dd19e5SAurelien Jarno             args += 4;
596f8dd19e5SAurelien Jarno             break;
597fbeaa26cSAurelien Jarno         CASE_OP_32_64(brcond):
598fbeaa26cSAurelien Jarno             if (temps[args[0]].state == TCG_TEMP_CONST
599fbeaa26cSAurelien Jarno                 && temps[args[1]].state == TCG_TEMP_CONST) {
600fbeaa26cSAurelien Jarno                 if (do_constant_folding_cond(op, temps[args[0]].val,
601fbeaa26cSAurelien Jarno                                              temps[args[1]].val, args[2])) {
602fbeaa26cSAurelien Jarno                     memset(temps, 0, nb_temps * sizeof(struct tcg_temp_info));
603fbeaa26cSAurelien Jarno                     gen_opc_buf[op_index] = INDEX_op_br;
604fbeaa26cSAurelien Jarno                     gen_args[0] = args[3];
605fbeaa26cSAurelien Jarno                     gen_args += 1;
606fbeaa26cSAurelien Jarno                 } else {
607fbeaa26cSAurelien Jarno                     gen_opc_buf[op_index] = INDEX_op_nop;
608fbeaa26cSAurelien Jarno                 }
609fbeaa26cSAurelien Jarno             } else {
610fbeaa26cSAurelien Jarno                 memset(temps, 0, nb_temps * sizeof(struct tcg_temp_info));
611fbeaa26cSAurelien Jarno                 reset_temp(args[0], nb_temps, nb_globals);
612fbeaa26cSAurelien Jarno                 gen_args[0] = args[0];
613fbeaa26cSAurelien Jarno                 gen_args[1] = args[1];
614fbeaa26cSAurelien Jarno                 gen_args[2] = args[2];
615fbeaa26cSAurelien Jarno                 gen_args[3] = args[3];
616fbeaa26cSAurelien Jarno                 gen_args += 4;
617*fedc0da2SAurelien Jarno             }
618fbeaa26cSAurelien Jarno             args += 4;
619fbeaa26cSAurelien Jarno             break;
6208f2e8c07SKirill Batuzov         case INDEX_op_call:
62122613af4SKirill Batuzov             nb_call_args = (args[0] >> 16) + (args[0] & 0xffff);
62222613af4SKirill Batuzov             if (!(args[nb_call_args + 1] & (TCG_CALL_CONST | TCG_CALL_PURE))) {
62322613af4SKirill Batuzov                 for (i = 0; i < nb_globals; i++) {
62422613af4SKirill Batuzov                     reset_temp(i, nb_temps, nb_globals);
62522613af4SKirill Batuzov                 }
62622613af4SKirill Batuzov             }
62722613af4SKirill Batuzov             for (i = 0; i < (args[0] >> 16); i++) {
62822613af4SKirill Batuzov                 reset_temp(args[i + 1], nb_temps, nb_globals);
62922613af4SKirill Batuzov             }
63022613af4SKirill Batuzov             i = nb_call_args + 3;
6318f2e8c07SKirill Batuzov             while (i) {
6328f2e8c07SKirill Batuzov                 *gen_args = *args;
6338f2e8c07SKirill Batuzov                 args++;
6348f2e8c07SKirill Batuzov                 gen_args++;
6358f2e8c07SKirill Batuzov                 i--;
6368f2e8c07SKirill Batuzov             }
6378f2e8c07SKirill Batuzov             break;
6388f2e8c07SKirill Batuzov         case INDEX_op_set_label:
6398f2e8c07SKirill Batuzov         case INDEX_op_jmp:
6408f2e8c07SKirill Batuzov         case INDEX_op_br:
64122613af4SKirill Batuzov             memset(temps, 0, nb_temps * sizeof(struct tcg_temp_info));
6428f2e8c07SKirill Batuzov             for (i = 0; i < def->nb_args; i++) {
6438f2e8c07SKirill Batuzov                 *gen_args = *args;
6448f2e8c07SKirill Batuzov                 args++;
6458f2e8c07SKirill Batuzov                 gen_args++;
6468f2e8c07SKirill Batuzov             }
6478f2e8c07SKirill Batuzov             break;
6488f2e8c07SKirill Batuzov         default:
64922613af4SKirill Batuzov             /* Default case: we do know nothing about operation so no
65022613af4SKirill Batuzov                propagation is done.  We only trash output args.  */
65122613af4SKirill Batuzov             for (i = 0; i < def->nb_oargs; i++) {
65222613af4SKirill Batuzov                 reset_temp(args[i], nb_temps, nb_globals);
65322613af4SKirill Batuzov             }
6548f2e8c07SKirill Batuzov             for (i = 0; i < def->nb_args; i++) {
6558f2e8c07SKirill Batuzov                 gen_args[i] = args[i];
6568f2e8c07SKirill Batuzov             }
6578f2e8c07SKirill Batuzov             args += def->nb_args;
6588f2e8c07SKirill Batuzov             gen_args += def->nb_args;
6598f2e8c07SKirill Batuzov             break;
6608f2e8c07SKirill Batuzov         }
6618f2e8c07SKirill Batuzov     }
6628f2e8c07SKirill Batuzov 
6638f2e8c07SKirill Batuzov     return gen_args;
6648f2e8c07SKirill Batuzov }
6658f2e8c07SKirill Batuzov 
6668f2e8c07SKirill Batuzov TCGArg *tcg_optimize(TCGContext *s, uint16_t *tcg_opc_ptr,
6678f2e8c07SKirill Batuzov         TCGArg *args, TCGOpDef *tcg_op_defs)
6688f2e8c07SKirill Batuzov {
6698f2e8c07SKirill Batuzov     TCGArg *res;
6708f2e8c07SKirill Batuzov     res = tcg_constant_folding(s, tcg_opc_ptr, args, tcg_op_defs);
6718f2e8c07SKirill Batuzov     return res;
6728f2e8c07SKirill Batuzov }
673