]>
git.proxmox.com Git - mirror_qemu.git/blob - tcg/optimize.c
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)
45 struct tcg_temp_info
{
52 static struct tcg_temp_info temps
[TCG_MAX_TEMPS
];
54 /* Reset TEMP's state to TCG_TEMP_UNDEF. If TEMP was a representative of some
55 class of equivalent temp's, a new representative should be chosen in this
57 static void reset_temp(TCGArg temp
, int nb_temps
, int nb_globals
)
60 TCGArg new_base
= (TCGArg
)-1;
61 if (temps
[temp
].state
== TCG_TEMP_HAS_COPY
) {
62 for (i
= temps
[temp
].next_copy
; i
!= temp
; i
= temps
[i
].next_copy
) {
63 if (i
>= nb_globals
) {
64 temps
[i
].state
= TCG_TEMP_HAS_COPY
;
69 for (i
= temps
[temp
].next_copy
; i
!= temp
; i
= temps
[i
].next_copy
) {
70 if (new_base
== (TCGArg
)-1) {
71 temps
[i
].state
= TCG_TEMP_UNDEF
;
73 temps
[i
].val
= new_base
;
76 temps
[temps
[temp
].next_copy
].prev_copy
= temps
[temp
].prev_copy
;
77 temps
[temps
[temp
].prev_copy
].next_copy
= temps
[temp
].next_copy
;
78 } else if (temps
[temp
].state
== TCG_TEMP_COPY
) {
79 temps
[temps
[temp
].next_copy
].prev_copy
= temps
[temp
].prev_copy
;
80 temps
[temps
[temp
].prev_copy
].next_copy
= temps
[temp
].next_copy
;
81 new_base
= temps
[temp
].val
;
83 temps
[temp
].state
= TCG_TEMP_UNDEF
;
84 if (new_base
!= (TCGArg
)-1 && temps
[new_base
].next_copy
== new_base
) {
85 temps
[new_base
].state
= TCG_TEMP_UNDEF
;
89 static int op_bits(TCGOpcode op
)
91 const TCGOpDef
*def
= &tcg_op_defs
[op
];
92 return def
->flags
& TCG_OPF_64BIT
? 64 : 32;
95 static TCGOpcode
op_to_movi(TCGOpcode op
)
97 switch (op_bits(op
)) {
99 return INDEX_op_movi_i32
;
101 return INDEX_op_movi_i64
;
103 fprintf(stderr
, "op_to_movi: unexpected return value of "
104 "function op_bits.\n");
109 static void tcg_opt_gen_mov(TCGArg
*gen_args
, TCGArg dst
, TCGArg src
,
110 int nb_temps
, int nb_globals
)
112 reset_temp(dst
, nb_temps
, nb_globals
);
113 assert(temps
[src
].state
!= TCG_TEMP_COPY
);
114 if (src
>= nb_globals
) {
115 assert(temps
[src
].state
!= TCG_TEMP_CONST
);
116 if (temps
[src
].state
!= TCG_TEMP_HAS_COPY
) {
117 temps
[src
].state
= TCG_TEMP_HAS_COPY
;
118 temps
[src
].next_copy
= src
;
119 temps
[src
].prev_copy
= src
;
121 temps
[dst
].state
= TCG_TEMP_COPY
;
122 temps
[dst
].val
= src
;
123 temps
[dst
].next_copy
= temps
[src
].next_copy
;
124 temps
[dst
].prev_copy
= src
;
125 temps
[temps
[dst
].next_copy
].prev_copy
= dst
;
126 temps
[src
].next_copy
= dst
;
132 static void tcg_opt_gen_movi(TCGArg
*gen_args
, TCGArg dst
, TCGArg val
,
133 int nb_temps
, int nb_globals
)
135 reset_temp(dst
, nb_temps
, nb_globals
);
136 temps
[dst
].state
= TCG_TEMP_CONST
;
137 temps
[dst
].val
= val
;
142 static TCGOpcode
op_to_mov(TCGOpcode op
)
144 switch (op_bits(op
)) {
146 return INDEX_op_mov_i32
;
148 return INDEX_op_mov_i64
;
150 fprintf(stderr
, "op_to_mov: unexpected return value of "
151 "function op_bits.\n");
156 static TCGArg
do_constant_folding_2(TCGOpcode op
, TCGArg x
, TCGArg y
)
177 case INDEX_op_shl_i32
:
178 return (uint32_t)x
<< (uint32_t)y
;
180 case INDEX_op_shl_i64
:
181 return (uint64_t)x
<< (uint64_t)y
;
183 case INDEX_op_shr_i32
:
184 return (uint32_t)x
>> (uint32_t)y
;
186 case INDEX_op_shr_i64
:
187 return (uint64_t)x
>> (uint64_t)y
;
189 case INDEX_op_sar_i32
:
190 return (int32_t)x
>> (int32_t)y
;
192 case INDEX_op_sar_i64
:
193 return (int64_t)x
>> (int64_t)y
;
195 case INDEX_op_rotr_i32
:
196 x
= ((uint32_t)x
<< (32 - y
)) | ((uint32_t)x
>> y
);
199 case INDEX_op_rotr_i64
:
200 x
= ((uint64_t)x
<< (64 - y
)) | ((uint64_t)x
>> y
);
203 case INDEX_op_rotl_i32
:
204 x
= ((uint32_t)x
<< y
) | ((uint32_t)x
>> (32 - y
));
207 case INDEX_op_rotl_i64
:
208 x
= ((uint64_t)x
<< y
) | ((uint64_t)x
>> (64 - y
));
232 CASE_OP_32_64(ext8s
):
235 CASE_OP_32_64(ext16s
):
238 CASE_OP_32_64(ext8u
):
241 CASE_OP_32_64(ext16u
):
244 case INDEX_op_ext32s_i64
:
247 case INDEX_op_ext32u_i64
:
252 "Unrecognized operation %d in do_constant_folding.\n", op
);
257 static TCGArg
do_constant_folding(TCGOpcode op
, TCGArg x
, TCGArg y
)
259 TCGArg res
= do_constant_folding_2(op
, x
, y
);
260 if (op_bits(op
) == 32) {
266 static TCGArg
do_constant_folding_cond(TCGOpcode op
, TCGArg x
,
269 switch (op_bits(op
)) {
273 return (uint32_t)x
== (uint32_t)y
;
275 return (uint32_t)x
!= (uint32_t)y
;
277 return (int32_t)x
< (int32_t)y
;
279 return (int32_t)x
>= (int32_t)y
;
281 return (int32_t)x
<= (int32_t)y
;
283 return (int32_t)x
> (int32_t)y
;
285 return (uint32_t)x
< (uint32_t)y
;
287 return (uint32_t)x
>= (uint32_t)y
;
289 return (uint32_t)x
<= (uint32_t)y
;
291 return (uint32_t)x
> (uint32_t)y
;
297 return (uint64_t)x
== (uint64_t)y
;
299 return (uint64_t)x
!= (uint64_t)y
;
301 return (int64_t)x
< (int64_t)y
;
303 return (int64_t)x
>= (int64_t)y
;
305 return (int64_t)x
<= (int64_t)y
;
307 return (int64_t)x
> (int64_t)y
;
309 return (uint64_t)x
< (uint64_t)y
;
311 return (uint64_t)x
>= (uint64_t)y
;
313 return (uint64_t)x
<= (uint64_t)y
;
315 return (uint64_t)x
> (uint64_t)y
;
321 "Unrecognized bitness %d or condition %d in "
322 "do_constant_folding_cond.\n", op_bits(op
), c
);
327 /* Propagate constants and copies, fold constant expressions. */
328 static TCGArg
*tcg_constant_folding(TCGContext
*s
, uint16_t *tcg_opc_ptr
,
329 TCGArg
*args
, TCGOpDef
*tcg_op_defs
)
331 int i
, nb_ops
, op_index
, nb_temps
, nb_globals
, nb_call_args
;
338 /* Array VALS has an element for each temp.
339 If this temp holds a constant then its value is kept in VALS' element.
340 If this temp is a copy of other ones then this equivalence class'
341 representative is kept in VALS' element.
342 If this temp is neither copy nor constant then corresponding VALS'
343 element is unused. */
345 nb_temps
= s
->nb_temps
;
346 nb_globals
= s
->nb_globals
;
347 memset(temps
, 0, nb_temps
* sizeof(struct tcg_temp_info
));
349 nb_ops
= tcg_opc_ptr
- gen_opc_buf
;
351 for (op_index
= 0; op_index
< nb_ops
; op_index
++) {
352 op
= gen_opc_buf
[op_index
];
353 def
= &tcg_op_defs
[op
];
354 /* Do copy propagation */
355 if (!(def
->flags
& (TCG_OPF_CALL_CLOBBER
| TCG_OPF_SIDE_EFFECTS
))) {
356 assert(op
!= INDEX_op_call
);
357 for (i
= def
->nb_oargs
; i
< def
->nb_oargs
+ def
->nb_iargs
; i
++) {
358 if (temps
[args
[i
]].state
== TCG_TEMP_COPY
) {
359 args
[i
] = temps
[args
[i
]].val
;
364 /* For commutative operations make constant second argument */
374 if (temps
[args
[1]].state
== TCG_TEMP_CONST
) {
380 CASE_OP_32_64(brcond
):
381 if (temps
[args
[0]].state
== TCG_TEMP_CONST
382 && temps
[args
[1]].state
!= TCG_TEMP_CONST
) {
386 args
[2] = tcg_swap_cond(args
[2]);
389 CASE_OP_32_64(setcond
):
390 if (temps
[args
[1]].state
== TCG_TEMP_CONST
391 && temps
[args
[2]].state
!= TCG_TEMP_CONST
) {
395 args
[3] = tcg_swap_cond(args
[3]);
398 CASE_OP_32_64(movcond
):
400 if (temps
[args
[1]].state
== TCG_TEMP_CONST
401 && temps
[args
[2]].state
!= TCG_TEMP_CONST
) {
405 cond
= tcg_swap_cond(cond
);
407 /* For movcond, we canonicalize the "false" input reg to match
408 the destination reg so that the tcg backend can implement
409 a "move if true" operation. */
410 if (args
[0] == args
[3]) {
414 cond
= tcg_invert_cond(cond
);
421 /* Simplify expressions for "shift/rot r, 0, a => movi r, 0" */
428 if (temps
[args
[1]].state
== TCG_TEMP_CONST
429 && temps
[args
[1]].val
== 0) {
430 gen_opc_buf
[op_index
] = op_to_movi(op
);
431 tcg_opt_gen_movi(gen_args
, args
[0], 0, nb_temps
, nb_globals
);
441 /* Simplify expression for "op r, a, 0 => mov r, a" cases */
452 if (temps
[args
[1]].state
== TCG_TEMP_CONST
) {
453 /* Proceed with possible constant folding. */
456 if (temps
[args
[2]].state
== TCG_TEMP_CONST
457 && temps
[args
[2]].val
== 0) {
458 if ((temps
[args
[0]].state
== TCG_TEMP_COPY
459 && temps
[args
[0]].val
== args
[1])
460 || args
[0] == args
[1]) {
461 gen_opc_buf
[op_index
] = INDEX_op_nop
;
463 gen_opc_buf
[op_index
] = op_to_mov(op
);
464 tcg_opt_gen_mov(gen_args
, args
[0], args
[1],
465 nb_temps
, nb_globals
);
476 /* Simplify expression for "op r, a, 0 => movi r, 0" cases */
480 if ((temps
[args
[2]].state
== TCG_TEMP_CONST
481 && temps
[args
[2]].val
== 0)) {
482 gen_opc_buf
[op_index
] = op_to_movi(op
);
483 tcg_opt_gen_movi(gen_args
, args
[0], 0, nb_temps
, nb_globals
);
493 /* Simplify expression for "op r, a, a => mov r, a" cases */
497 if (args
[1] == args
[2]) {
498 if (args
[1] == args
[0]) {
499 gen_opc_buf
[op_index
] = INDEX_op_nop
;
501 gen_opc_buf
[op_index
] = op_to_mov(op
);
502 tcg_opt_gen_mov(gen_args
, args
[0], args
[1], nb_temps
,
514 /* Propagate constants through copy operations and do constant
515 folding. Constants will be substituted to arguments by register
516 allocator where needed and possible. Also detect copies. */
519 if ((temps
[args
[1]].state
== TCG_TEMP_COPY
520 && temps
[args
[1]].val
== args
[0])
521 || args
[0] == args
[1]) {
523 gen_opc_buf
[op_index
] = INDEX_op_nop
;
526 if (temps
[args
[1]].state
!= TCG_TEMP_CONST
) {
527 tcg_opt_gen_mov(gen_args
, args
[0], args
[1],
528 nb_temps
, nb_globals
);
533 /* Source argument is constant. Rewrite the operation and
534 let movi case handle it. */
536 gen_opc_buf
[op_index
] = op
;
537 args
[1] = temps
[args
[1]].val
;
540 tcg_opt_gen_movi(gen_args
, args
[0], args
[1], nb_temps
, nb_globals
);
546 CASE_OP_32_64(ext8s
):
547 CASE_OP_32_64(ext8u
):
548 CASE_OP_32_64(ext16s
):
549 CASE_OP_32_64(ext16u
):
550 case INDEX_op_ext32s_i64
:
551 case INDEX_op_ext32u_i64
:
552 if (temps
[args
[1]].state
== TCG_TEMP_CONST
) {
553 gen_opc_buf
[op_index
] = op_to_movi(op
);
554 tmp
= do_constant_folding(op
, temps
[args
[1]].val
, 0);
555 tcg_opt_gen_movi(gen_args
, args
[0], tmp
, nb_temps
, nb_globals
);
557 reset_temp(args
[0], nb_temps
, nb_globals
);
558 gen_args
[0] = args
[0];
559 gen_args
[1] = args
[1];
580 if (temps
[args
[1]].state
== TCG_TEMP_CONST
581 && temps
[args
[2]].state
== TCG_TEMP_CONST
) {
582 gen_opc_buf
[op_index
] = op_to_movi(op
);
583 tmp
= do_constant_folding(op
, temps
[args
[1]].val
,
585 tcg_opt_gen_movi(gen_args
, args
[0], tmp
, nb_temps
, nb_globals
);
588 reset_temp(args
[0], nb_temps
, nb_globals
);
589 gen_args
[0] = args
[0];
590 gen_args
[1] = args
[1];
591 gen_args
[2] = args
[2];
596 CASE_OP_32_64(setcond
):
597 if (temps
[args
[1]].state
== TCG_TEMP_CONST
598 && temps
[args
[2]].state
== TCG_TEMP_CONST
) {
599 gen_opc_buf
[op_index
] = op_to_movi(op
);
600 tmp
= do_constant_folding_cond(op
, temps
[args
[1]].val
,
601 temps
[args
[2]].val
, args
[3]);
602 tcg_opt_gen_movi(gen_args
, args
[0], tmp
, nb_temps
, nb_globals
);
605 reset_temp(args
[0], nb_temps
, nb_globals
);
606 gen_args
[0] = args
[0];
607 gen_args
[1] = args
[1];
608 gen_args
[2] = args
[2];
609 gen_args
[3] = args
[3];
614 CASE_OP_32_64(brcond
):
615 if (temps
[args
[0]].state
== TCG_TEMP_CONST
616 && temps
[args
[1]].state
== TCG_TEMP_CONST
) {
617 if (do_constant_folding_cond(op
, temps
[args
[0]].val
,
618 temps
[args
[1]].val
, args
[2])) {
619 memset(temps
, 0, nb_temps
* sizeof(struct tcg_temp_info
));
620 gen_opc_buf
[op_index
] = INDEX_op_br
;
621 gen_args
[0] = args
[3];
624 gen_opc_buf
[op_index
] = INDEX_op_nop
;
627 memset(temps
, 0, nb_temps
* sizeof(struct tcg_temp_info
));
628 reset_temp(args
[0], nb_temps
, nb_globals
);
629 gen_args
[0] = args
[0];
630 gen_args
[1] = args
[1];
631 gen_args
[2] = args
[2];
632 gen_args
[3] = args
[3];
637 CASE_OP_32_64(movcond
):
638 if (temps
[args
[1]].state
== TCG_TEMP_CONST
639 && temps
[args
[2]].state
== TCG_TEMP_CONST
) {
640 tmp
= do_constant_folding_cond(op
, temps
[args
[1]].val
,
641 temps
[args
[2]].val
, args
[5]);
642 if (args
[0] == args
[4-tmp
]
643 || (temps
[args
[4-tmp
]].state
== TCG_TEMP_COPY
644 && temps
[args
[4-tmp
]].val
== args
[0])) {
645 gen_opc_buf
[op_index
] = INDEX_op_nop
;
646 } else if (temps
[args
[4-tmp
]].state
== TCG_TEMP_CONST
) {
647 gen_opc_buf
[op_index
] = op_to_movi(op
);
648 tcg_opt_gen_movi(gen_args
, args
[0], temps
[args
[4-tmp
]].val
,
649 nb_temps
, nb_globals
);
652 gen_opc_buf
[op_index
] = op_to_mov(op
);
653 tcg_opt_gen_mov(gen_args
, args
[0], args
[4-tmp
],
654 nb_temps
, nb_globals
);
658 reset_temp(args
[0], nb_temps
, nb_globals
);
659 gen_args
[0] = args
[0];
660 gen_args
[1] = args
[1];
661 gen_args
[2] = args
[2];
662 gen_args
[3] = args
[3];
663 gen_args
[4] = args
[4];
664 gen_args
[5] = args
[5];
670 nb_call_args
= (args
[0] >> 16) + (args
[0] & 0xffff);
671 if (!(args
[nb_call_args
+ 1] & (TCG_CALL_CONST
| TCG_CALL_PURE
))) {
672 for (i
= 0; i
< nb_globals
; i
++) {
673 reset_temp(i
, nb_temps
, nb_globals
);
676 for (i
= 0; i
< (args
[0] >> 16); i
++) {
677 reset_temp(args
[i
+ 1], nb_temps
, nb_globals
);
679 i
= nb_call_args
+ 3;
688 /* Default case: we do know nothing about operation so no
689 propagation is done. We trash everything if the operation
690 is the end of a basic block, otherwise we only trash the
692 if (def
->flags
& TCG_OPF_BB_END
) {
693 memset(temps
, 0, nb_temps
* sizeof(struct tcg_temp_info
));
695 for (i
= 0; i
< def
->nb_oargs
; i
++) {
696 reset_temp(args
[i
], nb_temps
, nb_globals
);
699 for (i
= 0; i
< def
->nb_args
; i
++) {
700 gen_args
[i
] = args
[i
];
702 args
+= def
->nb_args
;
703 gen_args
+= def
->nb_args
;
711 TCGArg
*tcg_optimize(TCGContext
*s
, uint16_t *tcg_opc_ptr
,
712 TCGArg
*args
, TCGOpDef
*tcg_op_defs
)
715 res
= tcg_constant_folding(s
, tcg_opc_ptr
, args
, tcg_op_defs
);