]>
git.proxmox.com Git - qemu.git/blob - tcg/optimize.c
1be7631672e1acadc7eb6dce15c7ddf757302d50
2 * Optimizations for Tiny Code Generator for QEMU
4 * Copyright (c) 2010 Samsung Electronics.
5 * Contributed by Kirill Batuzov <batuzovk@ispras.ru>
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:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
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
31 #include "qemu-common.h"
34 #define CASE_OP_32_64(x) \
35 glue(glue(case INDEX_op_, x), _i32): \
36 glue(glue(case INDEX_op_, x), _i64)
46 struct tcg_temp_info
{
53 static struct tcg_temp_info temps
[TCG_MAX_TEMPS
];
55 /* Reset TEMP's state to TCG_TEMP_ANY. If TEMP was a representative of some
56 class of equivalent temp's, a new representative should be chosen in this
58 static void reset_temp(TCGArg temp
, int nb_temps
, int nb_globals
)
61 TCGArg new_base
= (TCGArg
)-1;
62 if (temps
[temp
].state
== TCG_TEMP_HAS_COPY
) {
63 for (i
= temps
[temp
].next_copy
; i
!= temp
; i
= temps
[i
].next_copy
) {
64 if (i
>= nb_globals
) {
65 temps
[i
].state
= TCG_TEMP_HAS_COPY
;
70 for (i
= temps
[temp
].next_copy
; i
!= temp
; i
= temps
[i
].next_copy
) {
71 if (new_base
== (TCGArg
)-1) {
72 temps
[i
].state
= TCG_TEMP_ANY
;
74 temps
[i
].val
= new_base
;
77 temps
[temps
[temp
].next_copy
].prev_copy
= temps
[temp
].prev_copy
;
78 temps
[temps
[temp
].prev_copy
].next_copy
= temps
[temp
].next_copy
;
79 } else if (temps
[temp
].state
== TCG_TEMP_COPY
) {
80 temps
[temps
[temp
].next_copy
].prev_copy
= temps
[temp
].prev_copy
;
81 temps
[temps
[temp
].prev_copy
].next_copy
= temps
[temp
].next_copy
;
82 new_base
= temps
[temp
].val
;
84 temps
[temp
].state
= TCG_TEMP_ANY
;
85 if (new_base
!= (TCGArg
)-1 && temps
[new_base
].next_copy
== new_base
) {
86 temps
[new_base
].state
= TCG_TEMP_ANY
;
90 static int op_bits(TCGOpcode op
)
92 const TCGOpDef
*def
= &tcg_op_defs
[op
];
93 return def
->flags
& TCG_OPF_64BIT
? 64 : 32;
96 static TCGOpcode
op_to_movi(TCGOpcode op
)
98 switch (op_bits(op
)) {
100 return INDEX_op_movi_i32
;
102 return INDEX_op_movi_i64
;
104 fprintf(stderr
, "op_to_movi: unexpected return value of "
105 "function op_bits.\n");
110 static void tcg_opt_gen_mov(TCGArg
*gen_args
, TCGArg dst
, TCGArg src
,
111 int nb_temps
, int nb_globals
)
113 reset_temp(dst
, nb_temps
, nb_globals
);
114 assert(temps
[src
].state
!= TCG_TEMP_COPY
);
115 if (src
>= nb_globals
) {
116 assert(temps
[src
].state
!= TCG_TEMP_CONST
);
117 if (temps
[src
].state
!= TCG_TEMP_HAS_COPY
) {
118 temps
[src
].state
= TCG_TEMP_HAS_COPY
;
119 temps
[src
].next_copy
= src
;
120 temps
[src
].prev_copy
= src
;
122 temps
[dst
].state
= TCG_TEMP_COPY
;
123 temps
[dst
].val
= src
;
124 temps
[dst
].next_copy
= temps
[src
].next_copy
;
125 temps
[dst
].prev_copy
= src
;
126 temps
[temps
[dst
].next_copy
].prev_copy
= dst
;
127 temps
[src
].next_copy
= dst
;
133 static void tcg_opt_gen_movi(TCGArg
*gen_args
, TCGArg dst
, TCGArg val
,
134 int nb_temps
, int nb_globals
)
136 reset_temp(dst
, nb_temps
, nb_globals
);
137 temps
[dst
].state
= TCG_TEMP_CONST
;
138 temps
[dst
].val
= val
;
143 static TCGOpcode
op_to_mov(TCGOpcode op
)
145 switch (op_bits(op
)) {
147 return INDEX_op_mov_i32
;
149 return INDEX_op_mov_i64
;
151 fprintf(stderr
, "op_to_mov: unexpected return value of "
152 "function op_bits.\n");
157 static TCGArg
do_constant_folding_2(TCGOpcode op
, TCGArg x
, TCGArg y
)
178 case INDEX_op_shl_i32
:
179 return (uint32_t)x
<< (uint32_t)y
;
181 case INDEX_op_shl_i64
:
182 return (uint64_t)x
<< (uint64_t)y
;
184 case INDEX_op_shr_i32
:
185 return (uint32_t)x
>> (uint32_t)y
;
187 case INDEX_op_shr_i64
:
188 return (uint64_t)x
>> (uint64_t)y
;
190 case INDEX_op_sar_i32
:
191 return (int32_t)x
>> (int32_t)y
;
193 case INDEX_op_sar_i64
:
194 return (int64_t)x
>> (int64_t)y
;
196 case INDEX_op_rotr_i32
:
197 x
= ((uint32_t)x
<< (32 - y
)) | ((uint32_t)x
>> y
);
200 case INDEX_op_rotr_i64
:
201 x
= ((uint64_t)x
<< (64 - y
)) | ((uint64_t)x
>> y
);
204 case INDEX_op_rotl_i32
:
205 x
= ((uint32_t)x
<< y
) | ((uint32_t)x
>> (32 - y
));
208 case INDEX_op_rotl_i64
:
209 x
= ((uint64_t)x
<< y
) | ((uint64_t)x
>> (64 - y
));
233 CASE_OP_32_64(ext8s
):
236 CASE_OP_32_64(ext16s
):
239 CASE_OP_32_64(ext8u
):
242 CASE_OP_32_64(ext16u
):
245 case INDEX_op_ext32s_i64
:
248 case INDEX_op_ext32u_i64
:
253 "Unrecognized operation %d in do_constant_folding.\n", op
);
258 static TCGArg
do_constant_folding(TCGOpcode op
, TCGArg x
, TCGArg y
)
260 TCGArg res
= do_constant_folding_2(op
, x
, y
);
261 if (op_bits(op
) == 32) {
267 static TCGArg
do_constant_folding_cond(TCGOpcode op
, TCGArg x
,
270 switch (op_bits(op
)) {
274 return (uint32_t)x
== (uint32_t)y
;
276 return (uint32_t)x
!= (uint32_t)y
;
278 return (int32_t)x
< (int32_t)y
;
280 return (int32_t)x
>= (int32_t)y
;
282 return (int32_t)x
<= (int32_t)y
;
284 return (int32_t)x
> (int32_t)y
;
286 return (uint32_t)x
< (uint32_t)y
;
288 return (uint32_t)x
>= (uint32_t)y
;
290 return (uint32_t)x
<= (uint32_t)y
;
292 return (uint32_t)x
> (uint32_t)y
;
298 return (uint64_t)x
== (uint64_t)y
;
300 return (uint64_t)x
!= (uint64_t)y
;
302 return (int64_t)x
< (int64_t)y
;
304 return (int64_t)x
>= (int64_t)y
;
306 return (int64_t)x
<= (int64_t)y
;
308 return (int64_t)x
> (int64_t)y
;
310 return (uint64_t)x
< (uint64_t)y
;
312 return (uint64_t)x
>= (uint64_t)y
;
314 return (uint64_t)x
<= (uint64_t)y
;
316 return (uint64_t)x
> (uint64_t)y
;
322 "Unrecognized bitness %d or condition %d in "
323 "do_constant_folding_cond.\n", op_bits(op
), c
);
328 /* Propagate constants and copies, fold constant expressions. */
329 static TCGArg
*tcg_constant_folding(TCGContext
*s
, uint16_t *tcg_opc_ptr
,
330 TCGArg
*args
, TCGOpDef
*tcg_op_defs
)
332 int i
, nb_ops
, op_index
, nb_temps
, nb_globals
, nb_call_args
;
339 /* Array VALS has an element for each temp.
340 If this temp holds a constant then its value is kept in VALS' element.
341 If this temp is a copy of other ones then this equivalence class'
342 representative is kept in VALS' element.
343 If this temp is neither copy nor constant then corresponding VALS'
344 element is unused. */
346 nb_temps
= s
->nb_temps
;
347 nb_globals
= s
->nb_globals
;
348 memset(temps
, 0, nb_temps
* sizeof(struct tcg_temp_info
));
350 nb_ops
= tcg_opc_ptr
- gen_opc_buf
;
352 for (op_index
= 0; op_index
< nb_ops
; op_index
++) {
353 op
= gen_opc_buf
[op_index
];
354 def
= &tcg_op_defs
[op
];
355 /* Do copy propagation */
356 if (!(def
->flags
& (TCG_OPF_CALL_CLOBBER
| TCG_OPF_SIDE_EFFECTS
))) {
357 assert(op
!= INDEX_op_call
);
358 for (i
= def
->nb_oargs
; i
< def
->nb_oargs
+ def
->nb_iargs
; i
++) {
359 if (temps
[args
[i
]].state
== TCG_TEMP_COPY
) {
360 args
[i
] = temps
[args
[i
]].val
;
365 /* For commutative operations make constant second argument */
375 if (temps
[args
[1]].state
== TCG_TEMP_CONST
) {
381 CASE_OP_32_64(brcond
):
382 if (temps
[args
[0]].state
== TCG_TEMP_CONST
383 && temps
[args
[1]].state
!= TCG_TEMP_CONST
) {
387 args
[2] = tcg_swap_cond(args
[2]);
390 CASE_OP_32_64(setcond
):
391 if (temps
[args
[1]].state
== TCG_TEMP_CONST
392 && temps
[args
[2]].state
!= TCG_TEMP_CONST
) {
396 args
[3] = tcg_swap_cond(args
[3]);
399 CASE_OP_32_64(movcond
):
401 if (temps
[args
[1]].state
== TCG_TEMP_CONST
402 && temps
[args
[2]].state
!= TCG_TEMP_CONST
) {
406 cond
= tcg_swap_cond(cond
);
408 /* For movcond, we canonicalize the "false" input reg to match
409 the destination reg so that the tcg backend can implement
410 a "move if true" operation. */
411 if (args
[0] == args
[3]) {
415 cond
= tcg_invert_cond(cond
);
422 /* Simplify expressions for "shift/rot r, 0, a => movi r, 0" */
429 if (temps
[args
[1]].state
== TCG_TEMP_CONST
430 && temps
[args
[1]].val
== 0) {
431 gen_opc_buf
[op_index
] = op_to_movi(op
);
432 tcg_opt_gen_movi(gen_args
, args
[0], 0, nb_temps
, nb_globals
);
442 /* Simplify expression for "op r, a, 0 => mov r, a" cases */
453 if (temps
[args
[1]].state
== TCG_TEMP_CONST
) {
454 /* Proceed with possible constant folding. */
457 if (temps
[args
[2]].state
== TCG_TEMP_CONST
458 && temps
[args
[2]].val
== 0) {
459 if ((temps
[args
[0]].state
== TCG_TEMP_COPY
460 && temps
[args
[0]].val
== args
[1])
461 || args
[0] == args
[1]) {
462 gen_opc_buf
[op_index
] = INDEX_op_nop
;
464 gen_opc_buf
[op_index
] = op_to_mov(op
);
465 tcg_opt_gen_mov(gen_args
, args
[0], args
[1],
466 nb_temps
, nb_globals
);
477 /* Simplify expression for "op r, a, 0 => movi r, 0" cases */
481 if ((temps
[args
[2]].state
== TCG_TEMP_CONST
482 && temps
[args
[2]].val
== 0)) {
483 gen_opc_buf
[op_index
] = op_to_movi(op
);
484 tcg_opt_gen_movi(gen_args
, args
[0], 0, nb_temps
, nb_globals
);
494 /* Simplify expression for "op r, a, a => mov r, a" cases */
498 if (args
[1] == args
[2]) {
499 if (args
[1] == args
[0]) {
500 gen_opc_buf
[op_index
] = INDEX_op_nop
;
502 gen_opc_buf
[op_index
] = op_to_mov(op
);
503 tcg_opt_gen_mov(gen_args
, args
[0], args
[1], nb_temps
,
515 /* Propagate constants through copy operations and do constant
516 folding. Constants will be substituted to arguments by register
517 allocator where needed and possible. Also detect copies. */
520 if ((temps
[args
[1]].state
== TCG_TEMP_COPY
521 && temps
[args
[1]].val
== args
[0])
522 || args
[0] == args
[1]) {
524 gen_opc_buf
[op_index
] = INDEX_op_nop
;
527 if (temps
[args
[1]].state
!= TCG_TEMP_CONST
) {
528 tcg_opt_gen_mov(gen_args
, args
[0], args
[1],
529 nb_temps
, nb_globals
);
534 /* Source argument is constant. Rewrite the operation and
535 let movi case handle it. */
537 gen_opc_buf
[op_index
] = op
;
538 args
[1] = temps
[args
[1]].val
;
541 tcg_opt_gen_movi(gen_args
, args
[0], args
[1], nb_temps
, nb_globals
);
547 CASE_OP_32_64(ext8s
):
548 CASE_OP_32_64(ext8u
):
549 CASE_OP_32_64(ext16s
):
550 CASE_OP_32_64(ext16u
):
551 case INDEX_op_ext32s_i64
:
552 case INDEX_op_ext32u_i64
:
553 if (temps
[args
[1]].state
== TCG_TEMP_CONST
) {
554 gen_opc_buf
[op_index
] = op_to_movi(op
);
555 tmp
= do_constant_folding(op
, temps
[args
[1]].val
, 0);
556 tcg_opt_gen_movi(gen_args
, args
[0], tmp
, nb_temps
, nb_globals
);
558 reset_temp(args
[0], nb_temps
, nb_globals
);
559 gen_args
[0] = args
[0];
560 gen_args
[1] = args
[1];
581 if (temps
[args
[1]].state
== TCG_TEMP_CONST
582 && temps
[args
[2]].state
== TCG_TEMP_CONST
) {
583 gen_opc_buf
[op_index
] = op_to_movi(op
);
584 tmp
= do_constant_folding(op
, temps
[args
[1]].val
,
586 tcg_opt_gen_movi(gen_args
, args
[0], tmp
, nb_temps
, nb_globals
);
589 reset_temp(args
[0], nb_temps
, nb_globals
);
590 gen_args
[0] = args
[0];
591 gen_args
[1] = args
[1];
592 gen_args
[2] = args
[2];
597 CASE_OP_32_64(setcond
):
598 if (temps
[args
[1]].state
== TCG_TEMP_CONST
599 && temps
[args
[2]].state
== TCG_TEMP_CONST
) {
600 gen_opc_buf
[op_index
] = op_to_movi(op
);
601 tmp
= do_constant_folding_cond(op
, temps
[args
[1]].val
,
602 temps
[args
[2]].val
, args
[3]);
603 tcg_opt_gen_movi(gen_args
, args
[0], tmp
, nb_temps
, nb_globals
);
606 reset_temp(args
[0], nb_temps
, nb_globals
);
607 gen_args
[0] = args
[0];
608 gen_args
[1] = args
[1];
609 gen_args
[2] = args
[2];
610 gen_args
[3] = args
[3];
615 CASE_OP_32_64(brcond
):
616 if (temps
[args
[0]].state
== TCG_TEMP_CONST
617 && temps
[args
[1]].state
== TCG_TEMP_CONST
) {
618 if (do_constant_folding_cond(op
, temps
[args
[0]].val
,
619 temps
[args
[1]].val
, args
[2])) {
620 memset(temps
, 0, nb_temps
* sizeof(struct tcg_temp_info
));
621 gen_opc_buf
[op_index
] = INDEX_op_br
;
622 gen_args
[0] = args
[3];
625 gen_opc_buf
[op_index
] = INDEX_op_nop
;
628 memset(temps
, 0, nb_temps
* sizeof(struct tcg_temp_info
));
629 reset_temp(args
[0], nb_temps
, nb_globals
);
630 gen_args
[0] = args
[0];
631 gen_args
[1] = args
[1];
632 gen_args
[2] = args
[2];
633 gen_args
[3] = args
[3];
638 CASE_OP_32_64(movcond
):
639 if (temps
[args
[1]].state
== TCG_TEMP_CONST
640 && temps
[args
[2]].state
== TCG_TEMP_CONST
) {
641 tmp
= do_constant_folding_cond(op
, temps
[args
[1]].val
,
642 temps
[args
[2]].val
, args
[5]);
643 if (args
[0] == args
[4-tmp
]
644 || (temps
[args
[4-tmp
]].state
== TCG_TEMP_COPY
645 && temps
[args
[4-tmp
]].val
== args
[0])) {
646 gen_opc_buf
[op_index
] = INDEX_op_nop
;
647 } else if (temps
[args
[4-tmp
]].state
== TCG_TEMP_CONST
) {
648 gen_opc_buf
[op_index
] = op_to_movi(op
);
649 tcg_opt_gen_movi(gen_args
, args
[0], temps
[args
[4-tmp
]].val
,
650 nb_temps
, nb_globals
);
653 gen_opc_buf
[op_index
] = op_to_mov(op
);
654 tcg_opt_gen_mov(gen_args
, args
[0], args
[4-tmp
],
655 nb_temps
, nb_globals
);
659 reset_temp(args
[0], nb_temps
, nb_globals
);
660 gen_args
[0] = args
[0];
661 gen_args
[1] = args
[1];
662 gen_args
[2] = args
[2];
663 gen_args
[3] = args
[3];
664 gen_args
[4] = args
[4];
665 gen_args
[5] = args
[5];
671 nb_call_args
= (args
[0] >> 16) + (args
[0] & 0xffff);
672 if (!(args
[nb_call_args
+ 1] & (TCG_CALL_CONST
| TCG_CALL_PURE
))) {
673 for (i
= 0; i
< nb_globals
; i
++) {
674 reset_temp(i
, nb_temps
, nb_globals
);
677 for (i
= 0; i
< (args
[0] >> 16); i
++) {
678 reset_temp(args
[i
+ 1], nb_temps
, nb_globals
);
680 i
= nb_call_args
+ 3;
689 /* Default case: we do know nothing about operation so no
690 propagation is done. We trash everything if the operation
691 is the end of a basic block, otherwise we only trash the
693 if (def
->flags
& TCG_OPF_BB_END
) {
694 memset(temps
, 0, nb_temps
* sizeof(struct tcg_temp_info
));
696 for (i
= 0; i
< def
->nb_oargs
; i
++) {
697 reset_temp(args
[i
], nb_temps
, nb_globals
);
700 for (i
= 0; i
< def
->nb_args
; i
++) {
701 gen_args
[i
] = args
[i
];
703 args
+= def
->nb_args
;
704 gen_args
+= def
->nb_args
;
712 TCGArg
*tcg_optimize(TCGContext
*s
, uint16_t *tcg_opc_ptr
,
713 TCGArg
*args
, TCGOpDef
*tcg_op_defs
)
716 res
= tcg_constant_folding(s
, tcg_opc_ptr
, args
, tcg_op_defs
);