blob: 42a1bda66600916cfaf45381fca5d74f4b6a88b4 [file] [log] [blame]
Kirill Batuzov8f2e8c02011-07-07 16:37:12 +04001/*
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
Kirill Batuzov22613af2011-07-07 16:37:13 +040043typedef 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:
Kirill Batuzov53108fb2011-07-07 16:37:14 +040099 case INDEX_op_add_i32:
100 case INDEX_op_sub_i32:
101 case INDEX_op_mul_i32:
Kirill Batuzov22613af2011-07-07 16:37:13 +0400102 return 32;
103#if TCG_TARGET_REG_BITS == 64
104 case INDEX_op_mov_i64:
Kirill Batuzov53108fb2011-07-07 16:37:14 +0400105 case INDEX_op_add_i64:
106 case INDEX_op_sub_i64:
107 case INDEX_op_mul_i64:
Kirill Batuzov22613af2011-07-07 16:37:13 +0400108 return 64;
109#endif
110 default:
111 fprintf(stderr, "Unrecognized operation %d in op_bits.\n", op);
112 tcg_abort();
113 }
114}
115
116static int op_to_movi(int op)
117{
118 switch (op_bits(op)) {
119 case 32:
120 return INDEX_op_movi_i32;
121#if TCG_TARGET_REG_BITS == 64
122 case 64:
123 return INDEX_op_movi_i64;
124#endif
125 default:
126 fprintf(stderr, "op_to_movi: unexpected return value of "
127 "function op_bits.\n");
128 tcg_abort();
129 }
130}
131
132static void tcg_opt_gen_mov(TCGArg *gen_args, TCGArg dst, TCGArg src,
133 int nb_temps, int nb_globals)
134{
135 reset_temp(dst, nb_temps, nb_globals);
136 assert(temps[src].state != TCG_TEMP_COPY);
137 if (src >= nb_globals) {
138 assert(temps[src].state != TCG_TEMP_CONST);
139 if (temps[src].state != TCG_TEMP_HAS_COPY) {
140 temps[src].state = TCG_TEMP_HAS_COPY;
141 temps[src].next_copy = src;
142 temps[src].prev_copy = src;
143 }
144 temps[dst].state = TCG_TEMP_COPY;
145 temps[dst].val = src;
146 temps[dst].next_copy = temps[src].next_copy;
147 temps[dst].prev_copy = src;
148 temps[temps[dst].next_copy].prev_copy = dst;
149 temps[src].next_copy = dst;
150 }
151 gen_args[0] = dst;
152 gen_args[1] = src;
153}
154
155static void tcg_opt_gen_movi(TCGArg *gen_args, TCGArg dst, TCGArg val,
156 int nb_temps, int nb_globals)
157{
158 reset_temp(dst, nb_temps, nb_globals);
159 temps[dst].state = TCG_TEMP_CONST;
160 temps[dst].val = val;
161 gen_args[0] = dst;
162 gen_args[1] = val;
163}
164
Kirill Batuzov53108fb2011-07-07 16:37:14 +0400165static int op_to_mov(int op)
166{
167 switch (op_bits(op)) {
168 case 32:
169 return INDEX_op_mov_i32;
170#if TCG_TARGET_REG_BITS == 64
171 case 64:
172 return INDEX_op_mov_i64;
173#endif
174 default:
175 fprintf(stderr, "op_to_mov: unexpected return value of "
176 "function op_bits.\n");
177 tcg_abort();
178 }
179}
180
181static TCGArg do_constant_folding_2(int op, TCGArg x, TCGArg y)
182{
183 switch (op) {
184 CASE_OP_32_64(add):
185 return x + y;
186
187 CASE_OP_32_64(sub):
188 return x - y;
189
190 CASE_OP_32_64(mul):
191 return x * y;
192
193 default:
194 fprintf(stderr,
195 "Unrecognized operation %d in do_constant_folding.\n", op);
196 tcg_abort();
197 }
198}
199
200static TCGArg do_constant_folding(int op, TCGArg x, TCGArg y)
201{
202 TCGArg res = do_constant_folding_2(op, x, y);
203#if TCG_TARGET_REG_BITS == 64
204 if (op_bits(op) == 32) {
205 res &= 0xffffffff;
206 }
207#endif
208 return res;
209}
210
Kirill Batuzov22613af2011-07-07 16:37:13 +0400211/* Propagate constants and copies, fold constant expressions. */
Kirill Batuzov8f2e8c02011-07-07 16:37:12 +0400212static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
213 TCGArg *args, TCGOpDef *tcg_op_defs)
214{
Kirill Batuzov22613af2011-07-07 16:37:13 +0400215 int i, nb_ops, op_index, op, nb_temps, nb_globals, nb_call_args;
Kirill Batuzov8f2e8c02011-07-07 16:37:12 +0400216 const TCGOpDef *def;
217 TCGArg *gen_args;
Kirill Batuzov53108fb2011-07-07 16:37:14 +0400218 TCGArg tmp;
Kirill Batuzov22613af2011-07-07 16:37:13 +0400219 /* Array VALS has an element for each temp.
220 If this temp holds a constant then its value is kept in VALS' element.
221 If this temp is a copy of other ones then this equivalence class'
222 representative is kept in VALS' element.
223 If this temp is neither copy nor constant then corresponding VALS'
224 element is unused. */
Kirill Batuzov8f2e8c02011-07-07 16:37:12 +0400225
226 nb_temps = s->nb_temps;
227 nb_globals = s->nb_globals;
Kirill Batuzov22613af2011-07-07 16:37:13 +0400228 memset(temps, 0, nb_temps * sizeof(struct tcg_temp_info));
Kirill Batuzov8f2e8c02011-07-07 16:37:12 +0400229
230 nb_ops = tcg_opc_ptr - gen_opc_buf;
231 gen_args = args;
232 for (op_index = 0; op_index < nb_ops; op_index++) {
233 op = gen_opc_buf[op_index];
234 def = &tcg_op_defs[op];
Kirill Batuzov22613af2011-07-07 16:37:13 +0400235 /* Do copy propagation */
236 if (!(def->flags & (TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS))) {
237 assert(op != INDEX_op_call);
238 for (i = def->nb_oargs; i < def->nb_oargs + def->nb_iargs; i++) {
239 if (temps[args[i]].state == TCG_TEMP_COPY) {
240 args[i] = temps[args[i]].val;
241 }
242 }
243 }
244
Kirill Batuzov53108fb2011-07-07 16:37:14 +0400245 /* For commutative operations make constant second argument */
246 switch (op) {
247 CASE_OP_32_64(add):
248 CASE_OP_32_64(mul):
249 if (temps[args[1]].state == TCG_TEMP_CONST) {
250 tmp = args[1];
251 args[1] = args[2];
252 args[2] = tmp;
253 }
254 break;
255 default:
256 break;
257 }
258
259 /* Simplify expression if possible. */
260 switch (op) {
261 CASE_OP_32_64(add):
262 CASE_OP_32_64(sub):
263 if (temps[args[1]].state == TCG_TEMP_CONST) {
264 /* Proceed with possible constant folding. */
265 break;
266 }
267 if (temps[args[2]].state == TCG_TEMP_CONST
268 && temps[args[2]].val == 0) {
269 if ((temps[args[0]].state == TCG_TEMP_COPY
270 && temps[args[0]].val == args[1])
271 || args[0] == args[1]) {
272 args += 3;
273 gen_opc_buf[op_index] = INDEX_op_nop;
274 } else {
275 gen_opc_buf[op_index] = op_to_mov(op);
276 tcg_opt_gen_mov(gen_args, args[0], args[1],
277 nb_temps, nb_globals);
278 gen_args += 2;
279 args += 3;
280 }
281 continue;
282 }
283 break;
284 CASE_OP_32_64(mul):
285 if ((temps[args[2]].state == TCG_TEMP_CONST
286 && temps[args[2]].val == 0)) {
287 gen_opc_buf[op_index] = op_to_movi(op);
288 tcg_opt_gen_movi(gen_args, args[0], 0, nb_temps, nb_globals);
289 args += 3;
290 gen_args += 2;
291 continue;
292 }
293 break;
294 }
295
Kirill Batuzov22613af2011-07-07 16:37:13 +0400296 /* Propagate constants through copy operations and do constant
297 folding. Constants will be substituted to arguments by register
298 allocator where needed and possible. Also detect copies. */
Kirill Batuzov8f2e8c02011-07-07 16:37:12 +0400299 switch (op) {
Kirill Batuzov22613af2011-07-07 16:37:13 +0400300 CASE_OP_32_64(mov):
301 if ((temps[args[1]].state == TCG_TEMP_COPY
302 && temps[args[1]].val == args[0])
303 || args[0] == args[1]) {
304 args += 2;
305 gen_opc_buf[op_index] = INDEX_op_nop;
306 break;
307 }
308 if (temps[args[1]].state != TCG_TEMP_CONST) {
309 tcg_opt_gen_mov(gen_args, args[0], args[1],
310 nb_temps, nb_globals);
311 gen_args += 2;
312 args += 2;
313 break;
314 }
315 /* Source argument is constant. Rewrite the operation and
316 let movi case handle it. */
317 op = op_to_movi(op);
318 gen_opc_buf[op_index] = op;
319 args[1] = temps[args[1]].val;
320 /* fallthrough */
321 CASE_OP_32_64(movi):
322 tcg_opt_gen_movi(gen_args, args[0], args[1], nb_temps, nb_globals);
323 gen_args += 2;
324 args += 2;
325 break;
Kirill Batuzov53108fb2011-07-07 16:37:14 +0400326 CASE_OP_32_64(add):
327 CASE_OP_32_64(sub):
328 CASE_OP_32_64(mul):
329 if (temps[args[1]].state == TCG_TEMP_CONST
330 && temps[args[2]].state == TCG_TEMP_CONST) {
331 gen_opc_buf[op_index] = op_to_movi(op);
332 tmp = do_constant_folding(op, temps[args[1]].val,
333 temps[args[2]].val);
334 tcg_opt_gen_movi(gen_args, args[0], tmp, nb_temps, nb_globals);
335 gen_args += 2;
336 args += 3;
337 break;
338 } else {
339 reset_temp(args[0], nb_temps, nb_globals);
340 gen_args[0] = args[0];
341 gen_args[1] = args[1];
342 gen_args[2] = args[2];
343 gen_args += 3;
344 args += 3;
345 break;
346 }
Kirill Batuzov8f2e8c02011-07-07 16:37:12 +0400347 case INDEX_op_call:
Kirill Batuzov22613af2011-07-07 16:37:13 +0400348 nb_call_args = (args[0] >> 16) + (args[0] & 0xffff);
349 if (!(args[nb_call_args + 1] & (TCG_CALL_CONST | TCG_CALL_PURE))) {
350 for (i = 0; i < nb_globals; i++) {
351 reset_temp(i, nb_temps, nb_globals);
352 }
353 }
354 for (i = 0; i < (args[0] >> 16); i++) {
355 reset_temp(args[i + 1], nb_temps, nb_globals);
356 }
357 i = nb_call_args + 3;
Kirill Batuzov8f2e8c02011-07-07 16:37:12 +0400358 while (i) {
359 *gen_args = *args;
360 args++;
361 gen_args++;
362 i--;
363 }
364 break;
365 case INDEX_op_set_label:
366 case INDEX_op_jmp:
367 case INDEX_op_br:
368 CASE_OP_32_64(brcond):
Kirill Batuzov22613af2011-07-07 16:37:13 +0400369 memset(temps, 0, nb_temps * sizeof(struct tcg_temp_info));
Kirill Batuzov8f2e8c02011-07-07 16:37:12 +0400370 for (i = 0; i < def->nb_args; i++) {
371 *gen_args = *args;
372 args++;
373 gen_args++;
374 }
375 break;
376 default:
Kirill Batuzov22613af2011-07-07 16:37:13 +0400377 /* Default case: we do know nothing about operation so no
378 propagation is done. We only trash output args. */
379 for (i = 0; i < def->nb_oargs; i++) {
380 reset_temp(args[i], nb_temps, nb_globals);
381 }
Kirill Batuzov8f2e8c02011-07-07 16:37:12 +0400382 for (i = 0; i < def->nb_args; i++) {
383 gen_args[i] = args[i];
384 }
385 args += def->nb_args;
386 gen_args += def->nb_args;
387 break;
388 }
389 }
390
391 return gen_args;
392}
393
394TCGArg *tcg_optimize(TCGContext *s, uint16_t *tcg_opc_ptr,
395 TCGArg *args, TCGOpDef *tcg_op_defs)
396{
397 TCGArg *res;
398 res = tcg_constant_folding(s, tcg_opc_ptr, args, tcg_op_defs);
399 return res;
400}