xref: /openbmc/qemu/tcg/optimize.c (revision d193a14a)
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;
4922613af4SKirill Batuzov };
5022613af4SKirill Batuzov 
5122613af4SKirill Batuzov static struct tcg_temp_info temps[TCG_MAX_TEMPS];
5222613af4SKirill Batuzov 
53e590d4e6SAurelien Jarno /* Reset TEMP's state to TCG_TEMP_UNDEF.  If TEMP only had one copy, remove
54e590d4e6SAurelien Jarno    the copy flag from the left temp.  */
55e590d4e6SAurelien Jarno static void reset_temp(TCGArg temp)
5622613af4SKirill Batuzov {
57e590d4e6SAurelien Jarno     if (temps[temp].state == TCG_TEMP_COPY) {
58e590d4e6SAurelien Jarno         if (temps[temp].prev_copy == temps[temp].next_copy) {
59e590d4e6SAurelien Jarno             temps[temps[temp].next_copy].state = TCG_TEMP_UNDEF;
6022613af4SKirill Batuzov         } else {
6122613af4SKirill Batuzov             temps[temps[temp].next_copy].prev_copy = temps[temp].prev_copy;
6222613af4SKirill Batuzov             temps[temps[temp].prev_copy].next_copy = temps[temp].next_copy;
63e590d4e6SAurelien Jarno         }
6422613af4SKirill Batuzov     }
6548b56ce1SAurelien Jarno     temps[temp].state = TCG_TEMP_UNDEF;
6622613af4SKirill Batuzov }
6722613af4SKirill Batuzov 
68*d193a14aSPaolo Bonzini /* Reset all temporaries, given that there are NB_TEMPS of them.  */
69*d193a14aSPaolo Bonzini static void reset_all_temps(int nb_temps)
70*d193a14aSPaolo Bonzini {
71*d193a14aSPaolo Bonzini     int i;
72*d193a14aSPaolo Bonzini     for (i = 0; i < nb_temps; i++) {
73*d193a14aSPaolo Bonzini         temps[i].state = TCG_TEMP_UNDEF;
74*d193a14aSPaolo Bonzini     }
75*d193a14aSPaolo Bonzini }
76*d193a14aSPaolo Bonzini 
77fe0de7aaSBlue Swirl static int op_bits(TCGOpcode op)
7822613af4SKirill Batuzov {
798399ad59SRichard Henderson     const TCGOpDef *def = &tcg_op_defs[op];
808399ad59SRichard Henderson     return def->flags & TCG_OPF_64BIT ? 64 : 32;
8122613af4SKirill Batuzov }
8222613af4SKirill Batuzov 
83fe0de7aaSBlue Swirl static TCGOpcode op_to_movi(TCGOpcode op)
8422613af4SKirill Batuzov {
8522613af4SKirill Batuzov     switch (op_bits(op)) {
8622613af4SKirill Batuzov     case 32:
8722613af4SKirill Batuzov         return INDEX_op_movi_i32;
8822613af4SKirill Batuzov     case 64:
8922613af4SKirill Batuzov         return INDEX_op_movi_i64;
9022613af4SKirill Batuzov     default:
9122613af4SKirill Batuzov         fprintf(stderr, "op_to_movi: unexpected return value of "
9222613af4SKirill Batuzov                 "function op_bits.\n");
9322613af4SKirill Batuzov         tcg_abort();
9422613af4SKirill Batuzov     }
9522613af4SKirill Batuzov }
9622613af4SKirill Batuzov 
97e590d4e6SAurelien Jarno static TCGArg find_better_copy(TCGContext *s, TCGArg temp)
98e590d4e6SAurelien Jarno {
99e590d4e6SAurelien Jarno     TCGArg i;
100e590d4e6SAurelien Jarno 
101e590d4e6SAurelien Jarno     /* If this is already a global, we can't do better. */
102e590d4e6SAurelien Jarno     if (temp < s->nb_globals) {
103e590d4e6SAurelien Jarno         return temp;
104e590d4e6SAurelien Jarno     }
105e590d4e6SAurelien Jarno 
106e590d4e6SAurelien Jarno     /* Search for a global first. */
107e590d4e6SAurelien Jarno     for (i = temps[temp].next_copy ; i != temp ; i = temps[i].next_copy) {
108e590d4e6SAurelien Jarno         if (i < s->nb_globals) {
109e590d4e6SAurelien Jarno             return i;
110e590d4e6SAurelien Jarno         }
111e590d4e6SAurelien Jarno     }
112e590d4e6SAurelien Jarno 
113e590d4e6SAurelien Jarno     /* If it is a temp, search for a temp local. */
114e590d4e6SAurelien Jarno     if (!s->temps[temp].temp_local) {
115e590d4e6SAurelien Jarno         for (i = temps[temp].next_copy ; i != temp ; i = temps[i].next_copy) {
116e590d4e6SAurelien Jarno             if (s->temps[i].temp_local) {
117e590d4e6SAurelien Jarno                 return i;
118e590d4e6SAurelien Jarno             }
119e590d4e6SAurelien Jarno         }
120e590d4e6SAurelien Jarno     }
121e590d4e6SAurelien Jarno 
122e590d4e6SAurelien Jarno     /* Failure to find a better representation, return the same temp. */
123e590d4e6SAurelien Jarno     return temp;
124e590d4e6SAurelien Jarno }
125e590d4e6SAurelien Jarno 
126e590d4e6SAurelien Jarno static bool temps_are_copies(TCGArg arg1, TCGArg arg2)
127e590d4e6SAurelien Jarno {
128e590d4e6SAurelien Jarno     TCGArg i;
129e590d4e6SAurelien Jarno 
130e590d4e6SAurelien Jarno     if (arg1 == arg2) {
131e590d4e6SAurelien Jarno         return true;
132e590d4e6SAurelien Jarno     }
133e590d4e6SAurelien Jarno 
134e590d4e6SAurelien Jarno     if (temps[arg1].state != TCG_TEMP_COPY
135e590d4e6SAurelien Jarno         || temps[arg2].state != TCG_TEMP_COPY) {
136e590d4e6SAurelien Jarno         return false;
137e590d4e6SAurelien Jarno     }
138e590d4e6SAurelien Jarno 
139e590d4e6SAurelien Jarno     for (i = temps[arg1].next_copy ; i != arg1 ; i = temps[i].next_copy) {
140e590d4e6SAurelien Jarno         if (i == arg2) {
141e590d4e6SAurelien Jarno             return true;
142e590d4e6SAurelien Jarno         }
143e590d4e6SAurelien Jarno     }
144e590d4e6SAurelien Jarno 
145e590d4e6SAurelien Jarno     return false;
146e590d4e6SAurelien Jarno }
147e590d4e6SAurelien Jarno 
148b80bb016SAurelien Jarno static void tcg_opt_gen_mov(TCGContext *s, TCGArg *gen_args,
149b80bb016SAurelien Jarno                             TCGArg dst, TCGArg src)
15022613af4SKirill Batuzov {
151e590d4e6SAurelien Jarno         reset_temp(dst);
15222613af4SKirill Batuzov         assert(temps[src].state != TCG_TEMP_CONST);
153e590d4e6SAurelien Jarno 
154e590d4e6SAurelien Jarno         if (s->temps[src].type == s->temps[dst].type) {
155e590d4e6SAurelien Jarno             if (temps[src].state != TCG_TEMP_COPY) {
156e590d4e6SAurelien Jarno                 temps[src].state = TCG_TEMP_COPY;
15722613af4SKirill Batuzov                 temps[src].next_copy = src;
15822613af4SKirill Batuzov                 temps[src].prev_copy = src;
15922613af4SKirill Batuzov             }
16022613af4SKirill Batuzov             temps[dst].state = TCG_TEMP_COPY;
16122613af4SKirill Batuzov             temps[dst].next_copy = temps[src].next_copy;
16222613af4SKirill Batuzov             temps[dst].prev_copy = src;
16322613af4SKirill Batuzov             temps[temps[dst].next_copy].prev_copy = dst;
16422613af4SKirill Batuzov             temps[src].next_copy = dst;
16522613af4SKirill Batuzov         }
166e590d4e6SAurelien Jarno 
16722613af4SKirill Batuzov         gen_args[0] = dst;
16822613af4SKirill Batuzov         gen_args[1] = src;
16922613af4SKirill Batuzov }
17022613af4SKirill Batuzov 
171e590d4e6SAurelien Jarno static void tcg_opt_gen_movi(TCGArg *gen_args, TCGArg dst, TCGArg val)
17222613af4SKirill Batuzov {
173e590d4e6SAurelien Jarno         reset_temp(dst);
17422613af4SKirill Batuzov         temps[dst].state = TCG_TEMP_CONST;
17522613af4SKirill Batuzov         temps[dst].val = val;
17622613af4SKirill Batuzov         gen_args[0] = dst;
17722613af4SKirill Batuzov         gen_args[1] = val;
17822613af4SKirill Batuzov }
17922613af4SKirill Batuzov 
180fe0de7aaSBlue Swirl static TCGOpcode op_to_mov(TCGOpcode op)
18153108fb5SKirill Batuzov {
18253108fb5SKirill Batuzov     switch (op_bits(op)) {
18353108fb5SKirill Batuzov     case 32:
18453108fb5SKirill Batuzov         return INDEX_op_mov_i32;
18553108fb5SKirill Batuzov     case 64:
18653108fb5SKirill Batuzov         return INDEX_op_mov_i64;
18753108fb5SKirill Batuzov     default:
18853108fb5SKirill Batuzov         fprintf(stderr, "op_to_mov: unexpected return value of "
18953108fb5SKirill Batuzov                 "function op_bits.\n");
19053108fb5SKirill Batuzov         tcg_abort();
19153108fb5SKirill Batuzov     }
19253108fb5SKirill Batuzov }
19353108fb5SKirill Batuzov 
194fe0de7aaSBlue Swirl static TCGArg do_constant_folding_2(TCGOpcode op, TCGArg x, TCGArg y)
19553108fb5SKirill Batuzov {
19653108fb5SKirill Batuzov     switch (op) {
19753108fb5SKirill Batuzov     CASE_OP_32_64(add):
19853108fb5SKirill Batuzov         return x + y;
19953108fb5SKirill Batuzov 
20053108fb5SKirill Batuzov     CASE_OP_32_64(sub):
20153108fb5SKirill Batuzov         return x - y;
20253108fb5SKirill Batuzov 
20353108fb5SKirill Batuzov     CASE_OP_32_64(mul):
20453108fb5SKirill Batuzov         return x * y;
20553108fb5SKirill Batuzov 
2069a81090bSKirill Batuzov     CASE_OP_32_64(and):
2079a81090bSKirill Batuzov         return x & y;
2089a81090bSKirill Batuzov 
2099a81090bSKirill Batuzov     CASE_OP_32_64(or):
2109a81090bSKirill Batuzov         return x | y;
2119a81090bSKirill Batuzov 
2129a81090bSKirill Batuzov     CASE_OP_32_64(xor):
2139a81090bSKirill Batuzov         return x ^ y;
2149a81090bSKirill Batuzov 
21555c0975cSKirill Batuzov     case INDEX_op_shl_i32:
21655c0975cSKirill Batuzov         return (uint32_t)x << (uint32_t)y;
21755c0975cSKirill Batuzov 
21855c0975cSKirill Batuzov     case INDEX_op_shl_i64:
21955c0975cSKirill Batuzov         return (uint64_t)x << (uint64_t)y;
22055c0975cSKirill Batuzov 
22155c0975cSKirill Batuzov     case INDEX_op_shr_i32:
22255c0975cSKirill Batuzov         return (uint32_t)x >> (uint32_t)y;
22355c0975cSKirill Batuzov 
22455c0975cSKirill Batuzov     case INDEX_op_shr_i64:
22555c0975cSKirill Batuzov         return (uint64_t)x >> (uint64_t)y;
22655c0975cSKirill Batuzov 
22755c0975cSKirill Batuzov     case INDEX_op_sar_i32:
22855c0975cSKirill Batuzov         return (int32_t)x >> (int32_t)y;
22955c0975cSKirill Batuzov 
23055c0975cSKirill Batuzov     case INDEX_op_sar_i64:
23155c0975cSKirill Batuzov         return (int64_t)x >> (int64_t)y;
23255c0975cSKirill Batuzov 
23355c0975cSKirill Batuzov     case INDEX_op_rotr_i32:
23425c4d9ccSRichard Henderson         x = ((uint32_t)x << (32 - y)) | ((uint32_t)x >> y);
23555c0975cSKirill Batuzov         return x;
23655c0975cSKirill Batuzov 
23755c0975cSKirill Batuzov     case INDEX_op_rotr_i64:
23825c4d9ccSRichard Henderson         x = ((uint64_t)x << (64 - y)) | ((uint64_t)x >> y);
23955c0975cSKirill Batuzov         return x;
24055c0975cSKirill Batuzov 
24155c0975cSKirill Batuzov     case INDEX_op_rotl_i32:
24225c4d9ccSRichard Henderson         x = ((uint32_t)x << y) | ((uint32_t)x >> (32 - y));
24355c0975cSKirill Batuzov         return x;
24455c0975cSKirill Batuzov 
24555c0975cSKirill Batuzov     case INDEX_op_rotl_i64:
24625c4d9ccSRichard Henderson         x = ((uint64_t)x << y) | ((uint64_t)x >> (64 - y));
24755c0975cSKirill Batuzov         return x;
24855c0975cSKirill Batuzov 
24925c4d9ccSRichard Henderson     CASE_OP_32_64(not):
250a640f031SKirill Batuzov         return ~x;
251a640f031SKirill Batuzov 
252cb25c80aSRichard Henderson     CASE_OP_32_64(neg):
253cb25c80aSRichard Henderson         return -x;
254cb25c80aSRichard Henderson 
255cb25c80aSRichard Henderson     CASE_OP_32_64(andc):
256cb25c80aSRichard Henderson         return x & ~y;
257cb25c80aSRichard Henderson 
258cb25c80aSRichard Henderson     CASE_OP_32_64(orc):
259cb25c80aSRichard Henderson         return x | ~y;
260cb25c80aSRichard Henderson 
261cb25c80aSRichard Henderson     CASE_OP_32_64(eqv):
262cb25c80aSRichard Henderson         return ~(x ^ y);
263cb25c80aSRichard Henderson 
264cb25c80aSRichard Henderson     CASE_OP_32_64(nand):
265cb25c80aSRichard Henderson         return ~(x & y);
266cb25c80aSRichard Henderson 
267cb25c80aSRichard Henderson     CASE_OP_32_64(nor):
268cb25c80aSRichard Henderson         return ~(x | y);
269cb25c80aSRichard Henderson 
27025c4d9ccSRichard Henderson     CASE_OP_32_64(ext8s):
271a640f031SKirill Batuzov         return (int8_t)x;
272a640f031SKirill Batuzov 
27325c4d9ccSRichard Henderson     CASE_OP_32_64(ext16s):
274a640f031SKirill Batuzov         return (int16_t)x;
275a640f031SKirill Batuzov 
27625c4d9ccSRichard Henderson     CASE_OP_32_64(ext8u):
277a640f031SKirill Batuzov         return (uint8_t)x;
278a640f031SKirill Batuzov 
27925c4d9ccSRichard Henderson     CASE_OP_32_64(ext16u):
280a640f031SKirill Batuzov         return (uint16_t)x;
281a640f031SKirill Batuzov 
282a640f031SKirill Batuzov     case INDEX_op_ext32s_i64:
283a640f031SKirill Batuzov         return (int32_t)x;
284a640f031SKirill Batuzov 
285a640f031SKirill Batuzov     case INDEX_op_ext32u_i64:
286a640f031SKirill Batuzov         return (uint32_t)x;
287a640f031SKirill Batuzov 
28853108fb5SKirill Batuzov     default:
28953108fb5SKirill Batuzov         fprintf(stderr,
29053108fb5SKirill Batuzov                 "Unrecognized operation %d in do_constant_folding.\n", op);
29153108fb5SKirill Batuzov         tcg_abort();
29253108fb5SKirill Batuzov     }
29353108fb5SKirill Batuzov }
29453108fb5SKirill Batuzov 
295fe0de7aaSBlue Swirl static TCGArg do_constant_folding(TCGOpcode op, TCGArg x, TCGArg y)
29653108fb5SKirill Batuzov {
29753108fb5SKirill Batuzov     TCGArg res = do_constant_folding_2(op, x, y);
29853108fb5SKirill Batuzov     if (op_bits(op) == 32) {
29953108fb5SKirill Batuzov         res &= 0xffffffff;
30053108fb5SKirill Batuzov     }
30153108fb5SKirill Batuzov     return res;
30253108fb5SKirill Batuzov }
30353108fb5SKirill Batuzov 
3049519da7eSRichard Henderson static bool do_constant_folding_cond_32(uint32_t x, uint32_t y, TCGCond c)
305f8dd19e5SAurelien Jarno {
306f8dd19e5SAurelien Jarno     switch (c) {
307f8dd19e5SAurelien Jarno     case TCG_COND_EQ:
3089519da7eSRichard Henderson         return x == y;
309f8dd19e5SAurelien Jarno     case TCG_COND_NE:
3109519da7eSRichard Henderson         return x != y;
311f8dd19e5SAurelien Jarno     case TCG_COND_LT:
3129519da7eSRichard Henderson         return (int32_t)x < (int32_t)y;
313f8dd19e5SAurelien Jarno     case TCG_COND_GE:
3149519da7eSRichard Henderson         return (int32_t)x >= (int32_t)y;
315f8dd19e5SAurelien Jarno     case TCG_COND_LE:
3169519da7eSRichard Henderson         return (int32_t)x <= (int32_t)y;
317f8dd19e5SAurelien Jarno     case TCG_COND_GT:
3189519da7eSRichard Henderson         return (int32_t)x > (int32_t)y;
319f8dd19e5SAurelien Jarno     case TCG_COND_LTU:
3209519da7eSRichard Henderson         return x < y;
321f8dd19e5SAurelien Jarno     case TCG_COND_GEU:
3229519da7eSRichard Henderson         return x >= y;
323f8dd19e5SAurelien Jarno     case TCG_COND_LEU:
3249519da7eSRichard Henderson         return x <= y;
325f8dd19e5SAurelien Jarno     case TCG_COND_GTU:
3269519da7eSRichard Henderson         return x > y;
3270aed257fSRichard Henderson     default:
3289519da7eSRichard Henderson         tcg_abort();
329f8dd19e5SAurelien Jarno     }
3309519da7eSRichard Henderson }
3319519da7eSRichard Henderson 
3329519da7eSRichard Henderson static bool do_constant_folding_cond_64(uint64_t x, uint64_t y, TCGCond c)
3339519da7eSRichard Henderson {
334f8dd19e5SAurelien Jarno     switch (c) {
335f8dd19e5SAurelien Jarno     case TCG_COND_EQ:
3369519da7eSRichard Henderson         return x == y;
337f8dd19e5SAurelien Jarno     case TCG_COND_NE:
3389519da7eSRichard Henderson         return x != y;
339f8dd19e5SAurelien Jarno     case TCG_COND_LT:
3409519da7eSRichard Henderson         return (int64_t)x < (int64_t)y;
341f8dd19e5SAurelien Jarno     case TCG_COND_GE:
3429519da7eSRichard Henderson         return (int64_t)x >= (int64_t)y;
343f8dd19e5SAurelien Jarno     case TCG_COND_LE:
3449519da7eSRichard Henderson         return (int64_t)x <= (int64_t)y;
345f8dd19e5SAurelien Jarno     case TCG_COND_GT:
3469519da7eSRichard Henderson         return (int64_t)x > (int64_t)y;
347f8dd19e5SAurelien Jarno     case TCG_COND_LTU:
3489519da7eSRichard Henderson         return x < y;
349f8dd19e5SAurelien Jarno     case TCG_COND_GEU:
3509519da7eSRichard Henderson         return x >= y;
351f8dd19e5SAurelien Jarno     case TCG_COND_LEU:
3529519da7eSRichard Henderson         return x <= y;
353f8dd19e5SAurelien Jarno     case TCG_COND_GTU:
3549519da7eSRichard Henderson         return x > y;
3550aed257fSRichard Henderson     default:
3569519da7eSRichard Henderson         tcg_abort();
357f8dd19e5SAurelien Jarno     }
358f8dd19e5SAurelien Jarno }
3599519da7eSRichard Henderson 
3609519da7eSRichard Henderson static bool do_constant_folding_cond_eq(TCGCond c)
3619519da7eSRichard Henderson {
362b336ceb6SAurelien Jarno     switch (c) {
363b336ceb6SAurelien Jarno     case TCG_COND_GT:
364b336ceb6SAurelien Jarno     case TCG_COND_LTU:
365b336ceb6SAurelien Jarno     case TCG_COND_LT:
366b336ceb6SAurelien Jarno     case TCG_COND_GTU:
367b336ceb6SAurelien Jarno     case TCG_COND_NE:
368b336ceb6SAurelien Jarno         return 0;
369b336ceb6SAurelien Jarno     case TCG_COND_GE:
370b336ceb6SAurelien Jarno     case TCG_COND_GEU:
371b336ceb6SAurelien Jarno     case TCG_COND_LE:
372b336ceb6SAurelien Jarno     case TCG_COND_LEU:
373b336ceb6SAurelien Jarno     case TCG_COND_EQ:
374b336ceb6SAurelien Jarno         return 1;
3750aed257fSRichard Henderson     default:
3769519da7eSRichard Henderson         tcg_abort();
377b336ceb6SAurelien Jarno     }
3789519da7eSRichard Henderson }
3799519da7eSRichard Henderson 
3809519da7eSRichard Henderson /* Return 2 if the condition can't be simplified, and the result
3819519da7eSRichard Henderson    of the condition (0 or 1) if it can */
3829519da7eSRichard Henderson static TCGArg do_constant_folding_cond(TCGOpcode op, TCGArg x,
3839519da7eSRichard Henderson                                        TCGArg y, TCGCond c)
3849519da7eSRichard Henderson {
3859519da7eSRichard Henderson     if (temps[x].state == TCG_TEMP_CONST && temps[y].state == TCG_TEMP_CONST) {
3869519da7eSRichard Henderson         switch (op_bits(op)) {
3879519da7eSRichard Henderson         case 32:
3889519da7eSRichard Henderson             return do_constant_folding_cond_32(temps[x].val, temps[y].val, c);
3899519da7eSRichard Henderson         case 64:
3909519da7eSRichard Henderson             return do_constant_folding_cond_64(temps[x].val, temps[y].val, c);
3919519da7eSRichard Henderson         default:
3929519da7eSRichard Henderson             tcg_abort();
3939519da7eSRichard Henderson         }
3949519da7eSRichard Henderson     } else if (temps_are_copies(x, y)) {
3959519da7eSRichard Henderson         return do_constant_folding_cond_eq(c);
396b336ceb6SAurelien Jarno     } else if (temps[y].state == TCG_TEMP_CONST && temps[y].val == 0) {
397b336ceb6SAurelien Jarno         switch (c) {
398b336ceb6SAurelien Jarno         case TCG_COND_LTU:
399b336ceb6SAurelien Jarno             return 0;
400b336ceb6SAurelien Jarno         case TCG_COND_GEU:
401b336ceb6SAurelien Jarno             return 1;
402b336ceb6SAurelien Jarno         default:
403b336ceb6SAurelien Jarno             return 2;
404b336ceb6SAurelien Jarno         }
405b336ceb6SAurelien Jarno     } else {
406b336ceb6SAurelien Jarno         return 2;
407b336ceb6SAurelien Jarno     }
408f8dd19e5SAurelien Jarno }
409f8dd19e5SAurelien Jarno 
4106c4382f8SRichard Henderson /* Return 2 if the condition can't be simplified, and the result
4116c4382f8SRichard Henderson    of the condition (0 or 1) if it can */
4126c4382f8SRichard Henderson static TCGArg do_constant_folding_cond2(TCGArg *p1, TCGArg *p2, TCGCond c)
4136c4382f8SRichard Henderson {
4146c4382f8SRichard Henderson     TCGArg al = p1[0], ah = p1[1];
4156c4382f8SRichard Henderson     TCGArg bl = p2[0], bh = p2[1];
4166c4382f8SRichard Henderson 
4176c4382f8SRichard Henderson     if (temps[bl].state == TCG_TEMP_CONST
4186c4382f8SRichard Henderson         && temps[bh].state == TCG_TEMP_CONST) {
4196c4382f8SRichard Henderson         uint64_t b = ((uint64_t)temps[bh].val << 32) | (uint32_t)temps[bl].val;
4206c4382f8SRichard Henderson 
4216c4382f8SRichard Henderson         if (temps[al].state == TCG_TEMP_CONST
4226c4382f8SRichard Henderson             && temps[ah].state == TCG_TEMP_CONST) {
4236c4382f8SRichard Henderson             uint64_t a;
4246c4382f8SRichard Henderson             a = ((uint64_t)temps[ah].val << 32) | (uint32_t)temps[al].val;
4256c4382f8SRichard Henderson             return do_constant_folding_cond_64(a, b, c);
4266c4382f8SRichard Henderson         }
4276c4382f8SRichard Henderson         if (b == 0) {
4286c4382f8SRichard Henderson             switch (c) {
4296c4382f8SRichard Henderson             case TCG_COND_LTU:
4306c4382f8SRichard Henderson                 return 0;
4316c4382f8SRichard Henderson             case TCG_COND_GEU:
4326c4382f8SRichard Henderson                 return 1;
4336c4382f8SRichard Henderson             default:
4346c4382f8SRichard Henderson                 break;
4356c4382f8SRichard Henderson             }
4366c4382f8SRichard Henderson         }
4376c4382f8SRichard Henderson     }
4386c4382f8SRichard Henderson     if (temps_are_copies(al, bl) && temps_are_copies(ah, bh)) {
4396c4382f8SRichard Henderson         return do_constant_folding_cond_eq(c);
4406c4382f8SRichard Henderson     }
4416c4382f8SRichard Henderson     return 2;
4426c4382f8SRichard Henderson }
4436c4382f8SRichard Henderson 
44424c9ae4eSRichard Henderson static bool swap_commutative(TCGArg dest, TCGArg *p1, TCGArg *p2)
44524c9ae4eSRichard Henderson {
44624c9ae4eSRichard Henderson     TCGArg a1 = *p1, a2 = *p2;
44724c9ae4eSRichard Henderson     int sum = 0;
44824c9ae4eSRichard Henderson     sum += temps[a1].state == TCG_TEMP_CONST;
44924c9ae4eSRichard Henderson     sum -= temps[a2].state == TCG_TEMP_CONST;
45024c9ae4eSRichard Henderson 
45124c9ae4eSRichard Henderson     /* Prefer the constant in second argument, and then the form
45224c9ae4eSRichard Henderson        op a, a, b, which is better handled on non-RISC hosts. */
45324c9ae4eSRichard Henderson     if (sum > 0 || (sum == 0 && dest == a2)) {
45424c9ae4eSRichard Henderson         *p1 = a2;
45524c9ae4eSRichard Henderson         *p2 = a1;
45624c9ae4eSRichard Henderson         return true;
45724c9ae4eSRichard Henderson     }
45824c9ae4eSRichard Henderson     return false;
45924c9ae4eSRichard Henderson }
46024c9ae4eSRichard Henderson 
4610bfcb865SRichard Henderson static bool swap_commutative2(TCGArg *p1, TCGArg *p2)
4620bfcb865SRichard Henderson {
4630bfcb865SRichard Henderson     int sum = 0;
4640bfcb865SRichard Henderson     sum += temps[p1[0]].state == TCG_TEMP_CONST;
4650bfcb865SRichard Henderson     sum += temps[p1[1]].state == TCG_TEMP_CONST;
4660bfcb865SRichard Henderson     sum -= temps[p2[0]].state == TCG_TEMP_CONST;
4670bfcb865SRichard Henderson     sum -= temps[p2[1]].state == TCG_TEMP_CONST;
4680bfcb865SRichard Henderson     if (sum > 0) {
4690bfcb865SRichard Henderson         TCGArg t;
4700bfcb865SRichard Henderson         t = p1[0], p1[0] = p2[0], p2[0] = t;
4710bfcb865SRichard Henderson         t = p1[1], p1[1] = p2[1], p2[1] = t;
4720bfcb865SRichard Henderson         return true;
4730bfcb865SRichard Henderson     }
4740bfcb865SRichard Henderson     return false;
4750bfcb865SRichard Henderson }
4760bfcb865SRichard Henderson 
47722613af4SKirill Batuzov /* Propagate constants and copies, fold constant expressions. */
4788f2e8c07SKirill Batuzov static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
4798f2e8c07SKirill Batuzov                                     TCGArg *args, TCGOpDef *tcg_op_defs)
4808f2e8c07SKirill Batuzov {
481fe0de7aaSBlue Swirl     int i, nb_ops, op_index, nb_temps, nb_globals, nb_call_args;
482fe0de7aaSBlue Swirl     TCGOpcode op;
4838f2e8c07SKirill Batuzov     const TCGOpDef *def;
4848f2e8c07SKirill Batuzov     TCGArg *gen_args;
48553108fb5SKirill Batuzov     TCGArg tmp;
4865d8f5363SRichard Henderson 
48722613af4SKirill Batuzov     /* Array VALS has an element for each temp.
48822613af4SKirill Batuzov        If this temp holds a constant then its value is kept in VALS' element.
489e590d4e6SAurelien Jarno        If this temp is a copy of other ones then the other copies are
490e590d4e6SAurelien Jarno        available through the doubly linked circular list. */
4918f2e8c07SKirill Batuzov 
4928f2e8c07SKirill Batuzov     nb_temps = s->nb_temps;
4938f2e8c07SKirill Batuzov     nb_globals = s->nb_globals;
494*d193a14aSPaolo Bonzini     reset_all_temps(nb_temps);
4958f2e8c07SKirill Batuzov 
49692414b31SEvgeny Voevodin     nb_ops = tcg_opc_ptr - s->gen_opc_buf;
4978f2e8c07SKirill Batuzov     gen_args = args;
4988f2e8c07SKirill Batuzov     for (op_index = 0; op_index < nb_ops; op_index++) {
49992414b31SEvgeny Voevodin         op = s->gen_opc_buf[op_index];
5008f2e8c07SKirill Batuzov         def = &tcg_op_defs[op];
50122613af4SKirill Batuzov         /* Do copy propagation */
5021ff8c541SAurelien Jarno         if (op == INDEX_op_call) {
5031ff8c541SAurelien Jarno             int nb_oargs = args[0] >> 16;
5041ff8c541SAurelien Jarno             int nb_iargs = args[0] & 0xffff;
5051ff8c541SAurelien Jarno             for (i = nb_oargs + 1; i < nb_oargs + nb_iargs + 1; i++) {
5061ff8c541SAurelien Jarno                 if (temps[args[i]].state == TCG_TEMP_COPY) {
5071ff8c541SAurelien Jarno                     args[i] = find_better_copy(s, args[i]);
5081ff8c541SAurelien Jarno                 }
5091ff8c541SAurelien Jarno             }
5101ff8c541SAurelien Jarno         } else {
51122613af4SKirill Batuzov             for (i = def->nb_oargs; i < def->nb_oargs + def->nb_iargs; i++) {
51222613af4SKirill Batuzov                 if (temps[args[i]].state == TCG_TEMP_COPY) {
513e590d4e6SAurelien Jarno                     args[i] = find_better_copy(s, args[i]);
51422613af4SKirill Batuzov                 }
51522613af4SKirill Batuzov             }
51622613af4SKirill Batuzov         }
51722613af4SKirill Batuzov 
51853108fb5SKirill Batuzov         /* For commutative operations make constant second argument */
51953108fb5SKirill Batuzov         switch (op) {
52053108fb5SKirill Batuzov         CASE_OP_32_64(add):
52153108fb5SKirill Batuzov         CASE_OP_32_64(mul):
5229a81090bSKirill Batuzov         CASE_OP_32_64(and):
5239a81090bSKirill Batuzov         CASE_OP_32_64(or):
5249a81090bSKirill Batuzov         CASE_OP_32_64(xor):
525cb25c80aSRichard Henderson         CASE_OP_32_64(eqv):
526cb25c80aSRichard Henderson         CASE_OP_32_64(nand):
527cb25c80aSRichard Henderson         CASE_OP_32_64(nor):
52824c9ae4eSRichard Henderson             swap_commutative(args[0], &args[1], &args[2]);
52953108fb5SKirill Batuzov             break;
53065a7cce1SAurelien Jarno         CASE_OP_32_64(brcond):
53124c9ae4eSRichard Henderson             if (swap_commutative(-1, &args[0], &args[1])) {
53265a7cce1SAurelien Jarno                 args[2] = tcg_swap_cond(args[2]);
53365a7cce1SAurelien Jarno             }
53465a7cce1SAurelien Jarno             break;
53565a7cce1SAurelien Jarno         CASE_OP_32_64(setcond):
53624c9ae4eSRichard Henderson             if (swap_commutative(args[0], &args[1], &args[2])) {
53765a7cce1SAurelien Jarno                 args[3] = tcg_swap_cond(args[3]);
53865a7cce1SAurelien Jarno             }
53965a7cce1SAurelien Jarno             break;
540fa01a208SRichard Henderson         CASE_OP_32_64(movcond):
54124c9ae4eSRichard Henderson             if (swap_commutative(-1, &args[1], &args[2])) {
54224c9ae4eSRichard Henderson                 args[5] = tcg_swap_cond(args[5]);
543fa01a208SRichard Henderson             }
5445d8f5363SRichard Henderson             /* For movcond, we canonicalize the "false" input reg to match
5455d8f5363SRichard Henderson                the destination reg so that the tcg backend can implement
5465d8f5363SRichard Henderson                a "move if true" operation.  */
54724c9ae4eSRichard Henderson             if (swap_commutative(args[0], &args[4], &args[3])) {
54824c9ae4eSRichard Henderson                 args[5] = tcg_invert_cond(args[5]);
5495d8f5363SRichard Henderson             }
5501e484e61SRichard Henderson             break;
5511e484e61SRichard Henderson         case INDEX_op_add2_i32:
5521e484e61SRichard Henderson             swap_commutative(args[0], &args[2], &args[4]);
5531e484e61SRichard Henderson             swap_commutative(args[1], &args[3], &args[5]);
5541e484e61SRichard Henderson             break;
5551414968aSRichard Henderson         case INDEX_op_mulu2_i32:
5561414968aSRichard Henderson             swap_commutative(args[0], &args[2], &args[3]);
5571414968aSRichard Henderson             break;
5580bfcb865SRichard Henderson         case INDEX_op_brcond2_i32:
5590bfcb865SRichard Henderson             if (swap_commutative2(&args[0], &args[2])) {
5600bfcb865SRichard Henderson                 args[4] = tcg_swap_cond(args[4]);
5610bfcb865SRichard Henderson             }
5620bfcb865SRichard Henderson             break;
5630bfcb865SRichard Henderson         case INDEX_op_setcond2_i32:
5640bfcb865SRichard Henderson             if (swap_commutative2(&args[1], &args[3])) {
5650bfcb865SRichard Henderson                 args[5] = tcg_swap_cond(args[5]);
5660bfcb865SRichard Henderson             }
5670bfcb865SRichard Henderson             break;
56853108fb5SKirill Batuzov         default:
56953108fb5SKirill Batuzov             break;
57053108fb5SKirill Batuzov         }
57153108fb5SKirill Batuzov 
57201ee5282SAurelien Jarno         /* Simplify expressions for "shift/rot r, 0, a => movi r, 0" */
57301ee5282SAurelien Jarno         switch (op) {
57401ee5282SAurelien Jarno         CASE_OP_32_64(shl):
57501ee5282SAurelien Jarno         CASE_OP_32_64(shr):
57601ee5282SAurelien Jarno         CASE_OP_32_64(sar):
57701ee5282SAurelien Jarno         CASE_OP_32_64(rotl):
57801ee5282SAurelien Jarno         CASE_OP_32_64(rotr):
57901ee5282SAurelien Jarno             if (temps[args[1]].state == TCG_TEMP_CONST
58001ee5282SAurelien Jarno                 && temps[args[1]].val == 0) {
58192414b31SEvgeny Voevodin                 s->gen_opc_buf[op_index] = op_to_movi(op);
582e590d4e6SAurelien Jarno                 tcg_opt_gen_movi(gen_args, args[0], 0);
58301ee5282SAurelien Jarno                 args += 3;
58401ee5282SAurelien Jarno                 gen_args += 2;
58501ee5282SAurelien Jarno                 continue;
58601ee5282SAurelien Jarno             }
58701ee5282SAurelien Jarno             break;
58801ee5282SAurelien Jarno         default:
58901ee5282SAurelien Jarno             break;
59001ee5282SAurelien Jarno         }
59101ee5282SAurelien Jarno 
59256e49438SAurelien Jarno         /* Simplify expression for "op r, a, 0 => mov r, a" cases */
59353108fb5SKirill Batuzov         switch (op) {
59453108fb5SKirill Batuzov         CASE_OP_32_64(add):
59553108fb5SKirill Batuzov         CASE_OP_32_64(sub):
59655c0975cSKirill Batuzov         CASE_OP_32_64(shl):
59755c0975cSKirill Batuzov         CASE_OP_32_64(shr):
59855c0975cSKirill Batuzov         CASE_OP_32_64(sar):
59925c4d9ccSRichard Henderson         CASE_OP_32_64(rotl):
60025c4d9ccSRichard Henderson         CASE_OP_32_64(rotr):
60138ee188bSAurelien Jarno         CASE_OP_32_64(or):
60238ee188bSAurelien Jarno         CASE_OP_32_64(xor):
60353108fb5SKirill Batuzov             if (temps[args[1]].state == TCG_TEMP_CONST) {
60453108fb5SKirill Batuzov                 /* Proceed with possible constant folding. */
60553108fb5SKirill Batuzov                 break;
60653108fb5SKirill Batuzov             }
60753108fb5SKirill Batuzov             if (temps[args[2]].state == TCG_TEMP_CONST
60853108fb5SKirill Batuzov                 && temps[args[2]].val == 0) {
609e590d4e6SAurelien Jarno                 if (temps_are_copies(args[0], args[1])) {
61092414b31SEvgeny Voevodin                     s->gen_opc_buf[op_index] = INDEX_op_nop;
61153108fb5SKirill Batuzov                 } else {
61292414b31SEvgeny Voevodin                     s->gen_opc_buf[op_index] = op_to_mov(op);
613b80bb016SAurelien Jarno                     tcg_opt_gen_mov(s, gen_args, args[0], args[1]);
61453108fb5SKirill Batuzov                     gen_args += 2;
61553108fb5SKirill Batuzov                 }
616fedc0da2SAurelien Jarno                 args += 3;
61753108fb5SKirill Batuzov                 continue;
61853108fb5SKirill Batuzov             }
61953108fb5SKirill Batuzov             break;
62056e49438SAurelien Jarno         default:
62156e49438SAurelien Jarno             break;
62256e49438SAurelien Jarno         }
62356e49438SAurelien Jarno 
62456e49438SAurelien Jarno         /* Simplify expression for "op r, a, 0 => movi r, 0" cases */
62556e49438SAurelien Jarno         switch (op) {
62661251c0cSAurelien Jarno         CASE_OP_32_64(and):
62753108fb5SKirill Batuzov         CASE_OP_32_64(mul):
62853108fb5SKirill Batuzov             if ((temps[args[2]].state == TCG_TEMP_CONST
62953108fb5SKirill Batuzov                 && temps[args[2]].val == 0)) {
63092414b31SEvgeny Voevodin                 s->gen_opc_buf[op_index] = op_to_movi(op);
631e590d4e6SAurelien Jarno                 tcg_opt_gen_movi(gen_args, args[0], 0);
63253108fb5SKirill Batuzov                 args += 3;
63353108fb5SKirill Batuzov                 gen_args += 2;
63453108fb5SKirill Batuzov                 continue;
63553108fb5SKirill Batuzov             }
63653108fb5SKirill Batuzov             break;
63756e49438SAurelien Jarno         default:
63856e49438SAurelien Jarno             break;
63956e49438SAurelien Jarno         }
64056e49438SAurelien Jarno 
64156e49438SAurelien Jarno         /* Simplify expression for "op r, a, a => mov r, a" cases */
64256e49438SAurelien Jarno         switch (op) {
6439a81090bSKirill Batuzov         CASE_OP_32_64(or):
6449a81090bSKirill Batuzov         CASE_OP_32_64(and):
6450aba1c73SAurelien Jarno             if (temps_are_copies(args[1], args[2])) {
646e590d4e6SAurelien Jarno                 if (temps_are_copies(args[0], args[1])) {
64792414b31SEvgeny Voevodin                     s->gen_opc_buf[op_index] = INDEX_op_nop;
6489a81090bSKirill Batuzov                 } else {
64992414b31SEvgeny Voevodin                     s->gen_opc_buf[op_index] = op_to_mov(op);
650b80bb016SAurelien Jarno                     tcg_opt_gen_mov(s, gen_args, args[0], args[1]);
6519a81090bSKirill Batuzov                     gen_args += 2;
6529a81090bSKirill Batuzov                 }
653fedc0da2SAurelien Jarno                 args += 3;
6549a81090bSKirill Batuzov                 continue;
6559a81090bSKirill Batuzov             }
6569a81090bSKirill Batuzov             break;
657fe0de7aaSBlue Swirl         default:
658fe0de7aaSBlue Swirl             break;
65953108fb5SKirill Batuzov         }
66053108fb5SKirill Batuzov 
6613c94193eSAurelien Jarno         /* Simplify expression for "op r, a, a => movi r, 0" cases */
6623c94193eSAurelien Jarno         switch (op) {
6633c94193eSAurelien Jarno         CASE_OP_32_64(sub):
6643c94193eSAurelien Jarno         CASE_OP_32_64(xor):
6653c94193eSAurelien Jarno             if (temps_are_copies(args[1], args[2])) {
66692414b31SEvgeny Voevodin                 s->gen_opc_buf[op_index] = op_to_movi(op);
6673c94193eSAurelien Jarno                 tcg_opt_gen_movi(gen_args, args[0], 0);
6683c94193eSAurelien Jarno                 gen_args += 2;
6693c94193eSAurelien Jarno                 args += 3;
6703c94193eSAurelien Jarno                 continue;
6713c94193eSAurelien Jarno             }
6723c94193eSAurelien Jarno             break;
6733c94193eSAurelien Jarno         default:
6743c94193eSAurelien Jarno             break;
6753c94193eSAurelien Jarno         }
6763c94193eSAurelien Jarno 
67722613af4SKirill Batuzov         /* Propagate constants through copy operations and do constant
67822613af4SKirill Batuzov            folding.  Constants will be substituted to arguments by register
67922613af4SKirill Batuzov            allocator where needed and possible.  Also detect copies. */
6808f2e8c07SKirill Batuzov         switch (op) {
68122613af4SKirill Batuzov         CASE_OP_32_64(mov):
682e590d4e6SAurelien Jarno             if (temps_are_copies(args[0], args[1])) {
68322613af4SKirill Batuzov                 args += 2;
68492414b31SEvgeny Voevodin                 s->gen_opc_buf[op_index] = INDEX_op_nop;
68522613af4SKirill Batuzov                 break;
68622613af4SKirill Batuzov             }
68722613af4SKirill Batuzov             if (temps[args[1]].state != TCG_TEMP_CONST) {
688b80bb016SAurelien Jarno                 tcg_opt_gen_mov(s, gen_args, args[0], args[1]);
68922613af4SKirill Batuzov                 gen_args += 2;
69022613af4SKirill Batuzov                 args += 2;
69122613af4SKirill Batuzov                 break;
69222613af4SKirill Batuzov             }
69322613af4SKirill Batuzov             /* Source argument is constant.  Rewrite the operation and
69422613af4SKirill Batuzov                let movi case handle it. */
69522613af4SKirill Batuzov             op = op_to_movi(op);
69692414b31SEvgeny Voevodin             s->gen_opc_buf[op_index] = op;
69722613af4SKirill Batuzov             args[1] = temps[args[1]].val;
69822613af4SKirill Batuzov             /* fallthrough */
69922613af4SKirill Batuzov         CASE_OP_32_64(movi):
700e590d4e6SAurelien Jarno             tcg_opt_gen_movi(gen_args, args[0], args[1]);
70122613af4SKirill Batuzov             gen_args += 2;
70222613af4SKirill Batuzov             args += 2;
70322613af4SKirill Batuzov             break;
7046e14e91bSRichard Henderson 
705a640f031SKirill Batuzov         CASE_OP_32_64(not):
706cb25c80aSRichard Henderson         CASE_OP_32_64(neg):
70725c4d9ccSRichard Henderson         CASE_OP_32_64(ext8s):
70825c4d9ccSRichard Henderson         CASE_OP_32_64(ext8u):
70925c4d9ccSRichard Henderson         CASE_OP_32_64(ext16s):
71025c4d9ccSRichard Henderson         CASE_OP_32_64(ext16u):
711a640f031SKirill Batuzov         case INDEX_op_ext32s_i64:
712a640f031SKirill Batuzov         case INDEX_op_ext32u_i64:
713a640f031SKirill Batuzov             if (temps[args[1]].state == TCG_TEMP_CONST) {
71492414b31SEvgeny Voevodin                 s->gen_opc_buf[op_index] = op_to_movi(op);
715a640f031SKirill Batuzov                 tmp = do_constant_folding(op, temps[args[1]].val, 0);
716e590d4e6SAurelien Jarno                 tcg_opt_gen_movi(gen_args, args[0], tmp);
717a640f031SKirill Batuzov                 gen_args += 2;
718a640f031SKirill Batuzov                 args += 2;
719a640f031SKirill Batuzov                 break;
7206e14e91bSRichard Henderson             }
7216e14e91bSRichard Henderson             goto do_default;
7226e14e91bSRichard Henderson 
72353108fb5SKirill Batuzov         CASE_OP_32_64(add):
72453108fb5SKirill Batuzov         CASE_OP_32_64(sub):
72553108fb5SKirill Batuzov         CASE_OP_32_64(mul):
7269a81090bSKirill Batuzov         CASE_OP_32_64(or):
7279a81090bSKirill Batuzov         CASE_OP_32_64(and):
7289a81090bSKirill Batuzov         CASE_OP_32_64(xor):
72955c0975cSKirill Batuzov         CASE_OP_32_64(shl):
73055c0975cSKirill Batuzov         CASE_OP_32_64(shr):
73155c0975cSKirill Batuzov         CASE_OP_32_64(sar):
73225c4d9ccSRichard Henderson         CASE_OP_32_64(rotl):
73325c4d9ccSRichard Henderson         CASE_OP_32_64(rotr):
734cb25c80aSRichard Henderson         CASE_OP_32_64(andc):
735cb25c80aSRichard Henderson         CASE_OP_32_64(orc):
736cb25c80aSRichard Henderson         CASE_OP_32_64(eqv):
737cb25c80aSRichard Henderson         CASE_OP_32_64(nand):
738cb25c80aSRichard Henderson         CASE_OP_32_64(nor):
73953108fb5SKirill Batuzov             if (temps[args[1]].state == TCG_TEMP_CONST
74053108fb5SKirill Batuzov                 && temps[args[2]].state == TCG_TEMP_CONST) {
74192414b31SEvgeny Voevodin                 s->gen_opc_buf[op_index] = op_to_movi(op);
74253108fb5SKirill Batuzov                 tmp = do_constant_folding(op, temps[args[1]].val,
74353108fb5SKirill Batuzov                                           temps[args[2]].val);
744e590d4e6SAurelien Jarno                 tcg_opt_gen_movi(gen_args, args[0], tmp);
74553108fb5SKirill Batuzov                 gen_args += 2;
74653108fb5SKirill Batuzov                 args += 3;
74753108fb5SKirill Batuzov                 break;
7486e14e91bSRichard Henderson             }
7496e14e91bSRichard Henderson             goto do_default;
7506e14e91bSRichard Henderson 
7517ef55fc9SAurelien Jarno         CASE_OP_32_64(deposit):
7527ef55fc9SAurelien Jarno             if (temps[args[1]].state == TCG_TEMP_CONST
7537ef55fc9SAurelien Jarno                 && temps[args[2]].state == TCG_TEMP_CONST) {
75492414b31SEvgeny Voevodin                 s->gen_opc_buf[op_index] = op_to_movi(op);
7557ef55fc9SAurelien Jarno                 tmp = ((1ull << args[4]) - 1);
7567ef55fc9SAurelien Jarno                 tmp = (temps[args[1]].val & ~(tmp << args[3]))
7577ef55fc9SAurelien Jarno                       | ((temps[args[2]].val & tmp) << args[3]);
7587ef55fc9SAurelien Jarno                 tcg_opt_gen_movi(gen_args, args[0], tmp);
7597ef55fc9SAurelien Jarno                 gen_args += 2;
7607ef55fc9SAurelien Jarno                 args += 5;
7617ef55fc9SAurelien Jarno                 break;
7626e14e91bSRichard Henderson             }
7636e14e91bSRichard Henderson             goto do_default;
7646e14e91bSRichard Henderson 
765f8dd19e5SAurelien Jarno         CASE_OP_32_64(setcond):
766b336ceb6SAurelien Jarno             tmp = do_constant_folding_cond(op, args[1], args[2], args[3]);
767b336ceb6SAurelien Jarno             if (tmp != 2) {
76892414b31SEvgeny Voevodin                 s->gen_opc_buf[op_index] = op_to_movi(op);
769e590d4e6SAurelien Jarno                 tcg_opt_gen_movi(gen_args, args[0], tmp);
770f8dd19e5SAurelien Jarno                 gen_args += 2;
771f8dd19e5SAurelien Jarno                 args += 4;
772f8dd19e5SAurelien Jarno                 break;
7736e14e91bSRichard Henderson             }
7746e14e91bSRichard Henderson             goto do_default;
7756e14e91bSRichard Henderson 
776fbeaa26cSAurelien Jarno         CASE_OP_32_64(brcond):
777b336ceb6SAurelien Jarno             tmp = do_constant_folding_cond(op, args[0], args[1], args[2]);
778b336ceb6SAurelien Jarno             if (tmp != 2) {
779b336ceb6SAurelien Jarno                 if (tmp) {
780*d193a14aSPaolo Bonzini                     reset_all_temps(nb_temps);
78192414b31SEvgeny Voevodin                     s->gen_opc_buf[op_index] = INDEX_op_br;
782fbeaa26cSAurelien Jarno                     gen_args[0] = args[3];
783fbeaa26cSAurelien Jarno                     gen_args += 1;
784fbeaa26cSAurelien Jarno                 } else {
78592414b31SEvgeny Voevodin                     s->gen_opc_buf[op_index] = INDEX_op_nop;
786fbeaa26cSAurelien Jarno                 }
787fbeaa26cSAurelien Jarno                 args += 4;
788fbeaa26cSAurelien Jarno                 break;
7896e14e91bSRichard Henderson             }
7906e14e91bSRichard Henderson             goto do_default;
7916e14e91bSRichard Henderson 
792fa01a208SRichard Henderson         CASE_OP_32_64(movcond):
793b336ceb6SAurelien Jarno             tmp = do_constant_folding_cond(op, args[1], args[2], args[5]);
794b336ceb6SAurelien Jarno             if (tmp != 2) {
795e590d4e6SAurelien Jarno                 if (temps_are_copies(args[0], args[4-tmp])) {
79692414b31SEvgeny Voevodin                     s->gen_opc_buf[op_index] = INDEX_op_nop;
797fa01a208SRichard Henderson                 } else if (temps[args[4-tmp]].state == TCG_TEMP_CONST) {
79892414b31SEvgeny Voevodin                     s->gen_opc_buf[op_index] = op_to_movi(op);
799e590d4e6SAurelien Jarno                     tcg_opt_gen_movi(gen_args, args[0], temps[args[4-tmp]].val);
800fa01a208SRichard Henderson                     gen_args += 2;
801fa01a208SRichard Henderson                 } else {
80292414b31SEvgeny Voevodin                     s->gen_opc_buf[op_index] = op_to_mov(op);
803e590d4e6SAurelien Jarno                     tcg_opt_gen_mov(s, gen_args, args[0], args[4-tmp]);
804fa01a208SRichard Henderson                     gen_args += 2;
805fa01a208SRichard Henderson                 }
806fa01a208SRichard Henderson                 args += 6;
807fa01a208SRichard Henderson                 break;
8086e14e91bSRichard Henderson             }
8096e14e91bSRichard Henderson             goto do_default;
8106e14e91bSRichard Henderson 
811212c328dSRichard Henderson         case INDEX_op_add2_i32:
812212c328dSRichard Henderson         case INDEX_op_sub2_i32:
813212c328dSRichard Henderson             if (temps[args[2]].state == TCG_TEMP_CONST
814212c328dSRichard Henderson                 && temps[args[3]].state == TCG_TEMP_CONST
815212c328dSRichard Henderson                 && temps[args[4]].state == TCG_TEMP_CONST
816212c328dSRichard Henderson                 && temps[args[5]].state == TCG_TEMP_CONST) {
817212c328dSRichard Henderson                 uint32_t al = temps[args[2]].val;
818212c328dSRichard Henderson                 uint32_t ah = temps[args[3]].val;
819212c328dSRichard Henderson                 uint32_t bl = temps[args[4]].val;
820212c328dSRichard Henderson                 uint32_t bh = temps[args[5]].val;
821212c328dSRichard Henderson                 uint64_t a = ((uint64_t)ah << 32) | al;
822212c328dSRichard Henderson                 uint64_t b = ((uint64_t)bh << 32) | bl;
823212c328dSRichard Henderson                 TCGArg rl, rh;
824212c328dSRichard Henderson 
825212c328dSRichard Henderson                 if (op == INDEX_op_add2_i32) {
826212c328dSRichard Henderson                     a += b;
827212c328dSRichard Henderson                 } else {
828212c328dSRichard Henderson                     a -= b;
829212c328dSRichard Henderson                 }
830212c328dSRichard Henderson 
831212c328dSRichard Henderson                 /* We emit the extra nop when we emit the add2/sub2.  */
83292414b31SEvgeny Voevodin                 assert(s->gen_opc_buf[op_index + 1] == INDEX_op_nop);
833212c328dSRichard Henderson 
834212c328dSRichard Henderson                 rl = args[0];
835212c328dSRichard Henderson                 rh = args[1];
83692414b31SEvgeny Voevodin                 s->gen_opc_buf[op_index] = INDEX_op_movi_i32;
83792414b31SEvgeny Voevodin                 s->gen_opc_buf[++op_index] = INDEX_op_movi_i32;
838212c328dSRichard Henderson                 tcg_opt_gen_movi(&gen_args[0], rl, (uint32_t)a);
839212c328dSRichard Henderson                 tcg_opt_gen_movi(&gen_args[2], rh, (uint32_t)(a >> 32));
840212c328dSRichard Henderson                 gen_args += 4;
841212c328dSRichard Henderson                 args += 6;
842212c328dSRichard Henderson                 break;
843212c328dSRichard Henderson             }
844212c328dSRichard Henderson             goto do_default;
845212c328dSRichard Henderson 
8461414968aSRichard Henderson         case INDEX_op_mulu2_i32:
8471414968aSRichard Henderson             if (temps[args[2]].state == TCG_TEMP_CONST
8481414968aSRichard Henderson                 && temps[args[3]].state == TCG_TEMP_CONST) {
8491414968aSRichard Henderson                 uint32_t a = temps[args[2]].val;
8501414968aSRichard Henderson                 uint32_t b = temps[args[3]].val;
8511414968aSRichard Henderson                 uint64_t r = (uint64_t)a * b;
8521414968aSRichard Henderson                 TCGArg rl, rh;
8531414968aSRichard Henderson 
8541414968aSRichard Henderson                 /* We emit the extra nop when we emit the mulu2.  */
85592414b31SEvgeny Voevodin                 assert(s->gen_opc_buf[op_index + 1] == INDEX_op_nop);
8561414968aSRichard Henderson 
8571414968aSRichard Henderson                 rl = args[0];
8581414968aSRichard Henderson                 rh = args[1];
85992414b31SEvgeny Voevodin                 s->gen_opc_buf[op_index] = INDEX_op_movi_i32;
86092414b31SEvgeny Voevodin                 s->gen_opc_buf[++op_index] = INDEX_op_movi_i32;
8611414968aSRichard Henderson                 tcg_opt_gen_movi(&gen_args[0], rl, (uint32_t)r);
8621414968aSRichard Henderson                 tcg_opt_gen_movi(&gen_args[2], rh, (uint32_t)(r >> 32));
8631414968aSRichard Henderson                 gen_args += 4;
8641414968aSRichard Henderson                 args += 4;
8651414968aSRichard Henderson                 break;
8661414968aSRichard Henderson             }
8671414968aSRichard Henderson             goto do_default;
8681414968aSRichard Henderson 
869bc1473efSRichard Henderson         case INDEX_op_brcond2_i32:
8706c4382f8SRichard Henderson             tmp = do_constant_folding_cond2(&args[0], &args[2], args[4]);
8716c4382f8SRichard Henderson             if (tmp != 2) {
8726c4382f8SRichard Henderson                 if (tmp) {
873*d193a14aSPaolo Bonzini                     reset_all_temps(nb_temps);
87492414b31SEvgeny Voevodin                     s->gen_opc_buf[op_index] = INDEX_op_br;
8756c4382f8SRichard Henderson                     gen_args[0] = args[5];
8766c4382f8SRichard Henderson                     gen_args += 1;
8776c4382f8SRichard Henderson                 } else {
87892414b31SEvgeny Voevodin                     s->gen_opc_buf[op_index] = INDEX_op_nop;
8796c4382f8SRichard Henderson                 }
8806c4382f8SRichard Henderson             } else if ((args[4] == TCG_COND_LT || args[4] == TCG_COND_GE)
881bc1473efSRichard Henderson                        && temps[args[2]].state == TCG_TEMP_CONST
882bc1473efSRichard Henderson                        && temps[args[3]].state == TCG_TEMP_CONST
883bc1473efSRichard Henderson                        && temps[args[2]].val == 0
884bc1473efSRichard Henderson                        && temps[args[3]].val == 0) {
8856c4382f8SRichard Henderson                 /* Simplify LT/GE comparisons vs zero to a single compare
8866c4382f8SRichard Henderson                    vs the high word of the input.  */
887*d193a14aSPaolo Bonzini                 reset_all_temps(nb_temps);
88892414b31SEvgeny Voevodin                 s->gen_opc_buf[op_index] = INDEX_op_brcond_i32;
889bc1473efSRichard Henderson                 gen_args[0] = args[1];
890bc1473efSRichard Henderson                 gen_args[1] = args[3];
891bc1473efSRichard Henderson                 gen_args[2] = args[4];
892bc1473efSRichard Henderson                 gen_args[3] = args[5];
893bc1473efSRichard Henderson                 gen_args += 4;
8946c4382f8SRichard Henderson             } else {
895bc1473efSRichard Henderson                 goto do_default;
8966c4382f8SRichard Henderson             }
8976c4382f8SRichard Henderson             args += 6;
8986c4382f8SRichard Henderson             break;
899bc1473efSRichard Henderson 
900bc1473efSRichard Henderson         case INDEX_op_setcond2_i32:
9016c4382f8SRichard Henderson             tmp = do_constant_folding_cond2(&args[1], &args[3], args[5]);
9026c4382f8SRichard Henderson             if (tmp != 2) {
90392414b31SEvgeny Voevodin                 s->gen_opc_buf[op_index] = INDEX_op_movi_i32;
9046c4382f8SRichard Henderson                 tcg_opt_gen_movi(gen_args, args[0], tmp);
9056c4382f8SRichard Henderson                 gen_args += 2;
9066c4382f8SRichard Henderson             } else if ((args[5] == TCG_COND_LT || args[5] == TCG_COND_GE)
907bc1473efSRichard Henderson                        && temps[args[3]].state == TCG_TEMP_CONST
908bc1473efSRichard Henderson                        && temps[args[4]].state == TCG_TEMP_CONST
909bc1473efSRichard Henderson                        && temps[args[3]].val == 0
910bc1473efSRichard Henderson                        && temps[args[4]].val == 0) {
9116c4382f8SRichard Henderson                 /* Simplify LT/GE comparisons vs zero to a single compare
9126c4382f8SRichard Henderson                    vs the high word of the input.  */
91392414b31SEvgeny Voevodin                 s->gen_opc_buf[op_index] = INDEX_op_setcond_i32;
914bc1473efSRichard Henderson                 gen_args[0] = args[0];
915bc1473efSRichard Henderson                 gen_args[1] = args[2];
916bc1473efSRichard Henderson                 gen_args[2] = args[4];
917bc1473efSRichard Henderson                 gen_args[3] = args[5];
918bc1473efSRichard Henderson                 gen_args += 4;
9196c4382f8SRichard Henderson             } else {
9206c4382f8SRichard Henderson                 goto do_default;
9216c4382f8SRichard Henderson             }
922bc1473efSRichard Henderson             args += 6;
923bc1473efSRichard Henderson             break;
924bc1473efSRichard Henderson 
9258f2e8c07SKirill Batuzov         case INDEX_op_call:
92622613af4SKirill Batuzov             nb_call_args = (args[0] >> 16) + (args[0] & 0xffff);
92778505279SAurelien Jarno             if (!(args[nb_call_args + 1] & (TCG_CALL_NO_READ_GLOBALS |
92878505279SAurelien Jarno                                             TCG_CALL_NO_WRITE_GLOBALS))) {
92922613af4SKirill Batuzov                 for (i = 0; i < nb_globals; i++) {
930e590d4e6SAurelien Jarno                     reset_temp(i);
93122613af4SKirill Batuzov                 }
93222613af4SKirill Batuzov             }
93322613af4SKirill Batuzov             for (i = 0; i < (args[0] >> 16); i++) {
934e590d4e6SAurelien Jarno                 reset_temp(args[i + 1]);
93522613af4SKirill Batuzov             }
93622613af4SKirill Batuzov             i = nb_call_args + 3;
9378f2e8c07SKirill Batuzov             while (i) {
9388f2e8c07SKirill Batuzov                 *gen_args = *args;
9398f2e8c07SKirill Batuzov                 args++;
9408f2e8c07SKirill Batuzov                 gen_args++;
9418f2e8c07SKirill Batuzov                 i--;
9428f2e8c07SKirill Batuzov             }
9438f2e8c07SKirill Batuzov             break;
9446e14e91bSRichard Henderson 
9458f2e8c07SKirill Batuzov         default:
9466e14e91bSRichard Henderson         do_default:
9476e14e91bSRichard Henderson             /* Default case: we know nothing about operation (or were unable
9486e14e91bSRichard Henderson                to compute the operation result) so no propagation is done.
9496e14e91bSRichard Henderson                We trash everything if the operation is the end of a basic
9506e14e91bSRichard Henderson                block, otherwise we only trash the output args.  */
951a2550660SAurelien Jarno             if (def->flags & TCG_OPF_BB_END) {
952*d193a14aSPaolo Bonzini                 reset_all_temps(nb_temps);
953a2550660SAurelien Jarno             } else {
95422613af4SKirill Batuzov                 for (i = 0; i < def->nb_oargs; i++) {
955e590d4e6SAurelien Jarno                     reset_temp(args[i]);
95622613af4SKirill Batuzov                 }
957a2550660SAurelien Jarno             }
9588f2e8c07SKirill Batuzov             for (i = 0; i < def->nb_args; i++) {
9598f2e8c07SKirill Batuzov                 gen_args[i] = args[i];
9608f2e8c07SKirill Batuzov             }
9618f2e8c07SKirill Batuzov             args += def->nb_args;
9628f2e8c07SKirill Batuzov             gen_args += def->nb_args;
9638f2e8c07SKirill Batuzov             break;
9648f2e8c07SKirill Batuzov         }
9658f2e8c07SKirill Batuzov     }
9668f2e8c07SKirill Batuzov 
9678f2e8c07SKirill Batuzov     return gen_args;
9688f2e8c07SKirill Batuzov }
9698f2e8c07SKirill Batuzov 
9708f2e8c07SKirill Batuzov TCGArg *tcg_optimize(TCGContext *s, uint16_t *tcg_opc_ptr,
9718f2e8c07SKirill Batuzov         TCGArg *args, TCGOpDef *tcg_op_defs)
9728f2e8c07SKirill Batuzov {
9738f2e8c07SKirill Batuzov     TCGArg *res;
9748f2e8c07SKirill Batuzov     res = tcg_constant_folding(s, tcg_opc_ptr, args, tcg_op_defs);
9758f2e8c07SKirill Batuzov     return res;
9768f2e8c07SKirill Batuzov }
977