]> Git Repo - qemu.git/blob - tcg/optimize.c
Do constant folding for unary operations.
[qemu.git] / tcg / optimize.c
1 /*
2  * Optimizations for Tiny Code Generator for QEMU
3  *
4  * Copyright (c) 2010 Samsung Electronics.
5  * Contributed by Kirill Batuzov <[email protected]>
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy
8  * of this software and associated documentation files (the "Software"), to deal
9  * in the Software without restriction, including without limitation the rights
10  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11  * copies of the Software, and to permit persons to whom the Software is
12  * furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in
15  * all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23  * THE SOFTWARE.
24  */
25
26 #include "config.h"
27
28 #include <stdlib.h>
29 #include <stdio.h>
30
31 #include "qemu-common.h"
32 #include "tcg-op.h"
33
34 #if TCG_TARGET_REG_BITS == 64
35 #define CASE_OP_32_64(x)                        \
36         glue(glue(case INDEX_op_, x), _i32):    \
37         glue(glue(case INDEX_op_, x), _i64)
38 #else
39 #define CASE_OP_32_64(x)                        \
40         glue(glue(case INDEX_op_, x), _i32)
41 #endif
42
43 typedef enum {
44     TCG_TEMP_UNDEF = 0,
45     TCG_TEMP_CONST,
46     TCG_TEMP_COPY,
47     TCG_TEMP_HAS_COPY,
48     TCG_TEMP_ANY
49 } tcg_temp_state;
50
51 struct tcg_temp_info {
52     tcg_temp_state state;
53     uint16_t prev_copy;
54     uint16_t next_copy;
55     tcg_target_ulong val;
56 };
57
58 static struct tcg_temp_info temps[TCG_MAX_TEMPS];
59
60 /* Reset TEMP's state to TCG_TEMP_ANY.  If TEMP was a representative of some
61    class of equivalent temp's, a new representative should be chosen in this
62    class. */
63 static void reset_temp(TCGArg temp, int nb_temps, int nb_globals)
64 {
65     int i;
66     TCGArg new_base = (TCGArg)-1;
67     if (temps[temp].state == TCG_TEMP_HAS_COPY) {
68         for (i = temps[temp].next_copy; i != temp; i = temps[i].next_copy) {
69             if (i >= nb_globals) {
70                 temps[i].state = TCG_TEMP_HAS_COPY;
71                 new_base = i;
72                 break;
73             }
74         }
75         for (i = temps[temp].next_copy; i != temp; i = temps[i].next_copy) {
76             if (new_base == (TCGArg)-1) {
77                 temps[i].state = TCG_TEMP_ANY;
78             } else {
79                 temps[i].val = new_base;
80             }
81         }
82         temps[temps[temp].next_copy].prev_copy = temps[temp].prev_copy;
83         temps[temps[temp].prev_copy].next_copy = temps[temp].next_copy;
84     } else if (temps[temp].state == TCG_TEMP_COPY) {
85         temps[temps[temp].next_copy].prev_copy = temps[temp].prev_copy;
86         temps[temps[temp].prev_copy].next_copy = temps[temp].next_copy;
87         new_base = temps[temp].val;
88     }
89     temps[temp].state = TCG_TEMP_ANY;
90     if (new_base != (TCGArg)-1 && temps[new_base].next_copy == new_base) {
91         temps[new_base].state = TCG_TEMP_ANY;
92     }
93 }
94
95 static int op_bits(int op)
96 {
97     switch (op) {
98     case INDEX_op_mov_i32:
99     case INDEX_op_add_i32:
100     case INDEX_op_sub_i32:
101     case INDEX_op_mul_i32:
102     case INDEX_op_and_i32:
103     case INDEX_op_or_i32:
104     case INDEX_op_xor_i32:
105     case INDEX_op_shl_i32:
106     case INDEX_op_shr_i32:
107     case INDEX_op_sar_i32:
108     case INDEX_op_rotl_i32:
109     case INDEX_op_rotr_i32:
110     case INDEX_op_not_i32:
111     case INDEX_op_ext8s_i32:
112     case INDEX_op_ext16s_i32:
113     case INDEX_op_ext8u_i32:
114     case INDEX_op_ext16u_i32:
115         return 32;
116 #if TCG_TARGET_REG_BITS == 64
117     case INDEX_op_mov_i64:
118     case INDEX_op_add_i64:
119     case INDEX_op_sub_i64:
120     case INDEX_op_mul_i64:
121     case INDEX_op_and_i64:
122     case INDEX_op_or_i64:
123     case INDEX_op_xor_i64:
124     case INDEX_op_shl_i64:
125     case INDEX_op_shr_i64:
126     case INDEX_op_sar_i64:
127     case INDEX_op_rotl_i64:
128     case INDEX_op_rotr_i64:
129     case INDEX_op_not_i64:
130     case INDEX_op_ext8s_i64:
131     case INDEX_op_ext16s_i64:
132     case INDEX_op_ext32s_i64:
133     case INDEX_op_ext8u_i64:
134     case INDEX_op_ext16u_i64:
135     case INDEX_op_ext32u_i64:
136         return 64;
137 #endif
138     default:
139         fprintf(stderr, "Unrecognized operation %d in op_bits.\n", op);
140         tcg_abort();
141     }
142 }
143
144 static int op_to_movi(int op)
145 {
146     switch (op_bits(op)) {
147     case 32:
148         return INDEX_op_movi_i32;
149 #if TCG_TARGET_REG_BITS == 64
150     case 64:
151         return INDEX_op_movi_i64;
152 #endif
153     default:
154         fprintf(stderr, "op_to_movi: unexpected return value of "
155                 "function op_bits.\n");
156         tcg_abort();
157     }
158 }
159
160 static void tcg_opt_gen_mov(TCGArg *gen_args, TCGArg dst, TCGArg src,
161                             int nb_temps, int nb_globals)
162 {
163         reset_temp(dst, nb_temps, nb_globals);
164         assert(temps[src].state != TCG_TEMP_COPY);
165         if (src >= nb_globals) {
166             assert(temps[src].state != TCG_TEMP_CONST);
167             if (temps[src].state != TCG_TEMP_HAS_COPY) {
168                 temps[src].state = TCG_TEMP_HAS_COPY;
169                 temps[src].next_copy = src;
170                 temps[src].prev_copy = src;
171             }
172             temps[dst].state = TCG_TEMP_COPY;
173             temps[dst].val = src;
174             temps[dst].next_copy = temps[src].next_copy;
175             temps[dst].prev_copy = src;
176             temps[temps[dst].next_copy].prev_copy = dst;
177             temps[src].next_copy = dst;
178         }
179         gen_args[0] = dst;
180         gen_args[1] = src;
181 }
182
183 static void tcg_opt_gen_movi(TCGArg *gen_args, TCGArg dst, TCGArg val,
184                              int nb_temps, int nb_globals)
185 {
186         reset_temp(dst, nb_temps, nb_globals);
187         temps[dst].state = TCG_TEMP_CONST;
188         temps[dst].val = val;
189         gen_args[0] = dst;
190         gen_args[1] = val;
191 }
192
193 static int op_to_mov(int op)
194 {
195     switch (op_bits(op)) {
196     case 32:
197         return INDEX_op_mov_i32;
198 #if TCG_TARGET_REG_BITS == 64
199     case 64:
200         return INDEX_op_mov_i64;
201 #endif
202     default:
203         fprintf(stderr, "op_to_mov: unexpected return value of "
204                 "function op_bits.\n");
205         tcg_abort();
206     }
207 }
208
209 static TCGArg do_constant_folding_2(int op, TCGArg x, TCGArg y)
210 {
211     switch (op) {
212     CASE_OP_32_64(add):
213         return x + y;
214
215     CASE_OP_32_64(sub):
216         return x - y;
217
218     CASE_OP_32_64(mul):
219         return x * y;
220
221     CASE_OP_32_64(and):
222         return x & y;
223
224     CASE_OP_32_64(or):
225         return x | y;
226
227     CASE_OP_32_64(xor):
228         return x ^ y;
229
230     case INDEX_op_shl_i32:
231         return (uint32_t)x << (uint32_t)y;
232
233 #if TCG_TARGET_REG_BITS == 64
234     case INDEX_op_shl_i64:
235         return (uint64_t)x << (uint64_t)y;
236 #endif
237
238     case INDEX_op_shr_i32:
239         return (uint32_t)x >> (uint32_t)y;
240
241 #if TCG_TARGET_REG_BITS == 64
242     case INDEX_op_shr_i64:
243         return (uint64_t)x >> (uint64_t)y;
244 #endif
245
246     case INDEX_op_sar_i32:
247         return (int32_t)x >> (int32_t)y;
248
249 #if TCG_TARGET_REG_BITS == 64
250     case INDEX_op_sar_i64:
251         return (int64_t)x >> (int64_t)y;
252 #endif
253
254     case INDEX_op_rotr_i32:
255 #if TCG_TARGET_REG_BITS == 64
256         x &= 0xffffffff;
257         y &= 0xffffffff;
258 #endif
259         x = (x << (32 - y)) | (x >> y);
260         return x;
261
262 #if TCG_TARGET_REG_BITS == 64
263     case INDEX_op_rotr_i64:
264         x = (x << (64 - y)) | (x >> y);
265         return x;
266 #endif
267
268     case INDEX_op_rotl_i32:
269 #if TCG_TARGET_REG_BITS == 64
270         x &= 0xffffffff;
271         y &= 0xffffffff;
272 #endif
273         x = (x << y) | (x >> (32 - y));
274         return x;
275
276 #if TCG_TARGET_REG_BITS == 64
277     case INDEX_op_rotl_i64:
278         x = (x << y) | (x >> (64 - y));
279         return x;
280 #endif
281
282     CASE_OP_32_64(not):
283         return ~x;
284
285     CASE_OP_32_64(ext8s):
286         return (int8_t)x;
287
288     CASE_OP_32_64(ext16s):
289         return (int16_t)x;
290
291     CASE_OP_32_64(ext8u):
292         return (uint8_t)x;
293
294     CASE_OP_32_64(ext16u):
295         return (uint16_t)x;
296
297 #if TCG_TARGET_REG_BITS == 64
298     case INDEX_op_ext32s_i64:
299         return (int32_t)x;
300
301     case INDEX_op_ext32u_i64:
302         return (uint32_t)x;
303 #endif
304
305     default:
306         fprintf(stderr,
307                 "Unrecognized operation %d in do_constant_folding.\n", op);
308         tcg_abort();
309     }
310 }
311
312 static TCGArg do_constant_folding(int op, TCGArg x, TCGArg y)
313 {
314     TCGArg res = do_constant_folding_2(op, x, y);
315 #if TCG_TARGET_REG_BITS == 64
316     if (op_bits(op) == 32) {
317         res &= 0xffffffff;
318     }
319 #endif
320     return res;
321 }
322
323 /* Propagate constants and copies, fold constant expressions. */
324 static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
325                                     TCGArg *args, TCGOpDef *tcg_op_defs)
326 {
327     int i, nb_ops, op_index, op, nb_temps, nb_globals, nb_call_args;
328     const TCGOpDef *def;
329     TCGArg *gen_args;
330     TCGArg tmp;
331     /* Array VALS has an element for each temp.
332        If this temp holds a constant then its value is kept in VALS' element.
333        If this temp is a copy of other ones then this equivalence class'
334        representative is kept in VALS' element.
335        If this temp is neither copy nor constant then corresponding VALS'
336        element is unused. */
337
338     nb_temps = s->nb_temps;
339     nb_globals = s->nb_globals;
340     memset(temps, 0, nb_temps * sizeof(struct tcg_temp_info));
341
342     nb_ops = tcg_opc_ptr - gen_opc_buf;
343     gen_args = args;
344     for (op_index = 0; op_index < nb_ops; op_index++) {
345         op = gen_opc_buf[op_index];
346         def = &tcg_op_defs[op];
347         /* Do copy propagation */
348         if (!(def->flags & (TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS))) {
349             assert(op != INDEX_op_call);
350             for (i = def->nb_oargs; i < def->nb_oargs + def->nb_iargs; i++) {
351                 if (temps[args[i]].state == TCG_TEMP_COPY) {
352                     args[i] = temps[args[i]].val;
353                 }
354             }
355         }
356
357         /* For commutative operations make constant second argument */
358         switch (op) {
359         CASE_OP_32_64(add):
360         CASE_OP_32_64(mul):
361         CASE_OP_32_64(and):
362         CASE_OP_32_64(or):
363         CASE_OP_32_64(xor):
364             if (temps[args[1]].state == TCG_TEMP_CONST) {
365                 tmp = args[1];
366                 args[1] = args[2];
367                 args[2] = tmp;
368             }
369             break;
370         default:
371             break;
372         }
373
374         /* Simplify expression if possible. */
375         switch (op) {
376         CASE_OP_32_64(add):
377         CASE_OP_32_64(sub):
378         CASE_OP_32_64(shl):
379         CASE_OP_32_64(shr):
380         CASE_OP_32_64(sar):
381         CASE_OP_32_64(rotl):
382         CASE_OP_32_64(rotr):
383             if (temps[args[1]].state == TCG_TEMP_CONST) {
384                 /* Proceed with possible constant folding. */
385                 break;
386             }
387             if (temps[args[2]].state == TCG_TEMP_CONST
388                 && temps[args[2]].val == 0) {
389                 if ((temps[args[0]].state == TCG_TEMP_COPY
390                     && temps[args[0]].val == args[1])
391                     || args[0] == args[1]) {
392                     args += 3;
393                     gen_opc_buf[op_index] = INDEX_op_nop;
394                 } else {
395                     gen_opc_buf[op_index] = op_to_mov(op);
396                     tcg_opt_gen_mov(gen_args, args[0], args[1],
397                                     nb_temps, nb_globals);
398                     gen_args += 2;
399                     args += 3;
400                 }
401                 continue;
402             }
403             break;
404         CASE_OP_32_64(mul):
405             if ((temps[args[2]].state == TCG_TEMP_CONST
406                 && temps[args[2]].val == 0)) {
407                 gen_opc_buf[op_index] = op_to_movi(op);
408                 tcg_opt_gen_movi(gen_args, args[0], 0, nb_temps, nb_globals);
409                 args += 3;
410                 gen_args += 2;
411                 continue;
412             }
413             break;
414         CASE_OP_32_64(or):
415         CASE_OP_32_64(and):
416             if (args[1] == args[2]) {
417                 if (args[1] == args[0]) {
418                     args += 3;
419                     gen_opc_buf[op_index] = INDEX_op_nop;
420                 } else {
421                     gen_opc_buf[op_index] = op_to_mov(op);
422                     tcg_opt_gen_mov(gen_args, args[0], args[1], nb_temps,
423                                     nb_globals);
424                     gen_args += 2;
425                     args += 3;
426                 }
427                 continue;
428             }
429             break;
430         }
431
432         /* Propagate constants through copy operations and do constant
433            folding.  Constants will be substituted to arguments by register
434            allocator where needed and possible.  Also detect copies. */
435         switch (op) {
436         CASE_OP_32_64(mov):
437             if ((temps[args[1]].state == TCG_TEMP_COPY
438                 && temps[args[1]].val == args[0])
439                 || args[0] == args[1]) {
440                 args += 2;
441                 gen_opc_buf[op_index] = INDEX_op_nop;
442                 break;
443             }
444             if (temps[args[1]].state != TCG_TEMP_CONST) {
445                 tcg_opt_gen_mov(gen_args, args[0], args[1],
446                                 nb_temps, nb_globals);
447                 gen_args += 2;
448                 args += 2;
449                 break;
450             }
451             /* Source argument is constant.  Rewrite the operation and
452                let movi case handle it. */
453             op = op_to_movi(op);
454             gen_opc_buf[op_index] = op;
455             args[1] = temps[args[1]].val;
456             /* fallthrough */
457         CASE_OP_32_64(movi):
458             tcg_opt_gen_movi(gen_args, args[0], args[1], nb_temps, nb_globals);
459             gen_args += 2;
460             args += 2;
461             break;
462         CASE_OP_32_64(not):
463         CASE_OP_32_64(ext8s):
464         CASE_OP_32_64(ext16s):
465         CASE_OP_32_64(ext8u):
466         CASE_OP_32_64(ext16u):
467 #if TCG_TARGET_REG_BITS == 64
468         case INDEX_op_ext32s_i64:
469         case INDEX_op_ext32u_i64:
470 #endif
471             if (temps[args[1]].state == TCG_TEMP_CONST) {
472                 gen_opc_buf[op_index] = op_to_movi(op);
473                 tmp = do_constant_folding(op, temps[args[1]].val, 0);
474                 tcg_opt_gen_movi(gen_args, args[0], tmp, nb_temps, nb_globals);
475                 gen_args += 2;
476                 args += 2;
477                 break;
478             } else {
479                 reset_temp(args[0], nb_temps, nb_globals);
480                 gen_args[0] = args[0];
481                 gen_args[1] = args[1];
482                 gen_args += 2;
483                 args += 2;
484                 break;
485             }
486         CASE_OP_32_64(add):
487         CASE_OP_32_64(sub):
488         CASE_OP_32_64(mul):
489         CASE_OP_32_64(or):
490         CASE_OP_32_64(and):
491         CASE_OP_32_64(xor):
492         CASE_OP_32_64(shl):
493         CASE_OP_32_64(shr):
494         CASE_OP_32_64(sar):
495         CASE_OP_32_64(rotl):
496         CASE_OP_32_64(rotr):
497             if (temps[args[1]].state == TCG_TEMP_CONST
498                 && temps[args[2]].state == TCG_TEMP_CONST) {
499                 gen_opc_buf[op_index] = op_to_movi(op);
500                 tmp = do_constant_folding(op, temps[args[1]].val,
501                                           temps[args[2]].val);
502                 tcg_opt_gen_movi(gen_args, args[0], tmp, nb_temps, nb_globals);
503                 gen_args += 2;
504                 args += 3;
505                 break;
506             } else {
507                 reset_temp(args[0], nb_temps, nb_globals);
508                 gen_args[0] = args[0];
509                 gen_args[1] = args[1];
510                 gen_args[2] = args[2];
511                 gen_args += 3;
512                 args += 3;
513                 break;
514             }
515         case INDEX_op_call:
516             nb_call_args = (args[0] >> 16) + (args[0] & 0xffff);
517             if (!(args[nb_call_args + 1] & (TCG_CALL_CONST | TCG_CALL_PURE))) {
518                 for (i = 0; i < nb_globals; i++) {
519                     reset_temp(i, nb_temps, nb_globals);
520                 }
521             }
522             for (i = 0; i < (args[0] >> 16); i++) {
523                 reset_temp(args[i + 1], nb_temps, nb_globals);
524             }
525             i = nb_call_args + 3;
526             while (i) {
527                 *gen_args = *args;
528                 args++;
529                 gen_args++;
530                 i--;
531             }
532             break;
533         case INDEX_op_set_label:
534         case INDEX_op_jmp:
535         case INDEX_op_br:
536         CASE_OP_32_64(brcond):
537             memset(temps, 0, nb_temps * sizeof(struct tcg_temp_info));
538             for (i = 0; i < def->nb_args; i++) {
539                 *gen_args = *args;
540                 args++;
541                 gen_args++;
542             }
543             break;
544         default:
545             /* Default case: we do know nothing about operation so no
546                propagation is done.  We only trash output args.  */
547             for (i = 0; i < def->nb_oargs; i++) {
548                 reset_temp(args[i], nb_temps, nb_globals);
549             }
550             for (i = 0; i < def->nb_args; i++) {
551                 gen_args[i] = args[i];
552             }
553             args += def->nb_args;
554             gen_args += def->nb_args;
555             break;
556         }
557     }
558
559     return gen_args;
560 }
561
562 TCGArg *tcg_optimize(TCGContext *s, uint16_t *tcg_opc_ptr,
563         TCGArg *args, TCGOpDef *tcg_op_defs)
564 {
565     TCGArg *res;
566     res = tcg_constant_folding(s, tcg_opc_ptr, args, tcg_op_defs);
567     return res;
568 }
This page took 0.055873 seconds and 4 git commands to generate.