]> git.proxmox.com Git - qemu.git/blame - tcg/optimize.c
Add copy and constant propagation.
[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:
99 return 32;
100#if TCG_TARGET_REG_BITS == 64
101 case INDEX_op_mov_i64:
102 return 64;
103#endif
104 default:
105 fprintf(stderr, "Unrecognized operation %d in op_bits.\n", op);
106 tcg_abort();
107 }
108}
109
110static int op_to_movi(int op)
111{
112 switch (op_bits(op)) {
113 case 32:
114 return INDEX_op_movi_i32;
115#if TCG_TARGET_REG_BITS == 64
116 case 64:
117 return INDEX_op_movi_i64;
118#endif
119 default:
120 fprintf(stderr, "op_to_movi: unexpected return value of "
121 "function op_bits.\n");
122 tcg_abort();
123 }
124}
125
126static void tcg_opt_gen_mov(TCGArg *gen_args, TCGArg dst, TCGArg src,
127 int nb_temps, int nb_globals)
128{
129 reset_temp(dst, nb_temps, nb_globals);
130 assert(temps[src].state != TCG_TEMP_COPY);
131 if (src >= nb_globals) {
132 assert(temps[src].state != TCG_TEMP_CONST);
133 if (temps[src].state != TCG_TEMP_HAS_COPY) {
134 temps[src].state = TCG_TEMP_HAS_COPY;
135 temps[src].next_copy = src;
136 temps[src].prev_copy = src;
137 }
138 temps[dst].state = TCG_TEMP_COPY;
139 temps[dst].val = src;
140 temps[dst].next_copy = temps[src].next_copy;
141 temps[dst].prev_copy = src;
142 temps[temps[dst].next_copy].prev_copy = dst;
143 temps[src].next_copy = dst;
144 }
145 gen_args[0] = dst;
146 gen_args[1] = src;
147}
148
149static void tcg_opt_gen_movi(TCGArg *gen_args, TCGArg dst, TCGArg val,
150 int nb_temps, int nb_globals)
151{
152 reset_temp(dst, nb_temps, nb_globals);
153 temps[dst].state = TCG_TEMP_CONST;
154 temps[dst].val = val;
155 gen_args[0] = dst;
156 gen_args[1] = val;
157}
158
159/* Propagate constants and copies, fold constant expressions. */
8f2e8c07
KB
160static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
161 TCGArg *args, TCGOpDef *tcg_op_defs)
162{
22613af4 163 int i, nb_ops, op_index, op, nb_temps, nb_globals, nb_call_args;
8f2e8c07
KB
164 const TCGOpDef *def;
165 TCGArg *gen_args;
22613af4
KB
166 /* Array VALS has an element for each temp.
167 If this temp holds a constant then its value is kept in VALS' element.
168 If this temp is a copy of other ones then this equivalence class'
169 representative is kept in VALS' element.
170 If this temp is neither copy nor constant then corresponding VALS'
171 element is unused. */
8f2e8c07
KB
172
173 nb_temps = s->nb_temps;
174 nb_globals = s->nb_globals;
22613af4 175 memset(temps, 0, nb_temps * sizeof(struct tcg_temp_info));
8f2e8c07
KB
176
177 nb_ops = tcg_opc_ptr - gen_opc_buf;
178 gen_args = args;
179 for (op_index = 0; op_index < nb_ops; op_index++) {
180 op = gen_opc_buf[op_index];
181 def = &tcg_op_defs[op];
22613af4
KB
182 /* Do copy propagation */
183 if (!(def->flags & (TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS))) {
184 assert(op != INDEX_op_call);
185 for (i = def->nb_oargs; i < def->nb_oargs + def->nb_iargs; i++) {
186 if (temps[args[i]].state == TCG_TEMP_COPY) {
187 args[i] = temps[args[i]].val;
188 }
189 }
190 }
191
192 /* Propagate constants through copy operations and do constant
193 folding. Constants will be substituted to arguments by register
194 allocator where needed and possible. Also detect copies. */
8f2e8c07 195 switch (op) {
22613af4
KB
196 CASE_OP_32_64(mov):
197 if ((temps[args[1]].state == TCG_TEMP_COPY
198 && temps[args[1]].val == args[0])
199 || args[0] == args[1]) {
200 args += 2;
201 gen_opc_buf[op_index] = INDEX_op_nop;
202 break;
203 }
204 if (temps[args[1]].state != TCG_TEMP_CONST) {
205 tcg_opt_gen_mov(gen_args, args[0], args[1],
206 nb_temps, nb_globals);
207 gen_args += 2;
208 args += 2;
209 break;
210 }
211 /* Source argument is constant. Rewrite the operation and
212 let movi case handle it. */
213 op = op_to_movi(op);
214 gen_opc_buf[op_index] = op;
215 args[1] = temps[args[1]].val;
216 /* fallthrough */
217 CASE_OP_32_64(movi):
218 tcg_opt_gen_movi(gen_args, args[0], args[1], nb_temps, nb_globals);
219 gen_args += 2;
220 args += 2;
221 break;
8f2e8c07 222 case INDEX_op_call:
22613af4
KB
223 nb_call_args = (args[0] >> 16) + (args[0] & 0xffff);
224 if (!(args[nb_call_args + 1] & (TCG_CALL_CONST | TCG_CALL_PURE))) {
225 for (i = 0; i < nb_globals; i++) {
226 reset_temp(i, nb_temps, nb_globals);
227 }
228 }
229 for (i = 0; i < (args[0] >> 16); i++) {
230 reset_temp(args[i + 1], nb_temps, nb_globals);
231 }
232 i = nb_call_args + 3;
8f2e8c07
KB
233 while (i) {
234 *gen_args = *args;
235 args++;
236 gen_args++;
237 i--;
238 }
239 break;
240 case INDEX_op_set_label:
241 case INDEX_op_jmp:
242 case INDEX_op_br:
243 CASE_OP_32_64(brcond):
22613af4 244 memset(temps, 0, nb_temps * sizeof(struct tcg_temp_info));
8f2e8c07
KB
245 for (i = 0; i < def->nb_args; i++) {
246 *gen_args = *args;
247 args++;
248 gen_args++;
249 }
250 break;
251 default:
22613af4
KB
252 /* Default case: we do know nothing about operation so no
253 propagation is done. We only trash output args. */
254 for (i = 0; i < def->nb_oargs; i++) {
255 reset_temp(args[i], nb_temps, nb_globals);
256 }
8f2e8c07
KB
257 for (i = 0; i < def->nb_args; i++) {
258 gen_args[i] = args[i];
259 }
260 args += def->nb_args;
261 gen_args += def->nb_args;
262 break;
263 }
264 }
265
266 return gen_args;
267}
268
269TCGArg *tcg_optimize(TCGContext *s, uint16_t *tcg_opc_ptr,
270 TCGArg *args, TCGOpDef *tcg_op_defs)
271{
272 TCGArg *res;
273 res = tcg_constant_folding(s, tcg_opc_ptr, args, tcg_op_defs);
274 return res;
275}