]>
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(int 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
:
111 #if TCG_TARGET_REG_BITS == 64
112 case INDEX_op_mov_i64
:
113 case INDEX_op_add_i64
:
114 case INDEX_op_sub_i64
:
115 case INDEX_op_mul_i64
:
116 case INDEX_op_and_i64
:
117 case INDEX_op_or_i64
:
118 case INDEX_op_xor_i64
:
119 case INDEX_op_shl_i64
:
120 case INDEX_op_shr_i64
:
121 case INDEX_op_sar_i64
:
122 case INDEX_op_rotl_i64
:
123 case INDEX_op_rotr_i64
:
127 fprintf(stderr
, "Unrecognized operation %d in op_bits.\n", op
);
132 static int op_to_movi(int op
)
134 switch (op_bits(op
)) {
136 return INDEX_op_movi_i32
;
137 #if TCG_TARGET_REG_BITS == 64
139 return INDEX_op_movi_i64
;
142 fprintf(stderr
, "op_to_movi: unexpected return value of "
143 "function op_bits.\n");
148 static void tcg_opt_gen_mov(TCGArg
*gen_args
, TCGArg dst
, TCGArg src
,
149 int nb_temps
, int nb_globals
)
151 reset_temp(dst
, nb_temps
, nb_globals
);
152 assert(temps
[src
].state
!= TCG_TEMP_COPY
);
153 if (src
>= nb_globals
) {
154 assert(temps
[src
].state
!= TCG_TEMP_CONST
);
155 if (temps
[src
].state
!= TCG_TEMP_HAS_COPY
) {
156 temps
[src
].state
= TCG_TEMP_HAS_COPY
;
157 temps
[src
].next_copy
= src
;
158 temps
[src
].prev_copy
= src
;
160 temps
[dst
].state
= TCG_TEMP_COPY
;
161 temps
[dst
].val
= src
;
162 temps
[dst
].next_copy
= temps
[src
].next_copy
;
163 temps
[dst
].prev_copy
= src
;
164 temps
[temps
[dst
].next_copy
].prev_copy
= dst
;
165 temps
[src
].next_copy
= dst
;
171 static void tcg_opt_gen_movi(TCGArg
*gen_args
, TCGArg dst
, TCGArg val
,
172 int nb_temps
, int nb_globals
)
174 reset_temp(dst
, nb_temps
, nb_globals
);
175 temps
[dst
].state
= TCG_TEMP_CONST
;
176 temps
[dst
].val
= val
;
181 static int op_to_mov(int op
)
183 switch (op_bits(op
)) {
185 return INDEX_op_mov_i32
;
186 #if TCG_TARGET_REG_BITS == 64
188 return INDEX_op_mov_i64
;
191 fprintf(stderr
, "op_to_mov: unexpected return value of "
192 "function op_bits.\n");
197 static TCGArg
do_constant_folding_2(int op
, TCGArg x
, TCGArg y
)
218 case INDEX_op_shl_i32
:
219 return (uint32_t)x
<< (uint32_t)y
;
221 #if TCG_TARGET_REG_BITS == 64
222 case INDEX_op_shl_i64
:
223 return (uint64_t)x
<< (uint64_t)y
;
226 case INDEX_op_shr_i32
:
227 return (uint32_t)x
>> (uint32_t)y
;
229 #if TCG_TARGET_REG_BITS == 64
230 case INDEX_op_shr_i64
:
231 return (uint64_t)x
>> (uint64_t)y
;
234 case INDEX_op_sar_i32
:
235 return (int32_t)x
>> (int32_t)y
;
237 #if TCG_TARGET_REG_BITS == 64
238 case INDEX_op_sar_i64
:
239 return (int64_t)x
>> (int64_t)y
;
242 case INDEX_op_rotr_i32
:
243 #if TCG_TARGET_REG_BITS == 64
247 x
= (x
<< (32 - y
)) | (x
>> y
);
250 #if TCG_TARGET_REG_BITS == 64
251 case INDEX_op_rotr_i64
:
252 x
= (x
<< (64 - y
)) | (x
>> y
);
256 case INDEX_op_rotl_i32
:
257 #if TCG_TARGET_REG_BITS == 64
261 x
= (x
<< y
) | (x
>> (32 - y
));
264 #if TCG_TARGET_REG_BITS == 64
265 case INDEX_op_rotl_i64
:
266 x
= (x
<< y
) | (x
>> (64 - y
));
272 "Unrecognized operation %d in do_constant_folding.\n", op
);
277 static TCGArg
do_constant_folding(int op
, TCGArg x
, TCGArg y
)
279 TCGArg res
= do_constant_folding_2(op
, x
, y
);
280 #if TCG_TARGET_REG_BITS == 64
281 if (op_bits(op
) == 32) {
288 /* Propagate constants and copies, fold constant expressions. */
289 static TCGArg
*tcg_constant_folding(TCGContext
*s
, uint16_t *tcg_opc_ptr
,
290 TCGArg
*args
, TCGOpDef
*tcg_op_defs
)
292 int i
, nb_ops
, op_index
, op
, nb_temps
, nb_globals
, nb_call_args
;
296 /* Array VALS has an element for each temp.
297 If this temp holds a constant then its value is kept in VALS' element.
298 If this temp is a copy of other ones then this equivalence class'
299 representative is kept in VALS' element.
300 If this temp is neither copy nor constant then corresponding VALS'
301 element is unused. */
303 nb_temps
= s
->nb_temps
;
304 nb_globals
= s
->nb_globals
;
305 memset(temps
, 0, nb_temps
* sizeof(struct tcg_temp_info
));
307 nb_ops
= tcg_opc_ptr
- gen_opc_buf
;
309 for (op_index
= 0; op_index
< nb_ops
; op_index
++) {
310 op
= gen_opc_buf
[op_index
];
311 def
= &tcg_op_defs
[op
];
312 /* Do copy propagation */
313 if (!(def
->flags
& (TCG_OPF_CALL_CLOBBER
| TCG_OPF_SIDE_EFFECTS
))) {
314 assert(op
!= INDEX_op_call
);
315 for (i
= def
->nb_oargs
; i
< def
->nb_oargs
+ def
->nb_iargs
; i
++) {
316 if (temps
[args
[i
]].state
== TCG_TEMP_COPY
) {
317 args
[i
] = temps
[args
[i
]].val
;
322 /* For commutative operations make constant second argument */
329 if (temps
[args
[1]].state
== TCG_TEMP_CONST
) {
339 /* Simplify expression if possible. */
348 if (temps
[args
[1]].state
== TCG_TEMP_CONST
) {
349 /* Proceed with possible constant folding. */
352 if (temps
[args
[2]].state
== TCG_TEMP_CONST
353 && temps
[args
[2]].val
== 0) {
354 if ((temps
[args
[0]].state
== TCG_TEMP_COPY
355 && temps
[args
[0]].val
== args
[1])
356 || args
[0] == args
[1]) {
358 gen_opc_buf
[op_index
] = INDEX_op_nop
;
360 gen_opc_buf
[op_index
] = op_to_mov(op
);
361 tcg_opt_gen_mov(gen_args
, args
[0], args
[1],
362 nb_temps
, nb_globals
);
370 if ((temps
[args
[2]].state
== TCG_TEMP_CONST
371 && temps
[args
[2]].val
== 0)) {
372 gen_opc_buf
[op_index
] = op_to_movi(op
);
373 tcg_opt_gen_movi(gen_args
, args
[0], 0, nb_temps
, nb_globals
);
381 if (args
[1] == args
[2]) {
382 if (args
[1] == args
[0]) {
384 gen_opc_buf
[op_index
] = INDEX_op_nop
;
386 gen_opc_buf
[op_index
] = op_to_mov(op
);
387 tcg_opt_gen_mov(gen_args
, args
[0], args
[1], nb_temps
,
397 /* Propagate constants through copy operations and do constant
398 folding. Constants will be substituted to arguments by register
399 allocator where needed and possible. Also detect copies. */
402 if ((temps
[args
[1]].state
== TCG_TEMP_COPY
403 && temps
[args
[1]].val
== args
[0])
404 || args
[0] == args
[1]) {
406 gen_opc_buf
[op_index
] = INDEX_op_nop
;
409 if (temps
[args
[1]].state
!= TCG_TEMP_CONST
) {
410 tcg_opt_gen_mov(gen_args
, args
[0], args
[1],
411 nb_temps
, nb_globals
);
416 /* Source argument is constant. Rewrite the operation and
417 let movi case handle it. */
419 gen_opc_buf
[op_index
] = op
;
420 args
[1] = temps
[args
[1]].val
;
423 tcg_opt_gen_movi(gen_args
, args
[0], args
[1], nb_temps
, nb_globals
);
438 if (temps
[args
[1]].state
== TCG_TEMP_CONST
439 && temps
[args
[2]].state
== TCG_TEMP_CONST
) {
440 gen_opc_buf
[op_index
] = op_to_movi(op
);
441 tmp
= do_constant_folding(op
, temps
[args
[1]].val
,
443 tcg_opt_gen_movi(gen_args
, args
[0], tmp
, nb_temps
, nb_globals
);
448 reset_temp(args
[0], nb_temps
, nb_globals
);
449 gen_args
[0] = args
[0];
450 gen_args
[1] = args
[1];
451 gen_args
[2] = args
[2];
457 nb_call_args
= (args
[0] >> 16) + (args
[0] & 0xffff);
458 if (!(args
[nb_call_args
+ 1] & (TCG_CALL_CONST
| TCG_CALL_PURE
))) {
459 for (i
= 0; i
< nb_globals
; i
++) {
460 reset_temp(i
, nb_temps
, nb_globals
);
463 for (i
= 0; i
< (args
[0] >> 16); i
++) {
464 reset_temp(args
[i
+ 1], nb_temps
, nb_globals
);
466 i
= nb_call_args
+ 3;
474 case INDEX_op_set_label
:
477 CASE_OP_32_64(brcond
):
478 memset(temps
, 0, nb_temps
* sizeof(struct tcg_temp_info
));
479 for (i
= 0; i
< def
->nb_args
; i
++) {
486 /* Default case: we do know nothing about operation so no
487 propagation is done. We only trash output args. */
488 for (i
= 0; i
< def
->nb_oargs
; i
++) {
489 reset_temp(args
[i
], nb_temps
, nb_globals
);
491 for (i
= 0; i
< def
->nb_args
; i
++) {
492 gen_args
[i
] = args
[i
];
494 args
+= def
->nb_args
;
495 gen_args
+= def
->nb_args
;
503 TCGArg
*tcg_optimize(TCGContext
*s
, uint16_t *tcg_opc_ptr
,
504 TCGArg
*args
, TCGOpDef
*tcg_op_defs
)
507 res
= tcg_constant_folding(s
, tcg_opc_ptr
, args
, tcg_op_defs
);