]> git.proxmox.com Git - qemu.git/blame - tcg/optimize.c
Do constant folding for boolean operations.
[qemu.git] / tcg / optimize.c
CommitLineData
8f2e8c07
KB
1/*
2 * Optimizations for Tiny Code Generator for QEMU
3 *
4 * Copyright (c) 2010 Samsung Electronics.
5 * Contributed by Kirill Batuzov <batuzovk@ispras.ru>
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
22613af4
KB
43typedef 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
51struct 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
58static 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. */
63static 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
95static int op_bits(int op)
96{
97 switch (op) {
98 case INDEX_op_mov_i32:
53108fb5
KB
99 case INDEX_op_add_i32:
100 case INDEX_op_sub_i32:
101 case INDEX_op_mul_i32:
9a81090b
KB
102 case INDEX_op_and_i32:
103 case INDEX_op_or_i32:
104 case INDEX_op_xor_i32:
22613af4
KB
105 return 32;
106#if TCG_TARGET_REG_BITS == 64
107 case INDEX_op_mov_i64:
53108fb5
KB
108 case INDEX_op_add_i64:
109 case INDEX_op_sub_i64:
110 case INDEX_op_mul_i64:
9a81090b
KB
111 case INDEX_op_and_i64:
112 case INDEX_op_or_i64:
113 case INDEX_op_xor_i64:
22613af4
KB
114 return 64;
115#endif
116 default:
117 fprintf(stderr, "Unrecognized operation %d in op_bits.\n", op);
118 tcg_abort();
119 }
120}
121
122static int op_to_movi(int op)
123{
124 switch (op_bits(op)) {
125 case 32:
126 return INDEX_op_movi_i32;
127#if TCG_TARGET_REG_BITS == 64
128 case 64:
129 return INDEX_op_movi_i64;
130#endif
131 default:
132 fprintf(stderr, "op_to_movi: unexpected return value of "
133 "function op_bits.\n");
134 tcg_abort();
135 }
136}
137
138static void tcg_opt_gen_mov(TCGArg *gen_args, TCGArg dst, TCGArg src,
139 int nb_temps, int nb_globals)
140{
141 reset_temp(dst, nb_temps, nb_globals);
142 assert(temps[src].state != TCG_TEMP_COPY);
143 if (src >= nb_globals) {
144 assert(temps[src].state != TCG_TEMP_CONST);
145 if (temps[src].state != TCG_TEMP_HAS_COPY) {
146 temps[src].state = TCG_TEMP_HAS_COPY;
147 temps[src].next_copy = src;
148 temps[src].prev_copy = src;
149 }
150 temps[dst].state = TCG_TEMP_COPY;
151 temps[dst].val = src;
152 temps[dst].next_copy = temps[src].next_copy;
153 temps[dst].prev_copy = src;
154 temps[temps[dst].next_copy].prev_copy = dst;
155 temps[src].next_copy = dst;
156 }
157 gen_args[0] = dst;
158 gen_args[1] = src;
159}
160
161static void tcg_opt_gen_movi(TCGArg *gen_args, TCGArg dst, TCGArg val,
162 int nb_temps, int nb_globals)
163{
164 reset_temp(dst, nb_temps, nb_globals);
165 temps[dst].state = TCG_TEMP_CONST;
166 temps[dst].val = val;
167 gen_args[0] = dst;
168 gen_args[1] = val;
169}
170
53108fb5
KB
171static int op_to_mov(int op)
172{
173 switch (op_bits(op)) {
174 case 32:
175 return INDEX_op_mov_i32;
176#if TCG_TARGET_REG_BITS == 64
177 case 64:
178 return INDEX_op_mov_i64;
179#endif
180 default:
181 fprintf(stderr, "op_to_mov: unexpected return value of "
182 "function op_bits.\n");
183 tcg_abort();
184 }
185}
186
187static TCGArg do_constant_folding_2(int op, TCGArg x, TCGArg y)
188{
189 switch (op) {
190 CASE_OP_32_64(add):
191 return x + y;
192
193 CASE_OP_32_64(sub):
194 return x - y;
195
196 CASE_OP_32_64(mul):
197 return x * y;
198
9a81090b
KB
199 CASE_OP_32_64(and):
200 return x & y;
201
202 CASE_OP_32_64(or):
203 return x | y;
204
205 CASE_OP_32_64(xor):
206 return x ^ y;
207
53108fb5
KB
208 default:
209 fprintf(stderr,
210 "Unrecognized operation %d in do_constant_folding.\n", op);
211 tcg_abort();
212 }
213}
214
215static TCGArg do_constant_folding(int op, TCGArg x, TCGArg y)
216{
217 TCGArg res = do_constant_folding_2(op, x, y);
218#if TCG_TARGET_REG_BITS == 64
219 if (op_bits(op) == 32) {
220 res &= 0xffffffff;
221 }
222#endif
223 return res;
224}
225
22613af4 226/* Propagate constants and copies, fold constant expressions. */
8f2e8c07
KB
227static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
228 TCGArg *args, TCGOpDef *tcg_op_defs)
229{
22613af4 230 int i, nb_ops, op_index, op, nb_temps, nb_globals, nb_call_args;
8f2e8c07
KB
231 const TCGOpDef *def;
232 TCGArg *gen_args;
53108fb5 233 TCGArg tmp;
22613af4
KB
234 /* Array VALS has an element for each temp.
235 If this temp holds a constant then its value is kept in VALS' element.
236 If this temp is a copy of other ones then this equivalence class'
237 representative is kept in VALS' element.
238 If this temp is neither copy nor constant then corresponding VALS'
239 element is unused. */
8f2e8c07
KB
240
241 nb_temps = s->nb_temps;
242 nb_globals = s->nb_globals;
22613af4 243 memset(temps, 0, nb_temps * sizeof(struct tcg_temp_info));
8f2e8c07
KB
244
245 nb_ops = tcg_opc_ptr - gen_opc_buf;
246 gen_args = args;
247 for (op_index = 0; op_index < nb_ops; op_index++) {
248 op = gen_opc_buf[op_index];
249 def = &tcg_op_defs[op];
22613af4
KB
250 /* Do copy propagation */
251 if (!(def->flags & (TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS))) {
252 assert(op != INDEX_op_call);
253 for (i = def->nb_oargs; i < def->nb_oargs + def->nb_iargs; i++) {
254 if (temps[args[i]].state == TCG_TEMP_COPY) {
255 args[i] = temps[args[i]].val;
256 }
257 }
258 }
259
53108fb5
KB
260 /* For commutative operations make constant second argument */
261 switch (op) {
262 CASE_OP_32_64(add):
263 CASE_OP_32_64(mul):
9a81090b
KB
264 CASE_OP_32_64(and):
265 CASE_OP_32_64(or):
266 CASE_OP_32_64(xor):
53108fb5
KB
267 if (temps[args[1]].state == TCG_TEMP_CONST) {
268 tmp = args[1];
269 args[1] = args[2];
270 args[2] = tmp;
271 }
272 break;
273 default:
274 break;
275 }
276
277 /* Simplify expression if possible. */
278 switch (op) {
279 CASE_OP_32_64(add):
280 CASE_OP_32_64(sub):
281 if (temps[args[1]].state == TCG_TEMP_CONST) {
282 /* Proceed with possible constant folding. */
283 break;
284 }
285 if (temps[args[2]].state == TCG_TEMP_CONST
286 && temps[args[2]].val == 0) {
287 if ((temps[args[0]].state == TCG_TEMP_COPY
288 && temps[args[0]].val == args[1])
289 || args[0] == args[1]) {
290 args += 3;
291 gen_opc_buf[op_index] = INDEX_op_nop;
292 } else {
293 gen_opc_buf[op_index] = op_to_mov(op);
294 tcg_opt_gen_mov(gen_args, args[0], args[1],
295 nb_temps, nb_globals);
296 gen_args += 2;
297 args += 3;
298 }
299 continue;
300 }
301 break;
302 CASE_OP_32_64(mul):
303 if ((temps[args[2]].state == TCG_TEMP_CONST
304 && temps[args[2]].val == 0)) {
305 gen_opc_buf[op_index] = op_to_movi(op);
306 tcg_opt_gen_movi(gen_args, args[0], 0, nb_temps, nb_globals);
307 args += 3;
308 gen_args += 2;
309 continue;
310 }
311 break;
9a81090b
KB
312 CASE_OP_32_64(or):
313 CASE_OP_32_64(and):
314 if (args[1] == args[2]) {
315 if (args[1] == args[0]) {
316 args += 3;
317 gen_opc_buf[op_index] = INDEX_op_nop;
318 } else {
319 gen_opc_buf[op_index] = op_to_mov(op);
320 tcg_opt_gen_mov(gen_args, args[0], args[1], nb_temps,
321 nb_globals);
322 gen_args += 2;
323 args += 3;
324 }
325 continue;
326 }
327 break;
53108fb5
KB
328 }
329
22613af4
KB
330 /* Propagate constants through copy operations and do constant
331 folding. Constants will be substituted to arguments by register
332 allocator where needed and possible. Also detect copies. */
8f2e8c07 333 switch (op) {
22613af4
KB
334 CASE_OP_32_64(mov):
335 if ((temps[args[1]].state == TCG_TEMP_COPY
336 && temps[args[1]].val == args[0])
337 || args[0] == args[1]) {
338 args += 2;
339 gen_opc_buf[op_index] = INDEX_op_nop;
340 break;
341 }
342 if (temps[args[1]].state != TCG_TEMP_CONST) {
343 tcg_opt_gen_mov(gen_args, args[0], args[1],
344 nb_temps, nb_globals);
345 gen_args += 2;
346 args += 2;
347 break;
348 }
349 /* Source argument is constant. Rewrite the operation and
350 let movi case handle it. */
351 op = op_to_movi(op);
352 gen_opc_buf[op_index] = op;
353 args[1] = temps[args[1]].val;
354 /* fallthrough */
355 CASE_OP_32_64(movi):
356 tcg_opt_gen_movi(gen_args, args[0], args[1], nb_temps, nb_globals);
357 gen_args += 2;
358 args += 2;
359 break;
53108fb5
KB
360 CASE_OP_32_64(add):
361 CASE_OP_32_64(sub):
362 CASE_OP_32_64(mul):
9a81090b
KB
363 CASE_OP_32_64(or):
364 CASE_OP_32_64(and):
365 CASE_OP_32_64(xor):
53108fb5
KB
366 if (temps[args[1]].state == TCG_TEMP_CONST
367 && temps[args[2]].state == TCG_TEMP_CONST) {
368 gen_opc_buf[op_index] = op_to_movi(op);
369 tmp = do_constant_folding(op, temps[args[1]].val,
370 temps[args[2]].val);
371 tcg_opt_gen_movi(gen_args, args[0], tmp, nb_temps, nb_globals);
372 gen_args += 2;
373 args += 3;
374 break;
375 } else {
376 reset_temp(args[0], nb_temps, nb_globals);
377 gen_args[0] = args[0];
378 gen_args[1] = args[1];
379 gen_args[2] = args[2];
380 gen_args += 3;
381 args += 3;
382 break;
383 }
8f2e8c07 384 case INDEX_op_call:
22613af4
KB
385 nb_call_args = (args[0] >> 16) + (args[0] & 0xffff);
386 if (!(args[nb_call_args + 1] & (TCG_CALL_CONST | TCG_CALL_PURE))) {
387 for (i = 0; i < nb_globals; i++) {
388 reset_temp(i, nb_temps, nb_globals);
389 }
390 }
391 for (i = 0; i < (args[0] >> 16); i++) {
392 reset_temp(args[i + 1], nb_temps, nb_globals);
393 }
394 i = nb_call_args + 3;
8f2e8c07
KB
395 while (i) {
396 *gen_args = *args;
397 args++;
398 gen_args++;
399 i--;
400 }
401 break;
402 case INDEX_op_set_label:
403 case INDEX_op_jmp:
404 case INDEX_op_br:
405 CASE_OP_32_64(brcond):
22613af4 406 memset(temps, 0, nb_temps * sizeof(struct tcg_temp_info));
8f2e8c07
KB
407 for (i = 0; i < def->nb_args; i++) {
408 *gen_args = *args;
409 args++;
410 gen_args++;
411 }
412 break;
413 default:
22613af4
KB
414 /* Default case: we do know nothing about operation so no
415 propagation is done. We only trash output args. */
416 for (i = 0; i < def->nb_oargs; i++) {
417 reset_temp(args[i], nb_temps, nb_globals);
418 }
8f2e8c07
KB
419 for (i = 0; i < def->nb_args; i++) {
420 gen_args[i] = args[i];
421 }
422 args += def->nb_args;
423 gen_args += def->nb_args;
424 break;
425 }
426 }
427
428 return gen_args;
429}
430
431TCGArg *tcg_optimize(TCGContext *s, uint16_t *tcg_opc_ptr,
432 TCGArg *args, TCGOpDef *tcg_op_defs)
433{
434 TCGArg *res;
435 res = tcg_constant_folding(s, tcg_opc_ptr, args, tcg_op_defs);
436 return res;
437}