]>
git.proxmox.com Git - 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 #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)
39 #define CASE_OP_32_64(x) \
40 glue(glue(case INDEX_op_, x), _i32)
51 struct tcg_temp_info
{
58 static struct tcg_temp_info temps
[TCG_MAX_TEMPS
];
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
63 static void reset_temp(TCGArg temp
, int nb_temps
, int nb_globals
)
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
;
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
;
79 temps
[i
].val
= new_base
;
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
;
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
;
95 static int op_bits(enum TCGOpcode op
)
97 const TCGOpDef
*def
= &tcg_op_defs
[op
];
98 return def
->flags
& TCG_OPF_64BIT
? 64 : 32;
101 static int op_to_movi(int op
)
103 switch (op_bits(op
)) {
105 return INDEX_op_movi_i32
;
106 #if TCG_TARGET_REG_BITS == 64
108 return INDEX_op_movi_i64
;
111 fprintf(stderr
, "op_to_movi: unexpected return value of "
112 "function op_bits.\n");
117 static void tcg_opt_gen_mov(TCGContext
*s
, TCGArg
*gen_args
, TCGArg dst
,
118 TCGArg src
, int nb_temps
, int nb_globals
)
120 reset_temp(dst
, nb_temps
, nb_globals
);
121 assert(temps
[src
].state
!= TCG_TEMP_COPY
);
122 /* Don't try to copy if one of temps is a global or either one
123 is local and another is register */
124 if (src
>= nb_globals
&& dst
>= nb_globals
&&
125 tcg_arg_is_local(s
, src
) == tcg_arg_is_local(s
, dst
)) {
126 assert(temps
[src
].state
!= TCG_TEMP_CONST
);
127 if (temps
[src
].state
!= TCG_TEMP_HAS_COPY
) {
128 temps
[src
].state
= TCG_TEMP_HAS_COPY
;
129 temps
[src
].next_copy
= src
;
130 temps
[src
].prev_copy
= src
;
132 temps
[dst
].state
= TCG_TEMP_COPY
;
133 temps
[dst
].val
= src
;
134 temps
[dst
].next_copy
= temps
[src
].next_copy
;
135 temps
[dst
].prev_copy
= src
;
136 temps
[temps
[dst
].next_copy
].prev_copy
= dst
;
137 temps
[src
].next_copy
= dst
;
143 static void tcg_opt_gen_movi(TCGArg
*gen_args
, TCGArg dst
, TCGArg val
,
144 int nb_temps
, int nb_globals
)
146 reset_temp(dst
, nb_temps
, nb_globals
);
147 temps
[dst
].state
= TCG_TEMP_CONST
;
148 temps
[dst
].val
= val
;
153 static int op_to_mov(int op
)
155 switch (op_bits(op
)) {
157 return INDEX_op_mov_i32
;
158 #if TCG_TARGET_REG_BITS == 64
160 return INDEX_op_mov_i64
;
163 fprintf(stderr
, "op_to_mov: unexpected return value of "
164 "function op_bits.\n");
169 static TCGArg
do_constant_folding_2(int op
, TCGArg x
, TCGArg y
)
190 case INDEX_op_shl_i32
:
191 return (uint32_t)x
<< (uint32_t)y
;
193 #if TCG_TARGET_REG_BITS == 64
194 case INDEX_op_shl_i64
:
195 return (uint64_t)x
<< (uint64_t)y
;
198 case INDEX_op_shr_i32
:
199 return (uint32_t)x
>> (uint32_t)y
;
201 #if TCG_TARGET_REG_BITS == 64
202 case INDEX_op_shr_i64
:
203 return (uint64_t)x
>> (uint64_t)y
;
206 case INDEX_op_sar_i32
:
207 return (int32_t)x
>> (int32_t)y
;
209 #if TCG_TARGET_REG_BITS == 64
210 case INDEX_op_sar_i64
:
211 return (int64_t)x
>> (int64_t)y
;
214 #ifdef TCG_TARGET_HAS_rot_i32
215 case INDEX_op_rotr_i32
:
216 #if TCG_TARGET_REG_BITS == 64
220 x
= (x
<< (32 - y
)) | (x
>> y
);
224 #ifdef TCG_TARGET_HAS_rot_i64
225 #if TCG_TARGET_REG_BITS == 64
226 case INDEX_op_rotr_i64
:
227 x
= (x
<< (64 - y
)) | (x
>> y
);
232 #ifdef TCG_TARGET_HAS_rot_i32
233 case INDEX_op_rotl_i32
:
234 #if TCG_TARGET_REG_BITS == 64
238 x
= (x
<< y
) | (x
>> (32 - y
));
242 #ifdef TCG_TARGET_HAS_rot_i64
243 #if TCG_TARGET_REG_BITS == 64
244 case INDEX_op_rotl_i64
:
245 x
= (x
<< y
) | (x
>> (64 - y
));
250 #if defined(TCG_TARGET_HAS_not_i32) || defined(TCG_TARGET_HAS_not_i64)
251 #ifdef TCG_TARGET_HAS_not_i32
252 case INDEX_op_not_i32
:
254 #ifdef TCG_TARGET_HAS_not_i64
255 case INDEX_op_not_i64
:
260 #if defined(TCG_TARGET_HAS_ext8s_i32) || defined(TCG_TARGET_HAS_ext8s_i64)
261 #ifdef TCG_TARGET_HAS_ext8s_i32
262 case INDEX_op_ext8s_i32
:
264 #ifdef TCG_TARGET_HAS_ext8s_i64
265 case INDEX_op_ext8s_i64
:
270 #if defined(TCG_TARGET_HAS_ext16s_i32) || defined(TCG_TARGET_HAS_ext16s_i64)
271 #ifdef TCG_TARGET_HAS_ext16s_i32
272 case INDEX_op_ext16s_i32
:
274 #ifdef TCG_TARGET_HAS_ext16s_i64
275 case INDEX_op_ext16s_i64
:
280 #if defined(TCG_TARGET_HAS_ext8u_i32) || defined(TCG_TARGET_HAS_ext8u_i64)
281 #ifdef TCG_TARGET_HAS_ext8u_i32
282 case INDEX_op_ext8u_i32
:
284 #ifdef TCG_TARGET_HAS_ext8u_i64
285 case INDEX_op_ext8u_i64
:
290 #if defined(TCG_TARGET_HAS_ext16u_i32) || defined(TCG_TARGET_HAS_ext16u_i64)
291 #ifdef TCG_TARGET_HAS_ext16u_i32
292 case INDEX_op_ext16u_i32
:
294 #ifdef TCG_TARGET_HAS_ext16u_i64
295 case INDEX_op_ext16u_i64
:
300 #if TCG_TARGET_REG_BITS == 64
301 #ifdef TCG_TARGET_HAS_ext32s_i64
302 case INDEX_op_ext32s_i64
:
306 #ifdef TCG_TARGET_HAS_ext32u_i64
307 case INDEX_op_ext32u_i64
:
314 "Unrecognized operation %d in do_constant_folding.\n", op
);
319 static TCGArg
do_constant_folding(int op
, TCGArg x
, TCGArg y
)
321 TCGArg res
= do_constant_folding_2(op
, x
, y
);
322 #if TCG_TARGET_REG_BITS == 64
323 if (op_bits(op
) == 32) {
330 /* Propagate constants and copies, fold constant expressions. */
331 static TCGArg
*tcg_constant_folding(TCGContext
*s
, uint16_t *tcg_opc_ptr
,
332 TCGArg
*args
, TCGOpDef
*tcg_op_defs
)
334 int i
, nb_ops
, op_index
, op
, 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 */
371 if (temps
[args
[1]].state
== TCG_TEMP_CONST
) {
381 /* Simplify expression if possible. */
388 #ifdef TCG_TARGET_HAS_rot_i32
389 case INDEX_op_rotl_i32
:
390 case INDEX_op_rotr_i32
:
392 #ifdef TCG_TARGET_HAS_rot_i64
393 case INDEX_op_rotl_i64
:
394 case INDEX_op_rotr_i64
:
396 if (temps
[args
[1]].state
== TCG_TEMP_CONST
) {
397 /* Proceed with possible constant folding. */
400 if (temps
[args
[2]].state
== TCG_TEMP_CONST
401 && temps
[args
[2]].val
== 0) {
402 if ((temps
[args
[0]].state
== TCG_TEMP_COPY
403 && temps
[args
[0]].val
== args
[1])
404 || args
[0] == args
[1]) {
406 gen_opc_buf
[op_index
] = INDEX_op_nop
;
408 gen_opc_buf
[op_index
] = op_to_mov(op
);
409 tcg_opt_gen_mov(s
, gen_args
, args
[0], args
[1],
410 nb_temps
, nb_globals
);
418 if ((temps
[args
[2]].state
== TCG_TEMP_CONST
419 && temps
[args
[2]].val
== 0)) {
420 gen_opc_buf
[op_index
] = op_to_movi(op
);
421 tcg_opt_gen_movi(gen_args
, args
[0], 0, nb_temps
, nb_globals
);
429 if (args
[1] == args
[2]) {
430 if (args
[1] == args
[0]) {
432 gen_opc_buf
[op_index
] = INDEX_op_nop
;
434 gen_opc_buf
[op_index
] = op_to_mov(op
);
435 tcg_opt_gen_mov(s
, gen_args
, args
[0], args
[1], nb_temps
,
445 /* Propagate constants through copy operations and do constant
446 folding. Constants will be substituted to arguments by register
447 allocator where needed and possible. Also detect copies. */
450 if ((temps
[args
[1]].state
== TCG_TEMP_COPY
451 && temps
[args
[1]].val
== args
[0])
452 || args
[0] == args
[1]) {
454 gen_opc_buf
[op_index
] = INDEX_op_nop
;
457 if (temps
[args
[1]].state
!= TCG_TEMP_CONST
) {
458 tcg_opt_gen_mov(s
, gen_args
, args
[0], args
[1],
459 nb_temps
, nb_globals
);
464 /* Source argument is constant. Rewrite the operation and
465 let movi case handle it. */
467 gen_opc_buf
[op_index
] = op
;
468 args
[1] = temps
[args
[1]].val
;
471 tcg_opt_gen_movi(gen_args
, args
[0], args
[1], nb_temps
, nb_globals
);
476 #ifdef TCG_TARGET_HAS_ext8s_i32
477 case INDEX_op_ext8s_i32
:
479 #ifdef TCG_TARGET_HAS_ext8s_i64
480 case INDEX_op_ext8s_i64
:
482 #ifdef TCG_TARGET_HAS_ext16s_i32
483 case INDEX_op_ext16s_i32
:
485 #ifdef TCG_TARGET_HAS_ext16s_i64
486 case INDEX_op_ext16s_i64
:
488 #ifdef TCG_TARGET_HAS_ext8u_i32
489 case INDEX_op_ext8u_i32
:
491 #ifdef TCG_TARGET_HAS_ext8u_i64
492 case INDEX_op_ext8u_i64
:
494 #ifdef TCG_TARGET_HAS_ext16u_i32
495 case INDEX_op_ext16u_i32
:
497 #ifdef TCG_TARGET_HAS_ext16u_i64
498 case INDEX_op_ext16u_i64
:
500 #if TCG_TARGET_REG_BITS == 64
501 case INDEX_op_ext32s_i64
:
502 case INDEX_op_ext32u_i64
:
504 if (temps
[args
[1]].state
== TCG_TEMP_CONST
) {
505 gen_opc_buf
[op_index
] = op_to_movi(op
);
506 tmp
= do_constant_folding(op
, temps
[args
[1]].val
, 0);
507 tcg_opt_gen_movi(gen_args
, args
[0], tmp
, nb_temps
, nb_globals
);
512 reset_temp(args
[0], nb_temps
, nb_globals
);
513 gen_args
[0] = args
[0];
514 gen_args
[1] = args
[1];
528 #ifdef TCG_TARGET_HAS_rot_i32
529 case INDEX_op_rotl_i32
:
530 case INDEX_op_rotr_i32
:
532 #ifdef TCG_TARGET_HAS_rot_i64
533 case INDEX_op_rotl_i64
:
534 case INDEX_op_rotr_i64
:
536 if (temps
[args
[1]].state
== TCG_TEMP_CONST
537 && temps
[args
[2]].state
== TCG_TEMP_CONST
) {
538 gen_opc_buf
[op_index
] = op_to_movi(op
);
539 tmp
= do_constant_folding(op
, temps
[args
[1]].val
,
541 tcg_opt_gen_movi(gen_args
, args
[0], tmp
, nb_temps
, nb_globals
);
546 reset_temp(args
[0], nb_temps
, nb_globals
);
547 gen_args
[0] = args
[0];
548 gen_args
[1] = args
[1];
549 gen_args
[2] = args
[2];
555 nb_call_args
= (args
[0] >> 16) + (args
[0] & 0xffff);
556 if (!(args
[nb_call_args
+ 1] & (TCG_CALL_CONST
| TCG_CALL_PURE
))) {
557 for (i
= 0; i
< nb_globals
; i
++) {
558 reset_temp(i
, nb_temps
, nb_globals
);
561 for (i
= 0; i
< (args
[0] >> 16); i
++) {
562 reset_temp(args
[i
+ 1], nb_temps
, nb_globals
);
564 i
= nb_call_args
+ 3;
572 case INDEX_op_set_label
:
575 CASE_OP_32_64(brcond
):
576 memset(temps
, 0, nb_temps
* sizeof(struct tcg_temp_info
));
577 for (i
= 0; i
< def
->nb_args
; i
++) {
584 /* Default case: we do know nothing about operation so no
585 propagation is done. We only trash output args. */
586 for (i
= 0; i
< def
->nb_oargs
; i
++) {
587 reset_temp(args
[i
], nb_temps
, nb_globals
);
589 for (i
= 0; i
< def
->nb_args
; i
++) {
590 gen_args
[i
] = args
[i
];
592 args
+= def
->nb_args
;
593 gen_args
+= def
->nb_args
;
601 TCGArg
*tcg_optimize(TCGContext
*s
, uint16_t *tcg_opc_ptr
,
602 TCGArg
*args
, TCGOpDef
*tcg_op_defs
)
605 res
= tcg_constant_folding(s
, tcg_opc_ptr
, args
, tcg_op_defs
);