blob: 3c0e296f0dbf6764a96a70345764050771981950 [file] [log] [blame]
bellardc896fe22008-02-01 10:05:41 +00001/*
2 * Tiny Code Generator for QEMU
3 *
4 * Copyright (c) 2008 Fabrice Bellard
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24
bellardc896fe22008-02-01 10:05:41 +000025/* define it to use liveness analysis (better code) */
26#define USE_LIVENESS_ANALYSIS
27
aurel32cca82982009-04-16 09:58:30 +000028#include "config.h"
29
Juan Quintela092c73e2009-07-27 16:13:04 +020030#ifndef CONFIG_DEBUG_TCG
aurel32cca82982009-04-16 09:58:30 +000031/* define it to suppress various consistency checks (faster) */
32#define NDEBUG
33#endif
34
bellardc896fe22008-02-01 10:05:41 +000035#include <stdarg.h>
36#include <stdlib.h>
37#include <stdio.h>
38#include <string.h>
39#include <inttypes.h>
bellard3fe43da2008-02-04 22:03:16 +000040#ifdef _WIN32
41#include <malloc.h>
42#endif
malcb29fe3e2008-11-18 01:42:22 +000043#ifdef _AIX
44#include <alloca.h>
45#endif
bellardc896fe22008-02-01 10:05:41 +000046
aurel32ca10f862008-04-11 21:35:42 +000047#include "qemu-common.h"
malc902b3d52008-12-10 19:18:40 +000048#include "cache-utils.h"
Paul Brook379f6692009-07-17 12:48:08 +010049#include "host-utils.h"
bellardc896fe22008-02-01 10:05:41 +000050
51/* Note: the long term plan is to reduce the dependancies on the QEMU
52 CPU definitions. Currently they are used for qemu_ld/st
53 instructions */
54#define NO_CPU_IO_DEFS
55#include "cpu.h"
56#include "exec-all.h"
57
58#include "tcg-op.h"
59#include "elf.h"
60
Paul Brook379f6692009-07-17 12:48:08 +010061#if defined(CONFIG_USE_GUEST_BASE) && !defined(TCG_TARGET_HAS_GUEST_BASE)
62#error GUEST_BASE not supported on this host.
63#endif
bellardc896fe22008-02-01 10:05:41 +000064
65static void patch_reloc(uint8_t *code_ptr, int type,
aurel32f54b3f92008-04-12 20:14:54 +000066 tcg_target_long value, tcg_target_long addend);
bellardc896fe22008-02-01 10:05:41 +000067
blueswir12edd0892009-02-10 19:00:31 +000068static TCGOpDef tcg_op_defs[] = {
bellardc896fe22008-02-01 10:05:41 +000069#define DEF(s, n, copy_size) { #s, 0, 0, n, n, 0, copy_size },
Aurelien Jarno6692b042009-09-29 17:00:28 +020070#define DEF2(s, oargs, iargs, cargs, flags) { #s, oargs, iargs, cargs, iargs + oargs + cargs, flags, 0 },
bellardc896fe22008-02-01 10:05:41 +000071#include "tcg-opc.h"
72#undef DEF
73#undef DEF2
74};
75
blueswir1b1d8e522008-10-26 13:43:07 +000076static TCGRegSet tcg_target_available_regs[2];
77static TCGRegSet tcg_target_call_clobber_regs;
bellardc896fe22008-02-01 10:05:41 +000078
79/* XXX: move that inside the context */
80uint16_t *gen_opc_ptr;
81TCGArg *gen_opparam_ptr;
82
83static inline void tcg_out8(TCGContext *s, uint8_t v)
84{
85 *s->code_ptr++ = v;
86}
87
88static inline void tcg_out16(TCGContext *s, uint16_t v)
89{
90 *(uint16_t *)s->code_ptr = v;
91 s->code_ptr += 2;
92}
93
94static inline void tcg_out32(TCGContext *s, uint32_t v)
95{
96 *(uint32_t *)s->code_ptr = v;
97 s->code_ptr += 4;
98}
99
100/* label relocation processing */
101
102void tcg_out_reloc(TCGContext *s, uint8_t *code_ptr, int type,
103 int label_index, long addend)
104{
105 TCGLabel *l;
106 TCGRelocation *r;
107
108 l = &s->labels[label_index];
109 if (l->has_value) {
pbrook623e2652008-02-10 14:09:09 +0000110 /* FIXME: This may break relocations on RISC targets that
111 modify instruction fields in place. The caller may not have
112 written the initial value. */
aurel32f54b3f92008-04-12 20:14:54 +0000113 patch_reloc(code_ptr, type, l->u.value, addend);
bellardc896fe22008-02-01 10:05:41 +0000114 } else {
115 /* add a new relocation entry */
116 r = tcg_malloc(sizeof(TCGRelocation));
117 r->type = type;
118 r->ptr = code_ptr;
119 r->addend = addend;
120 r->next = l->u.first_reloc;
121 l->u.first_reloc = r;
122 }
123}
124
125static void tcg_out_label(TCGContext *s, int label_index,
126 tcg_target_long value)
127{
128 TCGLabel *l;
129 TCGRelocation *r;
130
131 l = &s->labels[label_index];
132 if (l->has_value)
133 tcg_abort();
134 r = l->u.first_reloc;
135 while (r != NULL) {
aurel32f54b3f92008-04-12 20:14:54 +0000136 patch_reloc(r->ptr, r->type, value, r->addend);
bellardc896fe22008-02-01 10:05:41 +0000137 r = r->next;
138 }
139 l->has_value = 1;
140 l->u.value = value;
141}
142
143int gen_new_label(void)
144{
145 TCGContext *s = &tcg_ctx;
146 int idx;
147 TCGLabel *l;
148
149 if (s->nb_labels >= TCG_MAX_LABELS)
150 tcg_abort();
151 idx = s->nb_labels++;
152 l = &s->labels[idx];
153 l->has_value = 0;
154 l->u.first_reloc = NULL;
155 return idx;
156}
157
158#include "tcg-target.c"
159
bellardc896fe22008-02-01 10:05:41 +0000160/* pool based memory allocation */
161void *tcg_malloc_internal(TCGContext *s, int size)
162{
163 TCGPool *p;
164 int pool_size;
165
166 if (size > TCG_POOL_CHUNK_SIZE) {
167 /* big malloc: insert a new pool (XXX: could optimize) */
168 p = qemu_malloc(sizeof(TCGPool) + size);
169 p->size = size;
170 if (s->pool_current)
171 s->pool_current->next = p;
172 else
173 s->pool_first = p;
174 p->next = s->pool_current;
175 } else {
176 p = s->pool_current;
177 if (!p) {
178 p = s->pool_first;
179 if (!p)
180 goto new_pool;
181 } else {
182 if (!p->next) {
183 new_pool:
184 pool_size = TCG_POOL_CHUNK_SIZE;
185 p = qemu_malloc(sizeof(TCGPool) + pool_size);
186 p->size = pool_size;
187 p->next = NULL;
188 if (s->pool_current)
189 s->pool_current->next = p;
190 else
191 s->pool_first = p;
192 } else {
193 p = p->next;
194 }
195 }
196 }
197 s->pool_current = p;
198 s->pool_cur = p->data + size;
199 s->pool_end = p->data + p->size;
200 return p->data;
201}
202
203void tcg_pool_reset(TCGContext *s)
204{
205 s->pool_cur = s->pool_end = NULL;
206 s->pool_current = NULL;
207}
208
bellardc896fe22008-02-01 10:05:41 +0000209void tcg_context_init(TCGContext *s)
210{
211 int op, total_args, n;
212 TCGOpDef *def;
213 TCGArgConstraint *args_ct;
214 int *sorted_args;
215
216 memset(s, 0, sizeof(*s));
217 s->temps = s->static_temps;
218 s->nb_globals = 0;
219
220 /* Count total number of arguments and allocate the corresponding
221 space */
222 total_args = 0;
223 for(op = 0; op < NB_OPS; op++) {
224 def = &tcg_op_defs[op];
225 n = def->nb_iargs + def->nb_oargs;
226 total_args += n;
227 }
228
229 args_ct = qemu_malloc(sizeof(TCGArgConstraint) * total_args);
230 sorted_args = qemu_malloc(sizeof(int) * total_args);
231
232 for(op = 0; op < NB_OPS; op++) {
233 def = &tcg_op_defs[op];
234 def->args_ct = args_ct;
235 def->sorted_args = sorted_args;
236 n = def->nb_iargs + def->nb_oargs;
237 sorted_args += n;
238 args_ct += n;
239 }
240
241 tcg_target_init(s);
bellardb03cce82008-05-10 10:52:05 +0000242
243 /* init global prologue and epilogue */
244 s->code_buf = code_gen_prologue;
245 s->code_ptr = s->code_buf;
246 tcg_target_qemu_prologue(s);
247 flush_icache_range((unsigned long)s->code_buf,
248 (unsigned long)s->code_ptr);
bellardc896fe22008-02-01 10:05:41 +0000249}
250
251void tcg_set_frame(TCGContext *s, int reg,
252 tcg_target_long start, tcg_target_long size)
253{
254 s->frame_start = start;
255 s->frame_end = start + size;
256 s->frame_reg = reg;
257}
258
bellardc896fe22008-02-01 10:05:41 +0000259void tcg_func_start(TCGContext *s)
260{
bellarde8996ee2008-05-23 17:33:39 +0000261 int i;
bellardc896fe22008-02-01 10:05:41 +0000262 tcg_pool_reset(s);
263 s->nb_temps = s->nb_globals;
bellard641d5fb2008-05-25 17:24:00 +0000264 for(i = 0; i < (TCG_TYPE_COUNT * 2); i++)
bellarde8996ee2008-05-23 17:33:39 +0000265 s->first_free_temp[i] = -1;
bellardc896fe22008-02-01 10:05:41 +0000266 s->labels = tcg_malloc(sizeof(TCGLabel) * TCG_MAX_LABELS);
267 s->nb_labels = 0;
268 s->current_frame_offset = s->frame_start;
269
270 gen_opc_ptr = gen_opc_buf;
271 gen_opparam_ptr = gen_opparam_buf;
272}
273
274static inline void tcg_temp_alloc(TCGContext *s, int n)
275{
276 if (n > TCG_MAX_TEMPS)
277 tcg_abort();
278}
279
pbrooka7812ae2008-11-17 14:43:54 +0000280static inline int tcg_global_reg_new_internal(TCGType type, int reg,
281 const char *name)
bellardc896fe22008-02-01 10:05:41 +0000282{
283 TCGContext *s = &tcg_ctx;
284 TCGTemp *ts;
285 int idx;
286
287#if TCG_TARGET_REG_BITS == 32
288 if (type != TCG_TYPE_I32)
289 tcg_abort();
290#endif
291 if (tcg_regset_test_reg(s->reserved_regs, reg))
292 tcg_abort();
293 idx = s->nb_globals;
294 tcg_temp_alloc(s, s->nb_globals + 1);
295 ts = &s->temps[s->nb_globals];
296 ts->base_type = type;
297 ts->type = type;
298 ts->fixed_reg = 1;
299 ts->reg = reg;
bellardc896fe22008-02-01 10:05:41 +0000300 ts->name = name;
301 s->nb_globals++;
302 tcg_regset_set_reg(s->reserved_regs, reg);
pbrooka7812ae2008-11-17 14:43:54 +0000303 return idx;
304}
305
306TCGv_i32 tcg_global_reg_new_i32(int reg, const char *name)
307{
308 int idx;
309
310 idx = tcg_global_reg_new_internal(TCG_TYPE_I32, reg, name);
311 return MAKE_TCGV_I32(idx);
312}
313
314TCGv_i64 tcg_global_reg_new_i64(int reg, const char *name)
315{
316 int idx;
317
318 idx = tcg_global_reg_new_internal(TCG_TYPE_I64, reg, name);
319 return MAKE_TCGV_I64(idx);
bellardc896fe22008-02-01 10:05:41 +0000320}
321
pbrooka7812ae2008-11-17 14:43:54 +0000322static inline int tcg_global_mem_new_internal(TCGType type, int reg,
323 tcg_target_long offset,
324 const char *name)
bellardc896fe22008-02-01 10:05:41 +0000325{
326 TCGContext *s = &tcg_ctx;
327 TCGTemp *ts;
328 int idx;
329
330 idx = s->nb_globals;
331#if TCG_TARGET_REG_BITS == 32
332 if (type == TCG_TYPE_I64) {
333 char buf[64];
thsc5889792008-06-07 04:31:49 +0000334 tcg_temp_alloc(s, s->nb_globals + 2);
bellardc896fe22008-02-01 10:05:41 +0000335 ts = &s->temps[s->nb_globals];
336 ts->base_type = type;
337 ts->type = TCG_TYPE_I32;
338 ts->fixed_reg = 0;
339 ts->mem_allocated = 1;
340 ts->mem_reg = reg;
341#ifdef TCG_TARGET_WORDS_BIGENDIAN
342 ts->mem_offset = offset + 4;
343#else
344 ts->mem_offset = offset;
345#endif
bellardc896fe22008-02-01 10:05:41 +0000346 pstrcpy(buf, sizeof(buf), name);
347 pstrcat(buf, sizeof(buf), "_0");
348 ts->name = strdup(buf);
349 ts++;
350
351 ts->base_type = type;
352 ts->type = TCG_TYPE_I32;
353 ts->fixed_reg = 0;
354 ts->mem_allocated = 1;
355 ts->mem_reg = reg;
356#ifdef TCG_TARGET_WORDS_BIGENDIAN
357 ts->mem_offset = offset;
358#else
359 ts->mem_offset = offset + 4;
360#endif
bellardc896fe22008-02-01 10:05:41 +0000361 pstrcpy(buf, sizeof(buf), name);
362 pstrcat(buf, sizeof(buf), "_1");
363 ts->name = strdup(buf);
364
365 s->nb_globals += 2;
366 } else
367#endif
368 {
369 tcg_temp_alloc(s, s->nb_globals + 1);
370 ts = &s->temps[s->nb_globals];
371 ts->base_type = type;
372 ts->type = type;
373 ts->fixed_reg = 0;
374 ts->mem_allocated = 1;
375 ts->mem_reg = reg;
376 ts->mem_offset = offset;
bellardc896fe22008-02-01 10:05:41 +0000377 ts->name = name;
378 s->nb_globals++;
379 }
pbrooka7812ae2008-11-17 14:43:54 +0000380 return idx;
bellardc896fe22008-02-01 10:05:41 +0000381}
382
pbrooka7812ae2008-11-17 14:43:54 +0000383TCGv_i32 tcg_global_mem_new_i32(int reg, tcg_target_long offset,
384 const char *name)
385{
386 int idx;
387
388 idx = tcg_global_mem_new_internal(TCG_TYPE_I32, reg, offset, name);
389 return MAKE_TCGV_I32(idx);
390}
391
392TCGv_i64 tcg_global_mem_new_i64(int reg, tcg_target_long offset,
393 const char *name)
394{
395 int idx;
396
397 idx = tcg_global_mem_new_internal(TCG_TYPE_I64, reg, offset, name);
398 return MAKE_TCGV_I64(idx);
399}
400
401static inline int tcg_temp_new_internal(TCGType type, int temp_local)
bellardc896fe22008-02-01 10:05:41 +0000402{
403 TCGContext *s = &tcg_ctx;
404 TCGTemp *ts;
bellard641d5fb2008-05-25 17:24:00 +0000405 int idx, k;
bellardc896fe22008-02-01 10:05:41 +0000406
bellard641d5fb2008-05-25 17:24:00 +0000407 k = type;
408 if (temp_local)
409 k += TCG_TYPE_COUNT;
410 idx = s->first_free_temp[k];
bellarde8996ee2008-05-23 17:33:39 +0000411 if (idx != -1) {
412 /* There is already an available temp with the
413 right type */
414 ts = &s->temps[idx];
bellard641d5fb2008-05-25 17:24:00 +0000415 s->first_free_temp[k] = ts->next_free_temp;
bellarde8996ee2008-05-23 17:33:39 +0000416 ts->temp_allocated = 1;
bellard641d5fb2008-05-25 17:24:00 +0000417 assert(ts->temp_local == temp_local);
bellarde8996ee2008-05-23 17:33:39 +0000418 } else {
419 idx = s->nb_temps;
bellardc896fe22008-02-01 10:05:41 +0000420#if TCG_TARGET_REG_BITS == 32
bellarde8996ee2008-05-23 17:33:39 +0000421 if (type == TCG_TYPE_I64) {
ths8df1ca42008-06-11 11:03:34 +0000422 tcg_temp_alloc(s, s->nb_temps + 2);
bellarde8996ee2008-05-23 17:33:39 +0000423 ts = &s->temps[s->nb_temps];
424 ts->base_type = type;
425 ts->type = TCG_TYPE_I32;
426 ts->temp_allocated = 1;
bellard641d5fb2008-05-25 17:24:00 +0000427 ts->temp_local = temp_local;
bellarde8996ee2008-05-23 17:33:39 +0000428 ts->name = NULL;
429 ts++;
430 ts->base_type = TCG_TYPE_I32;
431 ts->type = TCG_TYPE_I32;
432 ts->temp_allocated = 1;
bellard641d5fb2008-05-25 17:24:00 +0000433 ts->temp_local = temp_local;
bellarde8996ee2008-05-23 17:33:39 +0000434 ts->name = NULL;
435 s->nb_temps += 2;
436 } else
bellardc896fe22008-02-01 10:05:41 +0000437#endif
bellarde8996ee2008-05-23 17:33:39 +0000438 {
439 tcg_temp_alloc(s, s->nb_temps + 1);
440 ts = &s->temps[s->nb_temps];
441 ts->base_type = type;
442 ts->type = type;
443 ts->temp_allocated = 1;
bellard641d5fb2008-05-25 17:24:00 +0000444 ts->temp_local = temp_local;
bellarde8996ee2008-05-23 17:33:39 +0000445 ts->name = NULL;
446 s->nb_temps++;
447 }
bellardc896fe22008-02-01 10:05:41 +0000448 }
pbrooka7812ae2008-11-17 14:43:54 +0000449 return idx;
bellardc896fe22008-02-01 10:05:41 +0000450}
451
pbrooka7812ae2008-11-17 14:43:54 +0000452TCGv_i32 tcg_temp_new_internal_i32(int temp_local)
453{
454 int idx;
455
456 idx = tcg_temp_new_internal(TCG_TYPE_I32, temp_local);
457 return MAKE_TCGV_I32(idx);
458}
459
460TCGv_i64 tcg_temp_new_internal_i64(int temp_local)
461{
462 int idx;
463
464 idx = tcg_temp_new_internal(TCG_TYPE_I64, temp_local);
465 return MAKE_TCGV_I64(idx);
466}
467
468static inline void tcg_temp_free_internal(int idx)
bellardc896fe22008-02-01 10:05:41 +0000469{
470 TCGContext *s = &tcg_ctx;
471 TCGTemp *ts;
bellard641d5fb2008-05-25 17:24:00 +0000472 int k;
bellardc896fe22008-02-01 10:05:41 +0000473
bellarde8996ee2008-05-23 17:33:39 +0000474 assert(idx >= s->nb_globals && idx < s->nb_temps);
bellardc896fe22008-02-01 10:05:41 +0000475 ts = &s->temps[idx];
bellarde8996ee2008-05-23 17:33:39 +0000476 assert(ts->temp_allocated != 0);
477 ts->temp_allocated = 0;
bellard641d5fb2008-05-25 17:24:00 +0000478 k = ts->base_type;
479 if (ts->temp_local)
480 k += TCG_TYPE_COUNT;
481 ts->next_free_temp = s->first_free_temp[k];
482 s->first_free_temp[k] = idx;
bellarde8996ee2008-05-23 17:33:39 +0000483}
484
pbrooka7812ae2008-11-17 14:43:54 +0000485void tcg_temp_free_i32(TCGv_i32 arg)
bellarde8996ee2008-05-23 17:33:39 +0000486{
pbrooka7812ae2008-11-17 14:43:54 +0000487 tcg_temp_free_internal(GET_TCGV_I32(arg));
488}
489
490void tcg_temp_free_i64(TCGv_i64 arg)
491{
492 tcg_temp_free_internal(GET_TCGV_I64(arg));
493}
494
495TCGv_i32 tcg_const_i32(int32_t val)
496{
497 TCGv_i32 t0;
498 t0 = tcg_temp_new_i32();
bellarde8996ee2008-05-23 17:33:39 +0000499 tcg_gen_movi_i32(t0, val);
500 return t0;
bellardc896fe22008-02-01 10:05:41 +0000501}
502
pbrooka7812ae2008-11-17 14:43:54 +0000503TCGv_i64 tcg_const_i64(int64_t val)
bellardc896fe22008-02-01 10:05:41 +0000504{
pbrooka7812ae2008-11-17 14:43:54 +0000505 TCGv_i64 t0;
506 t0 = tcg_temp_new_i64();
bellarde8996ee2008-05-23 17:33:39 +0000507 tcg_gen_movi_i64(t0, val);
508 return t0;
bellardc896fe22008-02-01 10:05:41 +0000509}
510
pbrooka7812ae2008-11-17 14:43:54 +0000511TCGv_i32 tcg_const_local_i32(int32_t val)
aurel32bdffd4a2008-10-21 11:30:45 +0000512{
pbrooka7812ae2008-11-17 14:43:54 +0000513 TCGv_i32 t0;
514 t0 = tcg_temp_local_new_i32();
aurel32bdffd4a2008-10-21 11:30:45 +0000515 tcg_gen_movi_i32(t0, val);
516 return t0;
517}
518
pbrooka7812ae2008-11-17 14:43:54 +0000519TCGv_i64 tcg_const_local_i64(int64_t val)
aurel32bdffd4a2008-10-21 11:30:45 +0000520{
pbrooka7812ae2008-11-17 14:43:54 +0000521 TCGv_i64 t0;
522 t0 = tcg_temp_local_new_i64();
aurel32bdffd4a2008-10-21 11:30:45 +0000523 tcg_gen_movi_i64(t0, val);
524 return t0;
525}
526
bellardc896fe22008-02-01 10:05:41 +0000527void tcg_register_helper(void *func, const char *name)
528{
529 TCGContext *s = &tcg_ctx;
530 int n;
531 if ((s->nb_helpers + 1) > s->allocated_helpers) {
532 n = s->allocated_helpers;
533 if (n == 0) {
534 n = 4;
535 } else {
536 n *= 2;
537 }
538 s->helpers = realloc(s->helpers, n * sizeof(TCGHelperInfo));
539 s->allocated_helpers = n;
540 }
bellard4dc81f22008-05-22 16:08:32 +0000541 s->helpers[s->nb_helpers].func = (tcg_target_ulong)func;
bellardc896fe22008-02-01 10:05:41 +0000542 s->helpers[s->nb_helpers].name = name;
543 s->nb_helpers++;
544}
545
bellard39cf05d2008-05-22 14:59:57 +0000546/* Note: we convert the 64 bit args to 32 bit and do some alignment
547 and endian swap. Maybe it would be better to do the alignment
548 and endian swap in tcg_reg_alloc_call(). */
pbrooka7812ae2008-11-17 14:43:54 +0000549void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags,
550 int sizemask, TCGArg ret, int nargs, TCGArg *args)
bellardc896fe22008-02-01 10:05:41 +0000551{
pbrooka7812ae2008-11-17 14:43:54 +0000552 int call_type;
553 int i;
554 int real_args;
555 int nb_rets;
556 TCGArg *nparam;
557 *gen_opc_ptr++ = INDEX_op_call;
558 nparam = gen_opparam_ptr++;
bellardc896fe22008-02-01 10:05:41 +0000559 call_type = (flags & TCG_CALL_TYPE_MASK);
pbrooka7812ae2008-11-17 14:43:54 +0000560 if (ret != TCG_CALL_DUMMY_ARG) {
561#if TCG_TARGET_REG_BITS < 64
562 if (sizemask & 1) {
563#ifdef TCG_TARGET_WORDS_BIGENDIAN
564 *gen_opparam_ptr++ = ret + 1;
565 *gen_opparam_ptr++ = ret;
566#else
567 *gen_opparam_ptr++ = ret;
568 *gen_opparam_ptr++ = ret + 1;
569#endif
570 nb_rets = 2;
571 } else
572#endif
573 {
574 *gen_opparam_ptr++ = ret;
575 nb_rets = 1;
576 }
577 } else {
578 nb_rets = 0;
579 }
580 real_args = 0;
581 for (i = 0; i < nargs; i++) {
582#if TCG_TARGET_REG_BITS < 64
583 if (sizemask & (2 << i)) {
bellardc896fe22008-02-01 10:05:41 +0000584#ifdef TCG_TARGET_I386
585 /* REGPARM case: if the third parameter is 64 bit, it is
586 allocated on the stack */
pbrooka7812ae2008-11-17 14:43:54 +0000587 if (i == 2 && call_type == TCG_CALL_TYPE_REGPARM) {
bellardc896fe22008-02-01 10:05:41 +0000588 call_type = TCG_CALL_TYPE_REGPARM_2;
589 flags = (flags & ~TCG_CALL_TYPE_MASK) | call_type;
590 }
pbrooka7812ae2008-11-17 14:43:54 +0000591#endif
bellard39cf05d2008-05-22 14:59:57 +0000592#ifdef TCG_TARGET_CALL_ALIGN_ARGS
593 /* some targets want aligned 64 bit args */
malcebd486d2008-11-29 19:55:15 +0000594 if (real_args & 1) {
pbrooka7812ae2008-11-17 14:43:54 +0000595 *gen_opparam_ptr++ = TCG_CALL_DUMMY_ARG;
malcebd486d2008-11-29 19:55:15 +0000596 real_args++;
bellard39cf05d2008-05-22 14:59:57 +0000597 }
598#endif
bellardc896fe22008-02-01 10:05:41 +0000599#ifdef TCG_TARGET_WORDS_BIGENDIAN
pbrooka7812ae2008-11-17 14:43:54 +0000600 *gen_opparam_ptr++ = args[i] + 1;
601 *gen_opparam_ptr++ = args[i];
bellardc896fe22008-02-01 10:05:41 +0000602#else
pbrooka7812ae2008-11-17 14:43:54 +0000603 *gen_opparam_ptr++ = args[i];
604 *gen_opparam_ptr++ = args[i] + 1;
bellardc896fe22008-02-01 10:05:41 +0000605#endif
pbrooka7812ae2008-11-17 14:43:54 +0000606 real_args += 2;
607 } else
bellardc896fe22008-02-01 10:05:41 +0000608#endif
pbrooka7812ae2008-11-17 14:43:54 +0000609 {
610 *gen_opparam_ptr++ = args[i];
611 real_args++;
bellardc896fe22008-02-01 10:05:41 +0000612 }
613 }
pbrooka7812ae2008-11-17 14:43:54 +0000614 *gen_opparam_ptr++ = GET_TCGV_PTR(func);
615
616 *gen_opparam_ptr++ = flags;
617
618 *nparam = (nb_rets << 16) | (real_args + 1);
619
620 /* total parameters, needed to go backward in the instruction stream */
621 *gen_opparam_ptr++ = 1 + nb_rets + real_args + 3;
bellardc896fe22008-02-01 10:05:41 +0000622}
bellardc896fe22008-02-01 10:05:41 +0000623
pbrookac56dd42008-02-03 19:56:33 +0000624#if TCG_TARGET_REG_BITS == 32
pbrooka7812ae2008-11-17 14:43:54 +0000625void tcg_gen_shifti_i64(TCGv_i64 ret, TCGv_i64 arg1,
bellardc896fe22008-02-01 10:05:41 +0000626 int c, int right, int arith)
627{
bellardcf60bce2008-05-22 14:39:25 +0000628 if (c == 0) {
pbrooka7812ae2008-11-17 14:43:54 +0000629 tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg1));
bellardcf60bce2008-05-22 14:39:25 +0000630 tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1));
631 } else if (c >= 32) {
bellardc896fe22008-02-01 10:05:41 +0000632 c -= 32;
633 if (right) {
634 if (arith) {
pbrooka7812ae2008-11-17 14:43:54 +0000635 tcg_gen_sari_i32(TCGV_LOW(ret), TCGV_HIGH(arg1), c);
pbrookac56dd42008-02-03 19:56:33 +0000636 tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), 31);
bellardc896fe22008-02-01 10:05:41 +0000637 } else {
pbrooka7812ae2008-11-17 14:43:54 +0000638 tcg_gen_shri_i32(TCGV_LOW(ret), TCGV_HIGH(arg1), c);
pbrookac56dd42008-02-03 19:56:33 +0000639 tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
bellardc896fe22008-02-01 10:05:41 +0000640 }
641 } else {
pbrooka7812ae2008-11-17 14:43:54 +0000642 tcg_gen_shli_i32(TCGV_HIGH(ret), TCGV_LOW(arg1), c);
643 tcg_gen_movi_i32(TCGV_LOW(ret), 0);
bellardc896fe22008-02-01 10:05:41 +0000644 }
645 } else {
pbrooka7812ae2008-11-17 14:43:54 +0000646 TCGv_i32 t0, t1;
bellardc896fe22008-02-01 10:05:41 +0000647
pbrooka7812ae2008-11-17 14:43:54 +0000648 t0 = tcg_temp_new_i32();
649 t1 = tcg_temp_new_i32();
bellardc896fe22008-02-01 10:05:41 +0000650 if (right) {
pbrookac56dd42008-02-03 19:56:33 +0000651 tcg_gen_shli_i32(t0, TCGV_HIGH(arg1), 32 - c);
bellardc896fe22008-02-01 10:05:41 +0000652 if (arith)
pbrookac56dd42008-02-03 19:56:33 +0000653 tcg_gen_sari_i32(t1, TCGV_HIGH(arg1), c);
pbrooka7812ae2008-11-17 14:43:54 +0000654 else
pbrookac56dd42008-02-03 19:56:33 +0000655 tcg_gen_shri_i32(t1, TCGV_HIGH(arg1), c);
pbrooka7812ae2008-11-17 14:43:54 +0000656 tcg_gen_shri_i32(TCGV_LOW(ret), TCGV_LOW(arg1), c);
657 tcg_gen_or_i32(TCGV_LOW(ret), TCGV_LOW(ret), t0);
pbrookac56dd42008-02-03 19:56:33 +0000658 tcg_gen_mov_i32(TCGV_HIGH(ret), t1);
bellardc896fe22008-02-01 10:05:41 +0000659 } else {
pbrooka7812ae2008-11-17 14:43:54 +0000660 tcg_gen_shri_i32(t0, TCGV_LOW(arg1), 32 - c);
bellardc896fe22008-02-01 10:05:41 +0000661 /* Note: ret can be the same as arg1, so we use t1 */
pbrooka7812ae2008-11-17 14:43:54 +0000662 tcg_gen_shli_i32(t1, TCGV_LOW(arg1), c);
pbrookac56dd42008-02-03 19:56:33 +0000663 tcg_gen_shli_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), c);
664 tcg_gen_or_i32(TCGV_HIGH(ret), TCGV_HIGH(ret), t0);
pbrooka7812ae2008-11-17 14:43:54 +0000665 tcg_gen_mov_i32(TCGV_LOW(ret), t1);
bellardc896fe22008-02-01 10:05:41 +0000666 }
pbrooka7812ae2008-11-17 14:43:54 +0000667 tcg_temp_free_i32(t0);
668 tcg_temp_free_i32(t1);
bellardc896fe22008-02-01 10:05:41 +0000669 }
670}
pbrookac56dd42008-02-03 19:56:33 +0000671#endif
bellardc896fe22008-02-01 10:05:41 +0000672
blueswir18fcd3692008-08-17 20:26:25 +0000673static void tcg_reg_alloc_start(TCGContext *s)
bellardc896fe22008-02-01 10:05:41 +0000674{
675 int i;
676 TCGTemp *ts;
677 for(i = 0; i < s->nb_globals; i++) {
678 ts = &s->temps[i];
679 if (ts->fixed_reg) {
680 ts->val_type = TEMP_VAL_REG;
681 } else {
682 ts->val_type = TEMP_VAL_MEM;
683 }
684 }
bellarde8996ee2008-05-23 17:33:39 +0000685 for(i = s->nb_globals; i < s->nb_temps; i++) {
686 ts = &s->temps[i];
687 ts->val_type = TEMP_VAL_DEAD;
688 ts->mem_allocated = 0;
689 ts->fixed_reg = 0;
690 }
bellardc896fe22008-02-01 10:05:41 +0000691 for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
692 s->reg_to_temp[i] = -1;
693 }
694}
695
pbrookac56dd42008-02-03 19:56:33 +0000696static char *tcg_get_arg_str_idx(TCGContext *s, char *buf, int buf_size,
697 int idx)
bellardc896fe22008-02-01 10:05:41 +0000698{
699 TCGTemp *ts;
pbrookac56dd42008-02-03 19:56:33 +0000700
701 ts = &s->temps[idx];
702 if (idx < s->nb_globals) {
703 pstrcpy(buf, buf_size, ts->name);
bellardc896fe22008-02-01 10:05:41 +0000704 } else {
bellard641d5fb2008-05-25 17:24:00 +0000705 if (ts->temp_local)
706 snprintf(buf, buf_size, "loc%d", idx - s->nb_globals);
707 else
708 snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals);
bellardc896fe22008-02-01 10:05:41 +0000709 }
710 return buf;
711}
712
pbrooka7812ae2008-11-17 14:43:54 +0000713char *tcg_get_arg_str_i32(TCGContext *s, char *buf, int buf_size, TCGv_i32 arg)
pbrookac56dd42008-02-03 19:56:33 +0000714{
pbrooka7812ae2008-11-17 14:43:54 +0000715 return tcg_get_arg_str_idx(s, buf, buf_size, GET_TCGV_I32(arg));
716}
717
718char *tcg_get_arg_str_i64(TCGContext *s, char *buf, int buf_size, TCGv_i64 arg)
719{
blueswir1a810a2d2008-12-07 17:16:42 +0000720 return tcg_get_arg_str_idx(s, buf, buf_size, GET_TCGV_I64(arg));
pbrookac56dd42008-02-03 19:56:33 +0000721}
722
bellarde8996ee2008-05-23 17:33:39 +0000723static int helper_cmp(const void *p1, const void *p2)
724{
725 const TCGHelperInfo *th1 = p1;
726 const TCGHelperInfo *th2 = p2;
727 if (th1->func < th2->func)
728 return -1;
729 else if (th1->func == th2->func)
730 return 0;
731 else
732 return 1;
733}
734
735/* find helper definition (Note: A hash table would be better) */
bellard4dc81f22008-05-22 16:08:32 +0000736static TCGHelperInfo *tcg_find_helper(TCGContext *s, tcg_target_ulong val)
737{
bellarde8996ee2008-05-23 17:33:39 +0000738 int m, m_min, m_max;
739 TCGHelperInfo *th;
740 tcg_target_ulong v;
741
742 if (unlikely(!s->helpers_sorted)) {
743 qsort(s->helpers, s->nb_helpers, sizeof(TCGHelperInfo),
744 helper_cmp);
745 s->helpers_sorted = 1;
746 }
747
748 /* binary search */
749 m_min = 0;
750 m_max = s->nb_helpers - 1;
751 while (m_min <= m_max) {
752 m = (m_min + m_max) >> 1;
753 th = &s->helpers[m];
754 v = th->func;
755 if (v == val)
756 return th;
757 else if (val < v) {
758 m_max = m - 1;
759 } else {
760 m_min = m + 1;
761 }
bellard4dc81f22008-05-22 16:08:32 +0000762 }
763 return NULL;
764}
765
blueswir1f48f3ed2008-09-14 07:45:17 +0000766static const char * const cond_name[] =
767{
768 [TCG_COND_EQ] = "eq",
769 [TCG_COND_NE] = "ne",
770 [TCG_COND_LT] = "lt",
771 [TCG_COND_GE] = "ge",
772 [TCG_COND_LE] = "le",
773 [TCG_COND_GT] = "gt",
774 [TCG_COND_LTU] = "ltu",
775 [TCG_COND_GEU] = "geu",
776 [TCG_COND_LEU] = "leu",
777 [TCG_COND_GTU] = "gtu"
778};
779
bellardc896fe22008-02-01 10:05:41 +0000780void tcg_dump_ops(TCGContext *s, FILE *outfile)
781{
782 const uint16_t *opc_ptr;
783 const TCGArg *args;
784 TCGArg arg;
bellard7e4597d2008-05-22 16:56:05 +0000785 int c, i, k, nb_oargs, nb_iargs, nb_cargs, first_insn;
bellardc896fe22008-02-01 10:05:41 +0000786 const TCGOpDef *def;
787 char buf[128];
788
bellard7e4597d2008-05-22 16:56:05 +0000789 first_insn = 1;
bellardc896fe22008-02-01 10:05:41 +0000790 opc_ptr = gen_opc_buf;
791 args = gen_opparam_buf;
792 while (opc_ptr < gen_opc_ptr) {
793 c = *opc_ptr++;
794 def = &tcg_op_defs[c];
bellard7e4597d2008-05-22 16:56:05 +0000795 if (c == INDEX_op_debug_insn_start) {
796 uint64_t pc;
797#if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
798 pc = ((uint64_t)args[1] << 32) | args[0];
799#else
800 pc = args[0];
801#endif
802 if (!first_insn)
803 fprintf(outfile, "\n");
804 fprintf(outfile, " ---- 0x%" PRIx64, pc);
805 first_insn = 0;
806 nb_oargs = def->nb_oargs;
807 nb_iargs = def->nb_iargs;
808 nb_cargs = def->nb_cargs;
809 } else if (c == INDEX_op_call) {
bellardc896fe22008-02-01 10:05:41 +0000810 TCGArg arg;
bellard4dc81f22008-05-22 16:08:32 +0000811
bellardc896fe22008-02-01 10:05:41 +0000812 /* variable number of arguments */
813 arg = *args++;
814 nb_oargs = arg >> 16;
815 nb_iargs = arg & 0xffff;
816 nb_cargs = def->nb_cargs;
bellardc896fe22008-02-01 10:05:41 +0000817
bellard7e4597d2008-05-22 16:56:05 +0000818 fprintf(outfile, " %s ", def->name);
819
bellardb03cce82008-05-10 10:52:05 +0000820 /* function name */
pbrookac56dd42008-02-03 19:56:33 +0000821 fprintf(outfile, "%s",
bellarde8996ee2008-05-23 17:33:39 +0000822 tcg_get_arg_str_idx(s, buf, sizeof(buf), args[nb_oargs + nb_iargs - 1]));
bellardb03cce82008-05-10 10:52:05 +0000823 /* flags */
824 fprintf(outfile, ",$0x%" TCG_PRIlx,
825 args[nb_oargs + nb_iargs]);
826 /* nb out args */
827 fprintf(outfile, ",$%d", nb_oargs);
828 for(i = 0; i < nb_oargs; i++) {
bellardc896fe22008-02-01 10:05:41 +0000829 fprintf(outfile, ",");
bellardb03cce82008-05-10 10:52:05 +0000830 fprintf(outfile, "%s",
831 tcg_get_arg_str_idx(s, buf, sizeof(buf), args[i]));
832 }
833 for(i = 0; i < (nb_iargs - 1); i++) {
834 fprintf(outfile, ",");
bellard39cf05d2008-05-22 14:59:57 +0000835 if (args[nb_oargs + i] == TCG_CALL_DUMMY_ARG) {
836 fprintf(outfile, "<dummy>");
837 } else {
838 fprintf(outfile, "%s",
839 tcg_get_arg_str_idx(s, buf, sizeof(buf), args[nb_oargs + i]));
840 }
bellardb03cce82008-05-10 10:52:05 +0000841 }
bellarde8996ee2008-05-23 17:33:39 +0000842 } else if (c == INDEX_op_movi_i32
843#if TCG_TARGET_REG_BITS == 64
844 || c == INDEX_op_movi_i64
845#endif
846 ) {
847 tcg_target_ulong val;
848 TCGHelperInfo *th;
849
850 nb_oargs = def->nb_oargs;
851 nb_iargs = def->nb_iargs;
852 nb_cargs = def->nb_cargs;
853 fprintf(outfile, " %s %s,$", def->name,
854 tcg_get_arg_str_idx(s, buf, sizeof(buf), args[0]));
855 val = args[1];
856 th = tcg_find_helper(s, val);
857 if (th) {
aurel323e9a4742008-12-14 17:29:58 +0000858 fprintf(outfile, "%s", th->name);
bellarde8996ee2008-05-23 17:33:39 +0000859 } else {
860 if (c == INDEX_op_movi_i32)
861 fprintf(outfile, "0x%x", (uint32_t)val);
862 else
863 fprintf(outfile, "0x%" PRIx64 , (uint64_t)val);
864 }
bellardb03cce82008-05-10 10:52:05 +0000865 } else {
bellard7e4597d2008-05-22 16:56:05 +0000866 fprintf(outfile, " %s ", def->name);
bellardb03cce82008-05-10 10:52:05 +0000867 if (c == INDEX_op_nopn) {
868 /* variable number of arguments */
869 nb_cargs = *args;
870 nb_oargs = 0;
871 nb_iargs = 0;
872 } else {
873 nb_oargs = def->nb_oargs;
874 nb_iargs = def->nb_iargs;
875 nb_cargs = def->nb_cargs;
876 }
877
878 k = 0;
879 for(i = 0; i < nb_oargs; i++) {
880 if (k != 0)
881 fprintf(outfile, ",");
882 fprintf(outfile, "%s",
883 tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++]));
884 }
885 for(i = 0; i < nb_iargs; i++) {
886 if (k != 0)
887 fprintf(outfile, ",");
888 fprintf(outfile, "%s",
889 tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++]));
890 }
blueswir1f48f3ed2008-09-14 07:45:17 +0000891 if (c == INDEX_op_brcond_i32
892#if TCG_TARGET_REG_BITS == 32
893 || c == INDEX_op_brcond2_i32
894#elif TCG_TARGET_REG_BITS == 64
895 || c == INDEX_op_brcond_i64
896#endif
897 ) {
898 if (args[k] < ARRAY_SIZE(cond_name) && cond_name[args[k]])
899 fprintf(outfile, ",%s", cond_name[args[k++]]);
900 else
901 fprintf(outfile, ",$0x%" TCG_PRIlx, args[k++]);
902 i = 1;
903 }
904 else
905 i = 0;
906 for(; i < nb_cargs; i++) {
bellardb03cce82008-05-10 10:52:05 +0000907 if (k != 0)
908 fprintf(outfile, ",");
909 arg = args[k++];
910 fprintf(outfile, "$0x%" TCG_PRIlx, arg);
911 }
bellardc896fe22008-02-01 10:05:41 +0000912 }
913 fprintf(outfile, "\n");
914 args += nb_iargs + nb_oargs + nb_cargs;
915 }
916}
917
918/* we give more priority to constraints with less registers */
919static int get_constraint_priority(const TCGOpDef *def, int k)
920{
921 const TCGArgConstraint *arg_ct;
922
923 int i, n;
924 arg_ct = &def->args_ct[k];
925 if (arg_ct->ct & TCG_CT_ALIAS) {
926 /* an alias is equivalent to a single register */
927 n = 1;
928 } else {
929 if (!(arg_ct->ct & TCG_CT_REG))
930 return 0;
931 n = 0;
932 for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
933 if (tcg_regset_test_reg(arg_ct->u.regs, i))
934 n++;
935 }
936 }
937 return TCG_TARGET_NB_REGS - n + 1;
938}
939
940/* sort from highest priority to lowest */
941static void sort_constraints(TCGOpDef *def, int start, int n)
942{
943 int i, j, p1, p2, tmp;
944
945 for(i = 0; i < n; i++)
946 def->sorted_args[start + i] = start + i;
947 if (n <= 1)
948 return;
949 for(i = 0; i < n - 1; i++) {
950 for(j = i + 1; j < n; j++) {
951 p1 = get_constraint_priority(def, def->sorted_args[start + i]);
952 p2 = get_constraint_priority(def, def->sorted_args[start + j]);
953 if (p1 < p2) {
954 tmp = def->sorted_args[start + i];
955 def->sorted_args[start + i] = def->sorted_args[start + j];
956 def->sorted_args[start + j] = tmp;
957 }
958 }
959 }
960}
961
962void tcg_add_target_add_op_defs(const TCGTargetOpDef *tdefs)
963{
964 int op;
965 TCGOpDef *def;
966 const char *ct_str;
967 int i, nb_args;
968
969 for(;;) {
970 if (tdefs->op < 0)
971 break;
972 op = tdefs->op;
973 assert(op >= 0 && op < NB_OPS);
974 def = &tcg_op_defs[op];
975 nb_args = def->nb_iargs + def->nb_oargs;
976 for(i = 0; i < nb_args; i++) {
977 ct_str = tdefs->args_ct_str[i];
978 tcg_regset_clear(def->args_ct[i].u.regs);
979 def->args_ct[i].ct = 0;
980 if (ct_str[0] >= '0' && ct_str[0] <= '9') {
981 int oarg;
982 oarg = ct_str[0] - '0';
983 assert(oarg < def->nb_oargs);
984 assert(def->args_ct[oarg].ct & TCG_CT_REG);
985 /* TCG_CT_ALIAS is for the output arguments. The input
bellard5ff9d6a2008-02-04 00:37:54 +0000986 argument is tagged with TCG_CT_IALIAS. */
bellardc896fe22008-02-01 10:05:41 +0000987 def->args_ct[i] = def->args_ct[oarg];
bellard5ff9d6a2008-02-04 00:37:54 +0000988 def->args_ct[oarg].ct = TCG_CT_ALIAS;
989 def->args_ct[oarg].alias_index = i;
bellardc896fe22008-02-01 10:05:41 +0000990 def->args_ct[i].ct |= TCG_CT_IALIAS;
bellard5ff9d6a2008-02-04 00:37:54 +0000991 def->args_ct[i].alias_index = oarg;
bellardc896fe22008-02-01 10:05:41 +0000992 } else {
993 for(;;) {
994 if (*ct_str == '\0')
995 break;
996 switch(*ct_str) {
997 case 'i':
998 def->args_ct[i].ct |= TCG_CT_CONST;
999 ct_str++;
1000 break;
1001 default:
1002 if (target_parse_constraint(&def->args_ct[i], &ct_str) < 0) {
1003 fprintf(stderr, "Invalid constraint '%s' for arg %d of operation '%s'\n",
1004 ct_str, i, def->name);
1005 exit(1);
1006 }
1007 }
1008 }
1009 }
1010 }
1011
1012 /* sort the constraints (XXX: this is just an heuristic) */
1013 sort_constraints(def, 0, def->nb_oargs);
1014 sort_constraints(def, def->nb_oargs, def->nb_iargs);
1015
1016#if 0
1017 {
1018 int i;
1019
1020 printf("%s: sorted=", def->name);
1021 for(i = 0; i < def->nb_oargs + def->nb_iargs; i++)
1022 printf(" %d", def->sorted_args[i]);
1023 printf("\n");
1024 }
1025#endif
1026 tdefs++;
1027 }
1028
1029}
1030
1031#ifdef USE_LIVENESS_ANALYSIS
1032
1033/* set a nop for an operation using 'nb_args' */
1034static inline void tcg_set_nop(TCGContext *s, uint16_t *opc_ptr,
1035 TCGArg *args, int nb_args)
1036{
1037 if (nb_args == 0) {
1038 *opc_ptr = INDEX_op_nop;
1039 } else {
1040 *opc_ptr = INDEX_op_nopn;
1041 args[0] = nb_args;
1042 args[nb_args - 1] = nb_args;
1043 }
1044}
1045
bellard641d5fb2008-05-25 17:24:00 +00001046/* liveness analysis: end of function: globals are live, temps are
1047 dead. */
1048/* XXX: at this stage, not used as there would be little gains because
1049 most TBs end with a conditional jump. */
1050static inline void tcg_la_func_end(TCGContext *s, uint8_t *dead_temps)
bellardc896fe22008-02-01 10:05:41 +00001051{
1052 memset(dead_temps, 0, s->nb_globals);
1053 memset(dead_temps + s->nb_globals, 1, s->nb_temps - s->nb_globals);
1054}
1055
bellard641d5fb2008-05-25 17:24:00 +00001056/* liveness analysis: end of basic block: globals are live, temps are
1057 dead, local temps are live. */
1058static inline void tcg_la_bb_end(TCGContext *s, uint8_t *dead_temps)
1059{
1060 int i;
1061 TCGTemp *ts;
1062
1063 memset(dead_temps, 0, s->nb_globals);
1064 ts = &s->temps[s->nb_globals];
1065 for(i = s->nb_globals; i < s->nb_temps; i++) {
1066 if (ts->temp_local)
1067 dead_temps[i] = 0;
1068 else
1069 dead_temps[i] = 1;
1070 ts++;
1071 }
1072}
1073
bellardc896fe22008-02-01 10:05:41 +00001074/* Liveness analysis : update the opc_dead_iargs array to tell if a
1075 given input arguments is dead. Instructions updating dead
1076 temporaries are removed. */
blueswir18fcd3692008-08-17 20:26:25 +00001077static void tcg_liveness_analysis(TCGContext *s)
bellardc896fe22008-02-01 10:05:41 +00001078{
1079 int i, op_index, op, nb_args, nb_iargs, nb_oargs, arg, nb_ops;
1080 TCGArg *args;
1081 const TCGOpDef *def;
1082 uint8_t *dead_temps;
1083 unsigned int dead_iargs;
1084
1085 gen_opc_ptr++; /* skip end */
1086
1087 nb_ops = gen_opc_ptr - gen_opc_buf;
1088
Aurelien Jarno94f4af02009-10-04 15:30:44 +02001089 s->op_dead_iargs = tcg_malloc(nb_ops * sizeof(uint16_t));
bellardc896fe22008-02-01 10:05:41 +00001090
1091 dead_temps = tcg_malloc(s->nb_temps);
1092 memset(dead_temps, 1, s->nb_temps);
1093
1094 args = gen_opparam_ptr;
1095 op_index = nb_ops - 1;
1096 while (op_index >= 0) {
1097 op = gen_opc_buf[op_index];
1098 def = &tcg_op_defs[op];
1099 switch(op) {
1100 case INDEX_op_call:
bellardc6e113f2008-05-17 12:42:15 +00001101 {
1102 int call_flags;
bellardc896fe22008-02-01 10:05:41 +00001103
bellardc6e113f2008-05-17 12:42:15 +00001104 nb_args = args[-1];
1105 args -= nb_args;
1106 nb_iargs = args[0] & 0xffff;
1107 nb_oargs = args[0] >> 16;
1108 args++;
1109 call_flags = args[nb_oargs + nb_iargs];
bellardc896fe22008-02-01 10:05:41 +00001110
bellardc6e113f2008-05-17 12:42:15 +00001111 /* pure functions can be removed if their result is not
1112 used */
1113 if (call_flags & TCG_CALL_PURE) {
1114 for(i = 0; i < nb_oargs; i++) {
1115 arg = args[i];
1116 if (!dead_temps[arg])
1117 goto do_not_remove_call;
1118 }
1119 tcg_set_nop(s, gen_opc_buf + op_index,
1120 args - 1, nb_args);
1121 } else {
1122 do_not_remove_call:
1123
1124 /* output args are dead */
1125 for(i = 0; i < nb_oargs; i++) {
1126 arg = args[i];
1127 dead_temps[arg] = 1;
1128 }
1129
aurel32b9c18f52009-04-06 12:33:59 +00001130 if (!(call_flags & TCG_CALL_CONST)) {
1131 /* globals are live (they may be used by the call) */
1132 memset(dead_temps, 0, s->nb_globals);
1133 }
1134
bellardc6e113f2008-05-17 12:42:15 +00001135 /* input args are live */
1136 dead_iargs = 0;
1137 for(i = 0; i < nb_iargs; i++) {
1138 arg = args[i + nb_oargs];
bellard39cf05d2008-05-22 14:59:57 +00001139 if (arg != TCG_CALL_DUMMY_ARG) {
1140 if (dead_temps[arg]) {
1141 dead_iargs |= (1 << i);
1142 }
1143 dead_temps[arg] = 0;
bellardc6e113f2008-05-17 12:42:15 +00001144 }
bellardc6e113f2008-05-17 12:42:15 +00001145 }
1146 s->op_dead_iargs[op_index] = dead_iargs;
bellardc896fe22008-02-01 10:05:41 +00001147 }
bellardc6e113f2008-05-17 12:42:15 +00001148 args--;
bellardc896fe22008-02-01 10:05:41 +00001149 }
bellardc896fe22008-02-01 10:05:41 +00001150 break;
1151 case INDEX_op_set_label:
1152 args--;
1153 /* mark end of basic block */
1154 tcg_la_bb_end(s, dead_temps);
1155 break;
bellard7e4597d2008-05-22 16:56:05 +00001156 case INDEX_op_debug_insn_start:
1157 args -= def->nb_args;
1158 break;
bellardc896fe22008-02-01 10:05:41 +00001159 case INDEX_op_nopn:
1160 nb_args = args[-1];
1161 args -= nb_args;
1162 break;
bellard5ff9d6a2008-02-04 00:37:54 +00001163 case INDEX_op_discard:
1164 args--;
1165 /* mark the temporary as dead */
1166 dead_temps[args[0]] = 1;
1167 break;
bellardc896fe22008-02-01 10:05:41 +00001168 case INDEX_op_end:
1169 break;
1170 /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */
1171 default:
aurel3249516bc2008-12-07 18:15:45 +00001172 args -= def->nb_args;
1173 nb_iargs = def->nb_iargs;
1174 nb_oargs = def->nb_oargs;
bellardc896fe22008-02-01 10:05:41 +00001175
aurel3249516bc2008-12-07 18:15:45 +00001176 /* Test if the operation can be removed because all
1177 its outputs are dead. We assume that nb_oargs == 0
1178 implies side effects */
1179 if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) {
1180 for(i = 0; i < nb_oargs; i++) {
1181 arg = args[i];
1182 if (!dead_temps[arg])
1183 goto do_not_remove;
bellardc896fe22008-02-01 10:05:41 +00001184 }
aurel3249516bc2008-12-07 18:15:45 +00001185 tcg_set_nop(s, gen_opc_buf + op_index, args, def->nb_args);
1186#ifdef CONFIG_PROFILER
1187 s->del_op_count++;
1188#endif
bellardc896fe22008-02-01 10:05:41 +00001189 } else {
aurel3249516bc2008-12-07 18:15:45 +00001190 do_not_remove:
1191
1192 /* output args are dead */
1193 for(i = 0; i < nb_oargs; i++) {
1194 arg = args[i];
1195 dead_temps[arg] = 1;
1196 }
1197
1198 /* if end of basic block, update */
1199 if (def->flags & TCG_OPF_BB_END) {
1200 tcg_la_bb_end(s, dead_temps);
1201 } else if (def->flags & TCG_OPF_CALL_CLOBBER) {
1202 /* globals are live */
1203 memset(dead_temps, 0, s->nb_globals);
1204 }
1205
1206 /* input args are live */
1207 dead_iargs = 0;
1208 for(i = 0; i < nb_iargs; i++) {
1209 arg = args[i + nb_oargs];
1210 if (dead_temps[arg]) {
1211 dead_iargs |= (1 << i);
1212 }
1213 dead_temps[arg] = 0;
1214 }
1215 s->op_dead_iargs[op_index] = dead_iargs;
bellardc896fe22008-02-01 10:05:41 +00001216 }
1217 break;
1218 }
1219 op_index--;
1220 }
1221
1222 if (args != gen_opparam_buf)
1223 tcg_abort();
1224}
1225#else
1226/* dummy liveness analysis */
1227void tcg_liveness_analysis(TCGContext *s)
1228{
1229 int nb_ops;
1230 nb_ops = gen_opc_ptr - gen_opc_buf;
1231
1232 s->op_dead_iargs = tcg_malloc(nb_ops * sizeof(uint16_t));
1233 memset(s->op_dead_iargs, 0, nb_ops * sizeof(uint16_t));
1234}
1235#endif
1236
1237#ifndef NDEBUG
1238static void dump_regs(TCGContext *s)
1239{
1240 TCGTemp *ts;
1241 int i;
1242 char buf[64];
1243
1244 for(i = 0; i < s->nb_temps; i++) {
1245 ts = &s->temps[i];
pbrookac56dd42008-02-03 19:56:33 +00001246 printf(" %10s: ", tcg_get_arg_str_idx(s, buf, sizeof(buf), i));
bellardc896fe22008-02-01 10:05:41 +00001247 switch(ts->val_type) {
1248 case TEMP_VAL_REG:
1249 printf("%s", tcg_target_reg_names[ts->reg]);
1250 break;
1251 case TEMP_VAL_MEM:
1252 printf("%d(%s)", (int)ts->mem_offset, tcg_target_reg_names[ts->mem_reg]);
1253 break;
1254 case TEMP_VAL_CONST:
1255 printf("$0x%" TCG_PRIlx, ts->val);
1256 break;
1257 case TEMP_VAL_DEAD:
1258 printf("D");
1259 break;
1260 default:
1261 printf("???");
1262 break;
1263 }
1264 printf("\n");
1265 }
1266
1267 for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
1268 if (s->reg_to_temp[i] >= 0) {
1269 printf("%s: %s\n",
1270 tcg_target_reg_names[i],
pbrookac56dd42008-02-03 19:56:33 +00001271 tcg_get_arg_str_idx(s, buf, sizeof(buf), s->reg_to_temp[i]));
bellardc896fe22008-02-01 10:05:41 +00001272 }
1273 }
1274}
1275
1276static void check_regs(TCGContext *s)
1277{
1278 int reg, k;
1279 TCGTemp *ts;
1280 char buf[64];
1281
1282 for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
1283 k = s->reg_to_temp[reg];
1284 if (k >= 0) {
1285 ts = &s->temps[k];
1286 if (ts->val_type != TEMP_VAL_REG ||
1287 ts->reg != reg) {
1288 printf("Inconsistency for register %s:\n",
1289 tcg_target_reg_names[reg]);
bellardb03cce82008-05-10 10:52:05 +00001290 goto fail;
bellardc896fe22008-02-01 10:05:41 +00001291 }
1292 }
1293 }
1294 for(k = 0; k < s->nb_temps; k++) {
1295 ts = &s->temps[k];
1296 if (ts->val_type == TEMP_VAL_REG &&
1297 !ts->fixed_reg &&
1298 s->reg_to_temp[ts->reg] != k) {
1299 printf("Inconsistency for temp %s:\n",
pbrookac56dd42008-02-03 19:56:33 +00001300 tcg_get_arg_str_idx(s, buf, sizeof(buf), k));
bellardb03cce82008-05-10 10:52:05 +00001301 fail:
bellardc896fe22008-02-01 10:05:41 +00001302 printf("reg state:\n");
1303 dump_regs(s);
1304 tcg_abort();
1305 }
1306 }
1307}
1308#endif
1309
1310static void temp_allocate_frame(TCGContext *s, int temp)
1311{
1312 TCGTemp *ts;
1313 ts = &s->temps[temp];
1314 s->current_frame_offset = (s->current_frame_offset + sizeof(tcg_target_long) - 1) & ~(sizeof(tcg_target_long) - 1);
1315 if (s->current_frame_offset + sizeof(tcg_target_long) > s->frame_end)
bellard5ff9d6a2008-02-04 00:37:54 +00001316 tcg_abort();
bellardc896fe22008-02-01 10:05:41 +00001317 ts->mem_offset = s->current_frame_offset;
1318 ts->mem_reg = s->frame_reg;
1319 ts->mem_allocated = 1;
1320 s->current_frame_offset += sizeof(tcg_target_long);
1321}
1322
1323/* free register 'reg' by spilling the corresponding temporary if necessary */
1324static void tcg_reg_free(TCGContext *s, int reg)
1325{
1326 TCGTemp *ts;
1327 int temp;
1328
1329 temp = s->reg_to_temp[reg];
1330 if (temp != -1) {
1331 ts = &s->temps[temp];
1332 assert(ts->val_type == TEMP_VAL_REG);
1333 if (!ts->mem_coherent) {
1334 if (!ts->mem_allocated)
1335 temp_allocate_frame(s, temp);
blueswir1e4d54342008-03-13 17:34:19 +00001336 tcg_out_st(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
bellardc896fe22008-02-01 10:05:41 +00001337 }
1338 ts->val_type = TEMP_VAL_MEM;
1339 s->reg_to_temp[reg] = -1;
1340 }
1341}
1342
1343/* Allocate a register belonging to reg1 & ~reg2 */
1344static int tcg_reg_alloc(TCGContext *s, TCGRegSet reg1, TCGRegSet reg2)
1345{
1346 int i, reg;
1347 TCGRegSet reg_ct;
1348
1349 tcg_regset_andnot(reg_ct, reg1, reg2);
1350
1351 /* first try free registers */
blueswir10954d0d2008-03-11 21:01:02 +00001352 for(i = 0; i < ARRAY_SIZE(tcg_target_reg_alloc_order); i++) {
bellardc896fe22008-02-01 10:05:41 +00001353 reg = tcg_target_reg_alloc_order[i];
1354 if (tcg_regset_test_reg(reg_ct, reg) && s->reg_to_temp[reg] == -1)
1355 return reg;
1356 }
1357
1358 /* XXX: do better spill choice */
blueswir10954d0d2008-03-11 21:01:02 +00001359 for(i = 0; i < ARRAY_SIZE(tcg_target_reg_alloc_order); i++) {
bellardc896fe22008-02-01 10:05:41 +00001360 reg = tcg_target_reg_alloc_order[i];
1361 if (tcg_regset_test_reg(reg_ct, reg)) {
1362 tcg_reg_free(s, reg);
1363 return reg;
1364 }
1365 }
1366
1367 tcg_abort();
1368}
1369
bellard641d5fb2008-05-25 17:24:00 +00001370/* save a temporary to memory. 'allocated_regs' is used in case a
1371 temporary registers needs to be allocated to store a constant. */
1372static void temp_save(TCGContext *s, int temp, TCGRegSet allocated_regs)
1373{
1374 TCGTemp *ts;
1375 int reg;
1376
1377 ts = &s->temps[temp];
1378 if (!ts->fixed_reg) {
1379 switch(ts->val_type) {
1380 case TEMP_VAL_REG:
1381 tcg_reg_free(s, ts->reg);
1382 break;
1383 case TEMP_VAL_DEAD:
1384 ts->val_type = TEMP_VAL_MEM;
1385 break;
1386 case TEMP_VAL_CONST:
Aurelien Jarnod6859202009-09-30 14:16:12 +02001387 reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],
1388 allocated_regs);
bellard641d5fb2008-05-25 17:24:00 +00001389 if (!ts->mem_allocated)
1390 temp_allocate_frame(s, temp);
Aurelien Jarnod6859202009-09-30 14:16:12 +02001391 tcg_out_movi(s, ts->type, reg, ts->val);
1392 tcg_out_st(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
bellard641d5fb2008-05-25 17:24:00 +00001393 ts->val_type = TEMP_VAL_MEM;
1394 break;
1395 case TEMP_VAL_MEM:
1396 break;
1397 default:
1398 tcg_abort();
1399 }
1400 }
1401}
1402
bellarde5097dc2008-05-21 16:24:20 +00001403/* save globals to their cannonical location and assume they can be
bellarde8996ee2008-05-23 17:33:39 +00001404 modified be the following code. 'allocated_regs' is used in case a
1405 temporary registers needs to be allocated to store a constant. */
1406static void save_globals(TCGContext *s, TCGRegSet allocated_regs)
bellardc896fe22008-02-01 10:05:41 +00001407{
bellard641d5fb2008-05-25 17:24:00 +00001408 int i;
bellardc896fe22008-02-01 10:05:41 +00001409
1410 for(i = 0; i < s->nb_globals; i++) {
bellard641d5fb2008-05-25 17:24:00 +00001411 temp_save(s, i, allocated_regs);
bellardc896fe22008-02-01 10:05:41 +00001412 }
bellarde5097dc2008-05-21 16:24:20 +00001413}
1414
1415/* at the end of a basic block, we assume all temporaries are dead and
bellarde8996ee2008-05-23 17:33:39 +00001416 all globals are stored at their canonical location. */
1417static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs)
bellarde5097dc2008-05-21 16:24:20 +00001418{
1419 TCGTemp *ts;
1420 int i;
1421
bellardc896fe22008-02-01 10:05:41 +00001422 for(i = s->nb_globals; i < s->nb_temps; i++) {
1423 ts = &s->temps[i];
bellard641d5fb2008-05-25 17:24:00 +00001424 if (ts->temp_local) {
1425 temp_save(s, i, allocated_regs);
1426 } else {
1427 if (ts->val_type == TEMP_VAL_REG) {
1428 s->reg_to_temp[ts->reg] = -1;
1429 }
1430 ts->val_type = TEMP_VAL_DEAD;
bellardc896fe22008-02-01 10:05:41 +00001431 }
1432 }
bellarde8996ee2008-05-23 17:33:39 +00001433
1434 save_globals(s, allocated_regs);
bellardc896fe22008-02-01 10:05:41 +00001435}
1436
1437#define IS_DEAD_IARG(n) ((dead_iargs >> (n)) & 1)
1438
bellarde8996ee2008-05-23 17:33:39 +00001439static void tcg_reg_alloc_movi(TCGContext *s, const TCGArg *args)
1440{
1441 TCGTemp *ots;
1442 tcg_target_ulong val;
1443
1444 ots = &s->temps[args[0]];
1445 val = args[1];
1446
1447 if (ots->fixed_reg) {
1448 /* for fixed registers, we do not do any constant
1449 propagation */
1450 tcg_out_movi(s, ots->type, ots->reg, val);
1451 } else {
ths1235fc02008-06-03 19:51:57 +00001452 /* The movi is not explicitly generated here */
bellarde8996ee2008-05-23 17:33:39 +00001453 if (ots->val_type == TEMP_VAL_REG)
1454 s->reg_to_temp[ots->reg] = -1;
1455 ots->val_type = TEMP_VAL_CONST;
1456 ots->val = val;
1457 }
1458}
1459
bellardc896fe22008-02-01 10:05:41 +00001460static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def,
1461 const TCGArg *args,
1462 unsigned int dead_iargs)
1463{
1464 TCGTemp *ts, *ots;
1465 int reg;
1466 const TCGArgConstraint *arg_ct;
1467
1468 ots = &s->temps[args[0]];
1469 ts = &s->temps[args[1]];
1470 arg_ct = &def->args_ct[0];
1471
bellarde8996ee2008-05-23 17:33:39 +00001472 /* XXX: always mark arg dead if IS_DEAD_IARG(0) */
bellardc896fe22008-02-01 10:05:41 +00001473 if (ts->val_type == TEMP_VAL_REG) {
1474 if (IS_DEAD_IARG(0) && !ts->fixed_reg && !ots->fixed_reg) {
1475 /* the mov can be suppressed */
1476 if (ots->val_type == TEMP_VAL_REG)
1477 s->reg_to_temp[ots->reg] = -1;
1478 reg = ts->reg;
1479 s->reg_to_temp[reg] = -1;
1480 ts->val_type = TEMP_VAL_DEAD;
1481 } else {
1482 if (ots->val_type == TEMP_VAL_REG) {
1483 reg = ots->reg;
1484 } else {
1485 reg = tcg_reg_alloc(s, arg_ct->u.regs, s->reserved_regs);
1486 }
1487 if (ts->reg != reg) {
1488 tcg_out_mov(s, reg, ts->reg);
1489 }
1490 }
1491 } else if (ts->val_type == TEMP_VAL_MEM) {
1492 if (ots->val_type == TEMP_VAL_REG) {
1493 reg = ots->reg;
1494 } else {
1495 reg = tcg_reg_alloc(s, arg_ct->u.regs, s->reserved_regs);
1496 }
blueswir1e4d54342008-03-13 17:34:19 +00001497 tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
bellardc896fe22008-02-01 10:05:41 +00001498 } else if (ts->val_type == TEMP_VAL_CONST) {
bellarde8996ee2008-05-23 17:33:39 +00001499 if (ots->fixed_reg) {
bellardc896fe22008-02-01 10:05:41 +00001500 reg = ots->reg;
bellarde8996ee2008-05-23 17:33:39 +00001501 tcg_out_movi(s, ots->type, reg, ts->val);
bellardc896fe22008-02-01 10:05:41 +00001502 } else {
bellarde8996ee2008-05-23 17:33:39 +00001503 /* propagate constant */
1504 if (ots->val_type == TEMP_VAL_REG)
1505 s->reg_to_temp[ots->reg] = -1;
1506 ots->val_type = TEMP_VAL_CONST;
1507 ots->val = ts->val;
1508 return;
bellardc896fe22008-02-01 10:05:41 +00001509 }
bellardc896fe22008-02-01 10:05:41 +00001510 } else {
1511 tcg_abort();
1512 }
1513 s->reg_to_temp[reg] = args[0];
1514 ots->reg = reg;
1515 ots->val_type = TEMP_VAL_REG;
1516 ots->mem_coherent = 0;
1517}
1518
1519static void tcg_reg_alloc_op(TCGContext *s,
1520 const TCGOpDef *def, int opc,
1521 const TCGArg *args,
1522 unsigned int dead_iargs)
1523{
1524 TCGRegSet allocated_regs;
1525 int i, k, nb_iargs, nb_oargs, reg;
1526 TCGArg arg;
1527 const TCGArgConstraint *arg_ct;
1528 TCGTemp *ts;
1529 TCGArg new_args[TCG_MAX_OP_ARGS];
1530 int const_args[TCG_MAX_OP_ARGS];
1531
1532 nb_oargs = def->nb_oargs;
1533 nb_iargs = def->nb_iargs;
1534
1535 /* copy constants */
1536 memcpy(new_args + nb_oargs + nb_iargs,
1537 args + nb_oargs + nb_iargs,
1538 sizeof(TCGArg) * def->nb_cargs);
1539
1540 /* satisfy input constraints */
1541 tcg_regset_set(allocated_regs, s->reserved_regs);
1542 for(k = 0; k < nb_iargs; k++) {
1543 i = def->sorted_args[nb_oargs + k];
1544 arg = args[i];
1545 arg_ct = &def->args_ct[i];
1546 ts = &s->temps[arg];
1547 if (ts->val_type == TEMP_VAL_MEM) {
1548 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
blueswir1e4d54342008-03-13 17:34:19 +00001549 tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
bellardc896fe22008-02-01 10:05:41 +00001550 ts->val_type = TEMP_VAL_REG;
1551 ts->reg = reg;
1552 ts->mem_coherent = 1;
1553 s->reg_to_temp[reg] = arg;
1554 } else if (ts->val_type == TEMP_VAL_CONST) {
1555 if (tcg_target_const_match(ts->val, arg_ct)) {
1556 /* constant is OK for instruction */
1557 const_args[i] = 1;
1558 new_args[i] = ts->val;
1559 goto iarg_end;
1560 } else {
bellarde8996ee2008-05-23 17:33:39 +00001561 /* need to move to a register */
bellardc896fe22008-02-01 10:05:41 +00001562 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1563 tcg_out_movi(s, ts->type, reg, ts->val);
bellarde8996ee2008-05-23 17:33:39 +00001564 ts->val_type = TEMP_VAL_REG;
1565 ts->reg = reg;
1566 ts->mem_coherent = 0;
1567 s->reg_to_temp[reg] = arg;
bellardc896fe22008-02-01 10:05:41 +00001568 }
1569 }
1570 assert(ts->val_type == TEMP_VAL_REG);
bellard5ff9d6a2008-02-04 00:37:54 +00001571 if (arg_ct->ct & TCG_CT_IALIAS) {
1572 if (ts->fixed_reg) {
1573 /* if fixed register, we must allocate a new register
1574 if the alias is not the same register */
1575 if (arg != args[arg_ct->alias_index])
1576 goto allocate_in_reg;
1577 } else {
1578 /* if the input is aliased to an output and if it is
1579 not dead after the instruction, we must allocate
1580 a new register and move it */
1581 if (!IS_DEAD_IARG(i - nb_oargs))
1582 goto allocate_in_reg;
1583 }
bellardc896fe22008-02-01 10:05:41 +00001584 }
1585 reg = ts->reg;
1586 if (tcg_regset_test_reg(arg_ct->u.regs, reg)) {
1587 /* nothing to do : the constraint is satisfied */
1588 } else {
1589 allocate_in_reg:
1590 /* allocate a new register matching the constraint
1591 and move the temporary register into it */
1592 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1593 tcg_out_mov(s, reg, ts->reg);
1594 }
bellardc896fe22008-02-01 10:05:41 +00001595 new_args[i] = reg;
1596 const_args[i] = 0;
1597 tcg_regset_set_reg(allocated_regs, reg);
1598 iarg_end: ;
1599 }
1600
bellarde8996ee2008-05-23 17:33:39 +00001601 if (def->flags & TCG_OPF_BB_END) {
1602 tcg_reg_alloc_bb_end(s, allocated_regs);
1603 } else {
1604 /* mark dead temporaries and free the associated registers */
1605 for(i = 0; i < nb_iargs; i++) {
1606 arg = args[nb_oargs + i];
1607 if (IS_DEAD_IARG(i)) {
1608 ts = &s->temps[arg];
1609 if (!ts->fixed_reg) {
1610 if (ts->val_type == TEMP_VAL_REG)
1611 s->reg_to_temp[ts->reg] = -1;
1612 ts->val_type = TEMP_VAL_DEAD;
1613 }
1614 }
1615 }
1616
1617 if (def->flags & TCG_OPF_CALL_CLOBBER) {
1618 /* XXX: permit generic clobber register list ? */
1619 for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
1620 if (tcg_regset_test_reg(tcg_target_call_clobber_regs, reg)) {
1621 tcg_reg_free(s, reg);
1622 }
1623 }
1624 /* XXX: for load/store we could do that only for the slow path
1625 (i.e. when a memory callback is called) */
1626
1627 /* store globals and free associated registers (we assume the insn
1628 can modify any global. */
1629 save_globals(s, allocated_regs);
1630 }
1631
1632 /* satisfy the output constraints */
1633 tcg_regset_set(allocated_regs, s->reserved_regs);
1634 for(k = 0; k < nb_oargs; k++) {
1635 i = def->sorted_args[k];
1636 arg = args[i];
1637 arg_ct = &def->args_ct[i];
bellardc896fe22008-02-01 10:05:41 +00001638 ts = &s->temps[arg];
bellarde8996ee2008-05-23 17:33:39 +00001639 if (arg_ct->ct & TCG_CT_ALIAS) {
1640 reg = new_args[arg_ct->alias_index];
1641 } else {
1642 /* if fixed register, we try to use it */
1643 reg = ts->reg;
1644 if (ts->fixed_reg &&
1645 tcg_regset_test_reg(arg_ct->u.regs, reg)) {
1646 goto oarg_end;
1647 }
1648 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1649 }
1650 tcg_regset_set_reg(allocated_regs, reg);
1651 /* if a fixed register is used, then a move will be done afterwards */
1652 if (!ts->fixed_reg) {
bellardc896fe22008-02-01 10:05:41 +00001653 if (ts->val_type == TEMP_VAL_REG)
1654 s->reg_to_temp[ts->reg] = -1;
bellarde8996ee2008-05-23 17:33:39 +00001655 ts->val_type = TEMP_VAL_REG;
1656 ts->reg = reg;
1657 /* temp value is modified, so the value kept in memory is
1658 potentially not the same */
1659 ts->mem_coherent = 0;
1660 s->reg_to_temp[reg] = arg;
bellardc896fe22008-02-01 10:05:41 +00001661 }
bellarde8996ee2008-05-23 17:33:39 +00001662 oarg_end:
1663 new_args[i] = reg;
bellardc896fe22008-02-01 10:05:41 +00001664 }
1665 }
1666
bellardc896fe22008-02-01 10:05:41 +00001667 /* emit instruction */
1668 tcg_out_op(s, opc, new_args, const_args);
1669
1670 /* move the outputs in the correct register if needed */
1671 for(i = 0; i < nb_oargs; i++) {
1672 ts = &s->temps[args[i]];
1673 reg = new_args[i];
1674 if (ts->fixed_reg && ts->reg != reg) {
1675 tcg_out_mov(s, ts->reg, reg);
1676 }
1677 }
1678}
1679
bellardb03cce82008-05-10 10:52:05 +00001680#ifdef TCG_TARGET_STACK_GROWSUP
1681#define STACK_DIR(x) (-(x))
1682#else
1683#define STACK_DIR(x) (x)
1684#endif
1685
bellardc896fe22008-02-01 10:05:41 +00001686static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def,
1687 int opc, const TCGArg *args,
1688 unsigned int dead_iargs)
1689{
1690 int nb_iargs, nb_oargs, flags, nb_regs, i, reg, nb_params;
1691 TCGArg arg, func_arg;
1692 TCGTemp *ts;
aurel32f54b3f92008-04-12 20:14:54 +00001693 tcg_target_long stack_offset, call_stack_size, func_addr;
bellardb03cce82008-05-10 10:52:05 +00001694 int const_func_arg, allocate_args;
bellardc896fe22008-02-01 10:05:41 +00001695 TCGRegSet allocated_regs;
1696 const TCGArgConstraint *arg_ct;
1697
1698 arg = *args++;
1699
1700 nb_oargs = arg >> 16;
1701 nb_iargs = arg & 0xffff;
1702 nb_params = nb_iargs - 1;
1703
1704 flags = args[nb_oargs + nb_iargs];
1705
1706 nb_regs = tcg_target_get_call_iarg_regs_count(flags);
1707 if (nb_regs > nb_params)
1708 nb_regs = nb_params;
1709
1710 /* assign stack slots first */
1711 /* XXX: preallocate call stack */
1712 call_stack_size = (nb_params - nb_regs) * sizeof(tcg_target_long);
1713 call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) &
1714 ~(TCG_TARGET_STACK_ALIGN - 1);
bellardb03cce82008-05-10 10:52:05 +00001715 allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE);
1716 if (allocate_args) {
1717 tcg_out_addi(s, TCG_REG_CALL_STACK, -STACK_DIR(call_stack_size));
1718 }
bellard39cf05d2008-05-22 14:59:57 +00001719
1720 stack_offset = TCG_TARGET_CALL_STACK_OFFSET;
bellardc896fe22008-02-01 10:05:41 +00001721 for(i = nb_regs; i < nb_params; i++) {
1722 arg = args[nb_oargs + i];
bellard39cf05d2008-05-22 14:59:57 +00001723#ifdef TCG_TARGET_STACK_GROWSUP
1724 stack_offset -= sizeof(tcg_target_long);
1725#endif
1726 if (arg != TCG_CALL_DUMMY_ARG) {
1727 ts = &s->temps[arg];
1728 if (ts->val_type == TEMP_VAL_REG) {
1729 tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, stack_offset);
1730 } else if (ts->val_type == TEMP_VAL_MEM) {
1731 reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],
1732 s->reserved_regs);
1733 /* XXX: not correct if reading values from the stack */
1734 tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1735 tcg_out_st(s, ts->type, reg, TCG_REG_CALL_STACK, stack_offset);
1736 } else if (ts->val_type == TEMP_VAL_CONST) {
1737 reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],
1738 s->reserved_regs);
1739 /* XXX: sign extend may be needed on some targets */
1740 tcg_out_movi(s, ts->type, reg, ts->val);
1741 tcg_out_st(s, ts->type, reg, TCG_REG_CALL_STACK, stack_offset);
1742 } else {
1743 tcg_abort();
1744 }
bellardc896fe22008-02-01 10:05:41 +00001745 }
bellard39cf05d2008-05-22 14:59:57 +00001746#ifndef TCG_TARGET_STACK_GROWSUP
1747 stack_offset += sizeof(tcg_target_long);
1748#endif
bellardc896fe22008-02-01 10:05:41 +00001749 }
1750
1751 /* assign input registers */
1752 tcg_regset_set(allocated_regs, s->reserved_regs);
1753 for(i = 0; i < nb_regs; i++) {
1754 arg = args[nb_oargs + i];
bellard39cf05d2008-05-22 14:59:57 +00001755 if (arg != TCG_CALL_DUMMY_ARG) {
1756 ts = &s->temps[arg];
1757 reg = tcg_target_call_iarg_regs[i];
1758 tcg_reg_free(s, reg);
1759 if (ts->val_type == TEMP_VAL_REG) {
1760 if (ts->reg != reg) {
1761 tcg_out_mov(s, reg, ts->reg);
1762 }
1763 } else if (ts->val_type == TEMP_VAL_MEM) {
1764 tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1765 } else if (ts->val_type == TEMP_VAL_CONST) {
1766 /* XXX: sign extend ? */
1767 tcg_out_movi(s, ts->type, reg, ts->val);
1768 } else {
1769 tcg_abort();
bellardc896fe22008-02-01 10:05:41 +00001770 }
bellard39cf05d2008-05-22 14:59:57 +00001771 tcg_regset_set_reg(allocated_regs, reg);
bellardc896fe22008-02-01 10:05:41 +00001772 }
bellardc896fe22008-02-01 10:05:41 +00001773 }
1774
1775 /* assign function address */
1776 func_arg = args[nb_oargs + nb_iargs - 1];
1777 arg_ct = &def->args_ct[0];
1778 ts = &s->temps[func_arg];
aurel32f54b3f92008-04-12 20:14:54 +00001779 func_addr = ts->val;
bellardc896fe22008-02-01 10:05:41 +00001780 const_func_arg = 0;
1781 if (ts->val_type == TEMP_VAL_MEM) {
1782 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
blueswir1e4d54342008-03-13 17:34:19 +00001783 tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
bellardc896fe22008-02-01 10:05:41 +00001784 func_arg = reg;
bellarde8996ee2008-05-23 17:33:39 +00001785 tcg_regset_set_reg(allocated_regs, reg);
bellardc896fe22008-02-01 10:05:41 +00001786 } else if (ts->val_type == TEMP_VAL_REG) {
1787 reg = ts->reg;
1788 if (!tcg_regset_test_reg(arg_ct->u.regs, reg)) {
1789 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1790 tcg_out_mov(s, reg, ts->reg);
1791 }
1792 func_arg = reg;
bellarde8996ee2008-05-23 17:33:39 +00001793 tcg_regset_set_reg(allocated_regs, reg);
bellardc896fe22008-02-01 10:05:41 +00001794 } else if (ts->val_type == TEMP_VAL_CONST) {
aurel32f54b3f92008-04-12 20:14:54 +00001795 if (tcg_target_const_match(func_addr, arg_ct)) {
bellardc896fe22008-02-01 10:05:41 +00001796 const_func_arg = 1;
aurel32f54b3f92008-04-12 20:14:54 +00001797 func_arg = func_addr;
bellardc896fe22008-02-01 10:05:41 +00001798 } else {
1799 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
aurel32f54b3f92008-04-12 20:14:54 +00001800 tcg_out_movi(s, ts->type, reg, func_addr);
bellardc896fe22008-02-01 10:05:41 +00001801 func_arg = reg;
bellarde8996ee2008-05-23 17:33:39 +00001802 tcg_regset_set_reg(allocated_regs, reg);
bellardc896fe22008-02-01 10:05:41 +00001803 }
1804 } else {
1805 tcg_abort();
1806 }
bellarde8996ee2008-05-23 17:33:39 +00001807
bellardc896fe22008-02-01 10:05:41 +00001808
1809 /* mark dead temporaries and free the associated registers */
bellardc6e113f2008-05-17 12:42:15 +00001810 for(i = 0; i < nb_iargs; i++) {
bellardc896fe22008-02-01 10:05:41 +00001811 arg = args[nb_oargs + i];
1812 if (IS_DEAD_IARG(i)) {
1813 ts = &s->temps[arg];
bellarde8996ee2008-05-23 17:33:39 +00001814 if (!ts->fixed_reg) {
bellardc896fe22008-02-01 10:05:41 +00001815 if (ts->val_type == TEMP_VAL_REG)
1816 s->reg_to_temp[ts->reg] = -1;
1817 ts->val_type = TEMP_VAL_DEAD;
1818 }
1819 }
1820 }
1821
1822 /* clobber call registers */
1823 for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
1824 if (tcg_regset_test_reg(tcg_target_call_clobber_regs, reg)) {
1825 tcg_reg_free(s, reg);
1826 }
1827 }
1828
1829 /* store globals and free associated registers (we assume the call
1830 can modify any global. */
aurel32b9c18f52009-04-06 12:33:59 +00001831 if (!(flags & TCG_CALL_CONST)) {
1832 save_globals(s, allocated_regs);
1833 }
bellardc896fe22008-02-01 10:05:41 +00001834
1835 tcg_out_op(s, opc, &func_arg, &const_func_arg);
1836
bellardb03cce82008-05-10 10:52:05 +00001837 if (allocate_args) {
1838 tcg_out_addi(s, TCG_REG_CALL_STACK, STACK_DIR(call_stack_size));
1839 }
bellardc896fe22008-02-01 10:05:41 +00001840
1841 /* assign output registers and emit moves if needed */
1842 for(i = 0; i < nb_oargs; i++) {
1843 arg = args[i];
1844 ts = &s->temps[arg];
1845 reg = tcg_target_call_oarg_regs[i];
bellarde8996ee2008-05-23 17:33:39 +00001846 assert(s->reg_to_temp[reg] == -1);
bellardc896fe22008-02-01 10:05:41 +00001847 if (ts->fixed_reg) {
1848 if (ts->reg != reg) {
1849 tcg_out_mov(s, ts->reg, reg);
1850 }
1851 } else {
1852 if (ts->val_type == TEMP_VAL_REG)
1853 s->reg_to_temp[ts->reg] = -1;
1854 ts->val_type = TEMP_VAL_REG;
1855 ts->reg = reg;
1856 ts->mem_coherent = 0;
1857 s->reg_to_temp[reg] = arg;
1858 }
1859 }
1860
1861 return nb_iargs + nb_oargs + def->nb_cargs + 1;
1862}
1863
1864#ifdef CONFIG_PROFILER
1865
aurel3254604f72008-12-07 20:35:00 +00001866static int64_t tcg_table_op_count[NB_OPS];
bellardc896fe22008-02-01 10:05:41 +00001867
Blue Swirl871e6c32009-07-21 12:18:03 +00001868static void dump_op_count(void)
bellardc896fe22008-02-01 10:05:41 +00001869{
1870 int i;
1871 FILE *f;
aurel3254604f72008-12-07 20:35:00 +00001872 f = fopen("/tmp/op.log", "w");
bellardc896fe22008-02-01 10:05:41 +00001873 for(i = INDEX_op_end; i < NB_OPS; i++) {
aurel3254604f72008-12-07 20:35:00 +00001874 fprintf(f, "%s %" PRId64 "\n", tcg_op_defs[i].name, tcg_table_op_count[i]);
bellardc896fe22008-02-01 10:05:41 +00001875 }
1876 fclose(f);
1877}
1878#endif
1879
1880
1881static inline int tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf,
pbrook2ba1eeb2008-02-10 02:41:15 +00001882 long search_pc)
bellardc896fe22008-02-01 10:05:41 +00001883{
bellardb314f272008-05-25 18:21:31 +00001884 int opc, op_index;
bellardc896fe22008-02-01 10:05:41 +00001885 const TCGOpDef *def;
1886 unsigned int dead_iargs;
1887 const TCGArg *args;
1888
1889#ifdef DEBUG_DISAS
aliguori8fec2b82009-01-15 22:36:53 +00001890 if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP))) {
aliguori93fcfe32009-01-15 22:34:14 +00001891 qemu_log("OP:\n");
bellardc896fe22008-02-01 10:05:41 +00001892 tcg_dump_ops(s, logfile);
aliguori93fcfe32009-01-15 22:34:14 +00001893 qemu_log("\n");
bellardc896fe22008-02-01 10:05:41 +00001894 }
1895#endif
1896
bellarda23a9ec2008-05-23 09:52:20 +00001897#ifdef CONFIG_PROFILER
1898 s->la_time -= profile_getclock();
1899#endif
bellardc896fe22008-02-01 10:05:41 +00001900 tcg_liveness_analysis(s);
bellarda23a9ec2008-05-23 09:52:20 +00001901#ifdef CONFIG_PROFILER
1902 s->la_time += profile_getclock();
1903#endif
bellardc896fe22008-02-01 10:05:41 +00001904
1905#ifdef DEBUG_DISAS
aliguori8fec2b82009-01-15 22:36:53 +00001906 if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT))) {
Aurelien Jarno6a957022009-10-07 07:53:41 +02001907 qemu_log("OP after liveness analysis:\n");
bellardc896fe22008-02-01 10:05:41 +00001908 tcg_dump_ops(s, logfile);
aliguori93fcfe32009-01-15 22:34:14 +00001909 qemu_log("\n");
bellardc896fe22008-02-01 10:05:41 +00001910 }
1911#endif
1912
1913 tcg_reg_alloc_start(s);
1914
1915 s->code_buf = gen_code_buf;
1916 s->code_ptr = gen_code_buf;
1917
bellardc896fe22008-02-01 10:05:41 +00001918 args = gen_opparam_buf;
1919 op_index = 0;
blueswir1b3db8752008-03-08 13:33:42 +00001920
bellardc896fe22008-02-01 10:05:41 +00001921 for(;;) {
1922 opc = gen_opc_buf[op_index];
1923#ifdef CONFIG_PROFILER
aurel3254604f72008-12-07 20:35:00 +00001924 tcg_table_op_count[opc]++;
bellardc896fe22008-02-01 10:05:41 +00001925#endif
1926 def = &tcg_op_defs[opc];
1927#if 0
1928 printf("%s: %d %d %d\n", def->name,
1929 def->nb_oargs, def->nb_iargs, def->nb_cargs);
1930 // dump_regs(s);
1931#endif
1932 switch(opc) {
1933 case INDEX_op_mov_i32:
1934#if TCG_TARGET_REG_BITS == 64
1935 case INDEX_op_mov_i64:
1936#endif
1937 dead_iargs = s->op_dead_iargs[op_index];
1938 tcg_reg_alloc_mov(s, def, args, dead_iargs);
1939 break;
bellarde8996ee2008-05-23 17:33:39 +00001940 case INDEX_op_movi_i32:
1941#if TCG_TARGET_REG_BITS == 64
1942 case INDEX_op_movi_i64:
1943#endif
1944 tcg_reg_alloc_movi(s, args);
1945 break;
bellard7e4597d2008-05-22 16:56:05 +00001946 case INDEX_op_debug_insn_start:
1947 /* debug instruction */
1948 break;
bellardc896fe22008-02-01 10:05:41 +00001949 case INDEX_op_nop:
1950 case INDEX_op_nop1:
1951 case INDEX_op_nop2:
1952 case INDEX_op_nop3:
1953 break;
1954 case INDEX_op_nopn:
1955 args += args[0];
1956 goto next;
bellard5ff9d6a2008-02-04 00:37:54 +00001957 case INDEX_op_discard:
1958 {
1959 TCGTemp *ts;
1960 ts = &s->temps[args[0]];
1961 /* mark the temporary as dead */
bellarde8996ee2008-05-23 17:33:39 +00001962 if (!ts->fixed_reg) {
bellard5ff9d6a2008-02-04 00:37:54 +00001963 if (ts->val_type == TEMP_VAL_REG)
1964 s->reg_to_temp[ts->reg] = -1;
1965 ts->val_type = TEMP_VAL_DEAD;
1966 }
1967 }
1968 break;
bellardc896fe22008-02-01 10:05:41 +00001969 case INDEX_op_set_label:
bellarde8996ee2008-05-23 17:33:39 +00001970 tcg_reg_alloc_bb_end(s, s->reserved_regs);
bellardc896fe22008-02-01 10:05:41 +00001971 tcg_out_label(s, args[0], (long)s->code_ptr);
1972 break;
1973 case INDEX_op_call:
1974 dead_iargs = s->op_dead_iargs[op_index];
1975 args += tcg_reg_alloc_call(s, def, opc, args, dead_iargs);
1976 goto next;
1977 case INDEX_op_end:
1978 goto the_end;
bellardc896fe22008-02-01 10:05:41 +00001979 default:
1980 /* Note: in order to speed up the code, it would be much
1981 faster to have specialized register allocator functions for
1982 some common argument patterns */
1983 dead_iargs = s->op_dead_iargs[op_index];
1984 tcg_reg_alloc_op(s, def, opc, args, dead_iargs);
1985 break;
1986 }
1987 args += def->nb_args;
ths8df1ca42008-06-11 11:03:34 +00001988 next:
pbrook2ba1eeb2008-02-10 02:41:15 +00001989 if (search_pc >= 0 && search_pc < s->code_ptr - gen_code_buf) {
bellardb314f272008-05-25 18:21:31 +00001990 return op_index;
bellardc896fe22008-02-01 10:05:41 +00001991 }
1992 op_index++;
1993#ifndef NDEBUG
1994 check_regs(s);
1995#endif
1996 }
1997 the_end:
1998 return -1;
1999}
2000
aurel3254604f72008-12-07 20:35:00 +00002001int tcg_gen_code(TCGContext *s, uint8_t *gen_code_buf)
bellardc896fe22008-02-01 10:05:41 +00002002{
2003#ifdef CONFIG_PROFILER
2004 {
bellardc896fe22008-02-01 10:05:41 +00002005 int n;
2006 n = (gen_opc_ptr - gen_opc_buf);
bellarda23a9ec2008-05-23 09:52:20 +00002007 s->op_count += n;
2008 if (n > s->op_count_max)
2009 s->op_count_max = n;
2010
2011 s->temp_count += s->nb_temps;
2012 if (s->nb_temps > s->temp_count_max)
2013 s->temp_count_max = s->nb_temps;
bellardc896fe22008-02-01 10:05:41 +00002014 }
2015#endif
2016
pbrook2ba1eeb2008-02-10 02:41:15 +00002017 tcg_gen_code_common(s, gen_code_buf, -1);
bellardc896fe22008-02-01 10:05:41 +00002018
2019 /* flush instruction cache */
2020 flush_icache_range((unsigned long)gen_code_buf,
2021 (unsigned long)s->code_ptr);
2022 return s->code_ptr - gen_code_buf;
2023}
2024
pbrook2ba1eeb2008-02-10 02:41:15 +00002025/* Return the index of the micro operation such as the pc after is <
pbrook623e2652008-02-10 14:09:09 +00002026 offset bytes from the start of the TB. The contents of gen_code_buf must
2027 not be changed, though writing the same values is ok.
2028 Return -1 if not found. */
aurel3254604f72008-12-07 20:35:00 +00002029int tcg_gen_code_search_pc(TCGContext *s, uint8_t *gen_code_buf, long offset)
bellardc896fe22008-02-01 10:05:41 +00002030{
pbrook623e2652008-02-10 14:09:09 +00002031 return tcg_gen_code_common(s, gen_code_buf, offset);
bellardc896fe22008-02-01 10:05:41 +00002032}
bellarda23a9ec2008-05-23 09:52:20 +00002033
2034#ifdef CONFIG_PROFILER
2035void tcg_dump_info(FILE *f,
2036 int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
2037{
2038 TCGContext *s = &tcg_ctx;
2039 int64_t tot;
2040
2041 tot = s->interm_time + s->code_time;
2042 cpu_fprintf(f, "JIT cycles %" PRId64 " (%0.3f s at 2.4 GHz)\n",
2043 tot, tot / 2.4e9);
2044 cpu_fprintf(f, "translated TBs %" PRId64 " (aborted=%" PRId64 " %0.1f%%)\n",
2045 s->tb_count,
2046 s->tb_count1 - s->tb_count,
2047 s->tb_count1 ? (double)(s->tb_count1 - s->tb_count) / s->tb_count1 * 100.0 : 0);
2048 cpu_fprintf(f, "avg ops/TB %0.1f max=%d\n",
2049 s->tb_count ? (double)s->op_count / s->tb_count : 0, s->op_count_max);
bellarda23a9ec2008-05-23 09:52:20 +00002050 cpu_fprintf(f, "deleted ops/TB %0.2f\n",
2051 s->tb_count ?
2052 (double)s->del_op_count / s->tb_count : 0);
2053 cpu_fprintf(f, "avg temps/TB %0.2f max=%d\n",
2054 s->tb_count ?
2055 (double)s->temp_count / s->tb_count : 0,
2056 s->temp_count_max);
2057
2058 cpu_fprintf(f, "cycles/op %0.1f\n",
2059 s->op_count ? (double)tot / s->op_count : 0);
2060 cpu_fprintf(f, "cycles/in byte %0.1f\n",
2061 s->code_in_len ? (double)tot / s->code_in_len : 0);
2062 cpu_fprintf(f, "cycles/out byte %0.1f\n",
2063 s->code_out_len ? (double)tot / s->code_out_len : 0);
2064 if (tot == 0)
2065 tot = 1;
2066 cpu_fprintf(f, " gen_interm time %0.1f%%\n",
2067 (double)s->interm_time / tot * 100.0);
2068 cpu_fprintf(f, " gen_code time %0.1f%%\n",
2069 (double)s->code_time / tot * 100.0);
2070 cpu_fprintf(f, "liveness/code time %0.1f%%\n",
2071 (double)s->la_time / (s->code_time ? s->code_time : 1) * 100.0);
2072 cpu_fprintf(f, "cpu_restore count %" PRId64 "\n",
2073 s->restore_count);
2074 cpu_fprintf(f, " avg cycles %0.1f\n",
2075 s->restore_count ? (double)s->restore_time / s->restore_count : 0);
Blue Swirl871e6c32009-07-21 12:18:03 +00002076
2077 dump_op_count();
bellarda23a9ec2008-05-23 09:52:20 +00002078}
2079#else
bellard24bf7b32008-05-23 11:58:32 +00002080void tcg_dump_info(FILE *f,
bellarda23a9ec2008-05-23 09:52:20 +00002081 int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
2082{
bellard24bf7b32008-05-23 11:58:32 +00002083 cpu_fprintf(f, "[TCG profiler not compiled]\n");
bellarda23a9ec2008-05-23 09:52:20 +00002084}
2085#endif