2 * Optimizations for Tiny Code Generator for QEMU
4 * Copyright (c) 2010 Samsung Electronics.
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:
103 #if TCG_TARGET_REG_BITS == 64
104 case INDEX_op_mov_i64:
105 case INDEX_op_add_i64:
106 case INDEX_op_sub_i64:
107 case INDEX_op_mul_i64:
111 fprintf(stderr, "Unrecognized operation %d in op_bits.\n", op);
116 static int op_to_movi(int op)
118 switch (op_bits(op)) {
120 return INDEX_op_movi_i32;
121 #if TCG_TARGET_REG_BITS == 64
123 return INDEX_op_movi_i64;
126 fprintf(stderr, "op_to_movi: unexpected return value of "
127 "function op_bits.\n");
132 static void tcg_opt_gen_mov(TCGArg *gen_args, TCGArg dst, TCGArg src,
133 int nb_temps, int nb_globals)
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;
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;
155 static void tcg_opt_gen_movi(TCGArg *gen_args, TCGArg dst, TCGArg val,
156 int nb_temps, int nb_globals)
158 reset_temp(dst, nb_temps, nb_globals);
159 temps[dst].state = TCG_TEMP_CONST;
160 temps[dst].val = val;
165 static int op_to_mov(int op)
167 switch (op_bits(op)) {
169 return INDEX_op_mov_i32;
170 #if TCG_TARGET_REG_BITS == 64
172 return INDEX_op_mov_i64;
175 fprintf(stderr, "op_to_mov: unexpected return value of "
176 "function op_bits.\n");
181 static TCGArg do_constant_folding_2(int op, TCGArg x, TCGArg y)
195 "Unrecognized operation %d in do_constant_folding.\n", op);
200 static TCGArg do_constant_folding(int op, TCGArg x, TCGArg y)
202 TCGArg res = do_constant_folding_2(op, x, y);
203 #if TCG_TARGET_REG_BITS == 64
204 if (op_bits(op) == 32) {
211 /* Propagate constants and copies, fold constant expressions. */
212 static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
213 TCGArg *args, TCGOpDef *tcg_op_defs)
215 int i, nb_ops, op_index, op, nb_temps, nb_globals, nb_call_args;
219 /* 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. */
226 nb_temps = s->nb_temps;
227 nb_globals = s->nb_globals;
228 memset(temps, 0, nb_temps * sizeof(struct tcg_temp_info));
230 nb_ops = tcg_opc_ptr - gen_opc_buf;
232 for (op_index = 0; op_index < nb_ops; op_index++) {
233 op = gen_opc_buf[op_index];
234 def = &tcg_op_defs[op];
235 /* 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;
245 /* For commutative operations make constant second argument */
249 if (temps[args[1]].state == TCG_TEMP_CONST) {
259 /* Simplify expression if possible. */
263 if (temps[args[1]].state == TCG_TEMP_CONST) {
264 /* Proceed with possible constant folding. */
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]) {
273 gen_opc_buf[op_index] = INDEX_op_nop;
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);
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);
296 /* 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. */
301 if ((temps[args[1]].state == TCG_TEMP_COPY
302 && temps[args[1]].val == args[0])
303 || args[0] == args[1]) {
305 gen_opc_buf[op_index] = INDEX_op_nop;
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);
315 /* Source argument is constant. Rewrite the operation and
316 let movi case handle it. */
318 gen_opc_buf[op_index] = op;
319 args[1] = temps[args[1]].val;
322 tcg_opt_gen_movi(gen_args, args[0], args[1], nb_temps, nb_globals);
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,
334 tcg_opt_gen_movi(gen_args, args[0], tmp, nb_temps, nb_globals);
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];
348 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);
354 for (i = 0; i < (args[0] >> 16); i++) {
355 reset_temp(args[i + 1], nb_temps, nb_globals);
357 i = nb_call_args + 3;
365 case INDEX_op_set_label:
368 CASE_OP_32_64(brcond):
369 memset(temps, 0, nb_temps * sizeof(struct tcg_temp_info));
370 for (i = 0; i < def->nb_args; i++) {
377 /* 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);
382 for (i = 0; i < def->nb_args; i++) {
383 gen_args[i] = args[i];
385 args += def->nb_args;
386 gen_args += def->nb_args;
394 TCGArg *tcg_optimize(TCGContext *s, uint16_t *tcg_opc_ptr,
395 TCGArg *args, TCGOpDef *tcg_op_defs)
398 res = tcg_constant_folding(s, tcg_opc_ptr, args, tcg_op_defs);