VirtualBox

source: vbox/trunk/src/recompiler/tcg/tcg.c@ 37675

Last change on this file since 37675 was 37675, checked in by vboxsync, 13 years ago

rem: Synced with v0.12.5.

  • Property svn:eol-style set to native
File size: 62.9 KB
Line 
1/*
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
25/* define it to use liveness analysis (better code) */
26#define USE_LIVENESS_ANALYSIS
27
28#include "config.h"
29
30#ifndef CONFIG_DEBUG_TCG
31/* define it to suppress various consistency checks (faster) */
32#define NDEBUG
33#endif
34
35#ifndef VBOX
36#include <stdarg.h>
37#include <stdlib.h>
38#include <stdio.h>
39#include <string.h>
40#include <inttypes.h>
41#ifdef _WIN32
42#include <malloc.h>
43#endif
44#ifdef _AIX
45#include <alloca.h>
46#endif
47#else /* VBOX */
48# include <stdio.h>
49# include "osdep.h"
50#endif /* VBOX */
51
52#include "qemu-common.h"
53#include "cache-utils.h"
54#include "host-utils.h"
55
56/* Note: the long term plan is to reduce the dependancies on the QEMU
57 CPU definitions. Currently they are used for qemu_ld/st
58 instructions */
59#define NO_CPU_IO_DEFS
60#include "cpu.h"
61#include "exec-all.h"
62
63#include "tcg-op.h"
64#include "elf.h"
65
66#if defined(CONFIG_USE_GUEST_BASE) && !defined(TCG_TARGET_HAS_GUEST_BASE)
67#error GUEST_BASE not supported on this host.
68#endif
69
70#ifdef VBOX
71/*
72 * Liveness analysis doesn't work well with 32-bit hosts and 64-bit targets,
73 * second element of the register pair to store 64-bit value is considered
74 * dead, it seems.
75 * @todo: fix it in compiler
76 */
77# if defined(TARGET_X86_64) && (TCG_TARGET_REG_BITS == 32)
78# undef USE_LIVENESS_ANALYSIS
79# endif
80///* With 0.12.5 the liveness analysis does not work well even when targeting
81// 32-bit guest cpus. Just disable it wholesale to be on the safe side. */
82//#undef USE_LIVENESS_ANALYSIS
83#endif /* VBOX */
84
85static void patch_reloc(uint8_t *code_ptr, int type,
86 tcg_target_long value, tcg_target_long addend);
87
88static TCGOpDef tcg_op_defs[] = {
89#define DEF(s, n, copy_size) { #s, 0, 0, n, n, 0, copy_size },
90#ifndef VBOX
91#define DEF2(s, oargs, iargs, cargs, flags) { #s, oargs, iargs, cargs, iargs + oargs + cargs, flags, 0 },
92#else /* VBOX */
93# define DEF2(s, oargs, iargs, cargs, flags) { #s, oargs, iargs, cargs, iargs + oargs + cargs, flags, 0, 0, 0 },
94#endif /* VBOX */
95#include "tcg-opc.h"
96#undef DEF
97#undef DEF2
98};
99
100static TCGRegSet tcg_target_available_regs[2];
101static TCGRegSet tcg_target_call_clobber_regs;
102
103/* XXX: move that inside the context */
104uint16_t *gen_opc_ptr;
105TCGArg *gen_opparam_ptr;
106
107static inline void tcg_out8(TCGContext *s, uint8_t v)
108{
109 *s->code_ptr++ = v;
110}
111
112static inline void tcg_out16(TCGContext *s, uint16_t v)
113{
114 *(uint16_t *)s->code_ptr = v;
115 s->code_ptr += 2;
116}
117
118static inline void tcg_out32(TCGContext *s, uint32_t v)
119{
120 *(uint32_t *)s->code_ptr = v;
121 s->code_ptr += 4;
122}
123
124/* label relocation processing */
125
126void tcg_out_reloc(TCGContext *s, uint8_t *code_ptr, int type,
127 int label_index, long addend)
128{
129 TCGLabel *l;
130 TCGRelocation *r;
131
132 l = &s->labels[label_index];
133 if (l->has_value) {
134 /* FIXME: This may break relocations on RISC targets that
135 modify instruction fields in place. The caller may not have
136 written the initial value. */
137 patch_reloc(code_ptr, type, l->u.value, addend);
138 } else {
139 /* add a new relocation entry */
140 r = tcg_malloc(sizeof(TCGRelocation));
141 r->type = type;
142 r->ptr = code_ptr;
143 r->addend = addend;
144 r->next = l->u.first_reloc;
145 l->u.first_reloc = r;
146 }
147}
148
149static void tcg_out_label(TCGContext *s, int label_index,
150 tcg_target_long value)
151{
152 TCGLabel *l;
153 TCGRelocation *r;
154
155 l = &s->labels[label_index];
156 if (l->has_value)
157 tcg_abort();
158 r = l->u.first_reloc;
159 while (r != NULL) {
160 patch_reloc(r->ptr, r->type, value, r->addend);
161 r = r->next;
162 }
163 l->has_value = 1;
164 l->u.value = value;
165}
166
167int gen_new_label(void)
168{
169 TCGContext *s = &tcg_ctx;
170 int idx;
171 TCGLabel *l;
172
173 if (s->nb_labels >= TCG_MAX_LABELS)
174 tcg_abort();
175 idx = s->nb_labels++;
176 l = &s->labels[idx];
177 l->has_value = 0;
178 l->u.first_reloc = NULL;
179 return idx;
180}
181
182#include "tcg-target.c"
183
184/* pool based memory allocation */
185void *tcg_malloc_internal(TCGContext *s, int size)
186{
187 TCGPool *p;
188 int pool_size;
189
190 if (size > TCG_POOL_CHUNK_SIZE) {
191 /* big malloc: insert a new pool (XXX: could optimize) */
192 p = qemu_malloc(sizeof(TCGPool) + size);
193 p->size = size;
194 if (s->pool_current)
195 s->pool_current->next = p;
196 else
197 s->pool_first = p;
198 p->next = s->pool_current;
199 } else {
200 p = s->pool_current;
201 if (!p) {
202 p = s->pool_first;
203 if (!p)
204 goto new_pool;
205 } else {
206 if (!p->next) {
207 new_pool:
208 pool_size = TCG_POOL_CHUNK_SIZE;
209 p = qemu_malloc(sizeof(TCGPool) + pool_size);
210 p->size = pool_size;
211 p->next = NULL;
212 if (s->pool_current)
213 s->pool_current->next = p;
214 else
215 s->pool_first = p;
216 } else {
217 p = p->next;
218 }
219 }
220 }
221 s->pool_current = p;
222 s->pool_cur = p->data + size;
223 s->pool_end = p->data + p->size;
224 return p->data;
225}
226
227void tcg_pool_reset(TCGContext *s)
228{
229 s->pool_cur = s->pool_end = NULL;
230 s->pool_current = NULL;
231}
232
233void tcg_context_init(TCGContext *s)
234{
235 int op, total_args, n;
236 TCGOpDef *def;
237 TCGArgConstraint *args_ct;
238 int *sorted_args;
239
240 memset(s, 0, sizeof(*s));
241 s->temps = s->static_temps;
242 s->nb_globals = 0;
243
244 /* Count total number of arguments and allocate the corresponding
245 space */
246 total_args = 0;
247 for(op = 0; op < NB_OPS; op++) {
248 def = &tcg_op_defs[op];
249 n = def->nb_iargs + def->nb_oargs;
250 total_args += n;
251 }
252
253 args_ct = qemu_malloc(sizeof(TCGArgConstraint) * total_args);
254 sorted_args = qemu_malloc(sizeof(int) * total_args);
255
256 for(op = 0; op < NB_OPS; op++) {
257 def = &tcg_op_defs[op];
258 def->args_ct = args_ct;
259 def->sorted_args = sorted_args;
260 n = def->nb_iargs + def->nb_oargs;
261 sorted_args += n;
262 args_ct += n;
263 }
264
265 tcg_target_init(s);
266
267 /* init global prologue and epilogue */
268 s->code_buf = code_gen_prologue;
269 s->code_ptr = s->code_buf;
270 tcg_target_qemu_prologue(s);
271 flush_icache_range((unsigned long)s->code_buf,
272 (unsigned long)s->code_ptr);
273}
274
275void tcg_set_frame(TCGContext *s, int reg,
276 tcg_target_long start, tcg_target_long size)
277{
278 s->frame_start = start;
279 s->frame_end = start + size;
280 s->frame_reg = reg;
281}
282
283void tcg_func_start(TCGContext *s)
284{
285 int i;
286 tcg_pool_reset(s);
287 s->nb_temps = s->nb_globals;
288 for(i = 0; i < (TCG_TYPE_COUNT * 2); i++)
289 s->first_free_temp[i] = -1;
290 s->labels = tcg_malloc(sizeof(TCGLabel) * TCG_MAX_LABELS);
291 s->nb_labels = 0;
292 s->current_frame_offset = s->frame_start;
293
294 gen_opc_ptr = gen_opc_buf;
295 gen_opparam_ptr = gen_opparam_buf;
296}
297
298static inline void tcg_temp_alloc(TCGContext *s, int n)
299{
300 if (n > TCG_MAX_TEMPS)
301 tcg_abort();
302}
303
304static inline int tcg_global_reg_new_internal(TCGType type, int reg,
305 const char *name)
306{
307 TCGContext *s = &tcg_ctx;
308 TCGTemp *ts;
309 int idx;
310
311#if TCG_TARGET_REG_BITS == 32
312 if (type != TCG_TYPE_I32)
313 tcg_abort();
314#endif
315 if (tcg_regset_test_reg(s->reserved_regs, reg))
316 tcg_abort();
317 idx = s->nb_globals;
318 tcg_temp_alloc(s, s->nb_globals + 1);
319 ts = &s->temps[s->nb_globals];
320 ts->base_type = type;
321 ts->type = type;
322 ts->fixed_reg = 1;
323 ts->reg = reg;
324 ts->name = name;
325 s->nb_globals++;
326 tcg_regset_set_reg(s->reserved_regs, reg);
327 return idx;
328}
329
330TCGv_i32 tcg_global_reg_new_i32(int reg, const char *name)
331{
332 int idx;
333
334 idx = tcg_global_reg_new_internal(TCG_TYPE_I32, reg, name);
335 return MAKE_TCGV_I32(idx);
336}
337
338TCGv_i64 tcg_global_reg_new_i64(int reg, const char *name)
339{
340 int idx;
341
342 idx = tcg_global_reg_new_internal(TCG_TYPE_I64, reg, name);
343 return MAKE_TCGV_I64(idx);
344}
345
346static inline int tcg_global_mem_new_internal(TCGType type, int reg,
347 tcg_target_long offset,
348 const char *name)
349{
350 TCGContext *s = &tcg_ctx;
351 TCGTemp *ts;
352 int idx;
353
354 idx = s->nb_globals;
355#if TCG_TARGET_REG_BITS == 32
356 if (type == TCG_TYPE_I64) {
357 char buf[64];
358 tcg_temp_alloc(s, s->nb_globals + 2);
359 ts = &s->temps[s->nb_globals];
360 ts->base_type = type;
361 ts->type = TCG_TYPE_I32;
362 ts->fixed_reg = 0;
363 ts->mem_allocated = 1;
364 ts->mem_reg = reg;
365#ifdef TCG_TARGET_WORDS_BIGENDIAN
366 ts->mem_offset = offset + 4;
367#else
368 ts->mem_offset = offset;
369#endif
370 pstrcpy(buf, sizeof(buf), name);
371 pstrcat(buf, sizeof(buf), "_0");
372 ts->name = strdup(buf);
373 ts++;
374
375 ts->base_type = type;
376 ts->type = TCG_TYPE_I32;
377 ts->fixed_reg = 0;
378 ts->mem_allocated = 1;
379 ts->mem_reg = reg;
380#ifdef TCG_TARGET_WORDS_BIGENDIAN
381 ts->mem_offset = offset;
382#else
383 ts->mem_offset = offset + 4;
384#endif
385 pstrcpy(buf, sizeof(buf), name);
386 pstrcat(buf, sizeof(buf), "_1");
387 ts->name = strdup(buf);
388
389 s->nb_globals += 2;
390 } else
391#endif
392 {
393 tcg_temp_alloc(s, s->nb_globals + 1);
394 ts = &s->temps[s->nb_globals];
395 ts->base_type = type;
396 ts->type = type;
397 ts->fixed_reg = 0;
398 ts->mem_allocated = 1;
399 ts->mem_reg = reg;
400 ts->mem_offset = offset;
401 ts->name = name;
402 s->nb_globals++;
403 }
404 return idx;
405}
406
407TCGv_i32 tcg_global_mem_new_i32(int reg, tcg_target_long offset,
408 const char *name)
409{
410 int idx;
411
412 idx = tcg_global_mem_new_internal(TCG_TYPE_I32, reg, offset, name);
413 return MAKE_TCGV_I32(idx);
414}
415
416TCGv_i64 tcg_global_mem_new_i64(int reg, tcg_target_long offset,
417 const char *name)
418{
419 int idx;
420
421 idx = tcg_global_mem_new_internal(TCG_TYPE_I64, reg, offset, name);
422 return MAKE_TCGV_I64(idx);
423}
424
425static inline int tcg_temp_new_internal(TCGType type, int temp_local)
426{
427 TCGContext *s = &tcg_ctx;
428 TCGTemp *ts;
429 int idx, k;
430
431 k = type;
432 if (temp_local)
433 k += TCG_TYPE_COUNT;
434 idx = s->first_free_temp[k];
435 if (idx != -1) {
436 /* There is already an available temp with the
437 right type */
438 ts = &s->temps[idx];
439 s->first_free_temp[k] = ts->next_free_temp;
440 ts->temp_allocated = 1;
441 assert(ts->temp_local == temp_local);
442 } else {
443 idx = s->nb_temps;
444#if TCG_TARGET_REG_BITS == 32
445 if (type == TCG_TYPE_I64) {
446 tcg_temp_alloc(s, s->nb_temps + 2);
447 ts = &s->temps[s->nb_temps];
448 ts->base_type = type;
449 ts->type = TCG_TYPE_I32;
450 ts->temp_allocated = 1;
451 ts->temp_local = temp_local;
452 ts->name = NULL;
453 ts++;
454 ts->base_type = TCG_TYPE_I32;
455 ts->type = TCG_TYPE_I32;
456 ts->temp_allocated = 1;
457 ts->temp_local = temp_local;
458 ts->name = NULL;
459 s->nb_temps += 2;
460 } else
461#endif
462 {
463 tcg_temp_alloc(s, s->nb_temps + 1);
464 ts = &s->temps[s->nb_temps];
465 ts->base_type = type;
466 ts->type = type;
467 ts->temp_allocated = 1;
468 ts->temp_local = temp_local;
469 ts->name = NULL;
470 s->nb_temps++;
471 }
472 }
473 return idx;
474}
475
476TCGv_i32 tcg_temp_new_internal_i32(int temp_local)
477{
478 int idx;
479
480 idx = tcg_temp_new_internal(TCG_TYPE_I32, temp_local);
481 return MAKE_TCGV_I32(idx);
482}
483
484TCGv_i64 tcg_temp_new_internal_i64(int temp_local)
485{
486 int idx;
487
488 idx = tcg_temp_new_internal(TCG_TYPE_I64, temp_local);
489 return MAKE_TCGV_I64(idx);
490}
491
492static inline void tcg_temp_free_internal(int idx)
493{
494 TCGContext *s = &tcg_ctx;
495 TCGTemp *ts;
496 int k;
497
498 assert(idx >= s->nb_globals && idx < s->nb_temps);
499 ts = &s->temps[idx];
500 assert(ts->temp_allocated != 0);
501 ts->temp_allocated = 0;
502 k = ts->base_type;
503 if (ts->temp_local)
504 k += TCG_TYPE_COUNT;
505 ts->next_free_temp = s->first_free_temp[k];
506 s->first_free_temp[k] = idx;
507}
508
509void tcg_temp_free_i32(TCGv_i32 arg)
510{
511 tcg_temp_free_internal(GET_TCGV_I32(arg));
512}
513
514void tcg_temp_free_i64(TCGv_i64 arg)
515{
516 tcg_temp_free_internal(GET_TCGV_I64(arg));
517}
518
519TCGv_i32 tcg_const_i32(int32_t val)
520{
521 TCGv_i32 t0;
522 t0 = tcg_temp_new_i32();
523 tcg_gen_movi_i32(t0, val);
524 return t0;
525}
526
527TCGv_i64 tcg_const_i64(int64_t val)
528{
529 TCGv_i64 t0;
530 t0 = tcg_temp_new_i64();
531 tcg_gen_movi_i64(t0, val);
532 return t0;
533}
534
535TCGv_i32 tcg_const_local_i32(int32_t val)
536{
537 TCGv_i32 t0;
538 t0 = tcg_temp_local_new_i32();
539 tcg_gen_movi_i32(t0, val);
540 return t0;
541}
542
543TCGv_i64 tcg_const_local_i64(int64_t val)
544{
545 TCGv_i64 t0;
546 t0 = tcg_temp_local_new_i64();
547 tcg_gen_movi_i64(t0, val);
548 return t0;
549}
550
551void tcg_register_helper(void *func, const char *name)
552{
553 TCGContext *s = &tcg_ctx;
554 int n;
555 if ((s->nb_helpers + 1) > s->allocated_helpers) {
556 n = s->allocated_helpers;
557 if (n == 0) {
558 n = 4;
559 } else {
560 n *= 2;
561 }
562#ifdef VBOX
563 s->helpers = qemu_realloc(s->helpers, n * sizeof(TCGHelperInfo));
564#else
565 s->helpers = realloc(s->helpers, n * sizeof(TCGHelperInfo));
566#endif
567 s->allocated_helpers = n;
568 }
569 s->helpers[s->nb_helpers].func = (tcg_target_ulong)func;
570 s->helpers[s->nb_helpers].name = name;
571 s->nb_helpers++;
572}
573
574/* Note: we convert the 64 bit args to 32 bit and do some alignment
575 and endian swap. Maybe it would be better to do the alignment
576 and endian swap in tcg_reg_alloc_call(). */
577void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags,
578 int sizemask, TCGArg ret, int nargs, TCGArg *args)
579{
580 int call_type;
581 int i;
582 int real_args;
583 int nb_rets;
584 TCGArg *nparam;
585 *gen_opc_ptr++ = INDEX_op_call;
586 nparam = gen_opparam_ptr++;
587 call_type = (flags & TCG_CALL_TYPE_MASK);
588 if (ret != TCG_CALL_DUMMY_ARG) {
589#if TCG_TARGET_REG_BITS < 64
590 if (sizemask & 1) {
591#ifdef TCG_TARGET_WORDS_BIGENDIAN
592 *gen_opparam_ptr++ = ret + 1;
593 *gen_opparam_ptr++ = ret;
594#else
595 *gen_opparam_ptr++ = ret;
596 *gen_opparam_ptr++ = ret + 1;
597#endif
598 nb_rets = 2;
599 } else
600#endif
601 {
602 *gen_opparam_ptr++ = ret;
603 nb_rets = 1;
604 }
605 } else {
606 nb_rets = 0;
607 }
608 real_args = 0;
609 for (i = 0; i < nargs; i++) {
610#if TCG_TARGET_REG_BITS < 64
611 if (sizemask & (2 << i)) {
612#ifdef TCG_TARGET_I386
613 /* REGPARM case: if the third parameter is 64 bit, it is
614 allocated on the stack */
615 if (i == 2 && call_type == TCG_CALL_TYPE_REGPARM) {
616 call_type = TCG_CALL_TYPE_REGPARM_2;
617 flags = (flags & ~TCG_CALL_TYPE_MASK) | call_type;
618 }
619#endif
620#ifdef TCG_TARGET_CALL_ALIGN_ARGS
621 /* some targets want aligned 64 bit args */
622 if (real_args & 1) {
623 *gen_opparam_ptr++ = TCG_CALL_DUMMY_ARG;
624 real_args++;
625 }
626#endif
627#ifdef TCG_TARGET_WORDS_BIGENDIAN
628 *gen_opparam_ptr++ = args[i] + 1;
629 *gen_opparam_ptr++ = args[i];
630#else
631 *gen_opparam_ptr++ = args[i];
632 *gen_opparam_ptr++ = args[i] + 1;
633#endif
634 real_args += 2;
635 } else
636#endif
637 {
638 *gen_opparam_ptr++ = args[i];
639 real_args++;
640 }
641 }
642 *gen_opparam_ptr++ = GET_TCGV_PTR(func);
643
644 *gen_opparam_ptr++ = flags;
645
646 *nparam = (nb_rets << 16) | (real_args + 1);
647
648 /* total parameters, needed to go backward in the instruction stream */
649 *gen_opparam_ptr++ = 1 + nb_rets + real_args + 3;
650}
651
652#if TCG_TARGET_REG_BITS == 32
653void tcg_gen_shifti_i64(TCGv_i64 ret, TCGv_i64 arg1,
654 int c, int right, int arith)
655{
656 if (c == 0) {
657 tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg1));
658 tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1));
659 } else if (c >= 32) {
660 c -= 32;
661 if (right) {
662 if (arith) {
663 tcg_gen_sari_i32(TCGV_LOW(ret), TCGV_HIGH(arg1), c);
664 tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), 31);
665 } else {
666 tcg_gen_shri_i32(TCGV_LOW(ret), TCGV_HIGH(arg1), c);
667 tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
668 }
669 } else {
670 tcg_gen_shli_i32(TCGV_HIGH(ret), TCGV_LOW(arg1), c);
671 tcg_gen_movi_i32(TCGV_LOW(ret), 0);
672 }
673 } else {
674 TCGv_i32 t0, t1;
675
676 t0 = tcg_temp_new_i32();
677 t1 = tcg_temp_new_i32();
678 if (right) {
679 tcg_gen_shli_i32(t0, TCGV_HIGH(arg1), 32 - c);
680 if (arith)
681 tcg_gen_sari_i32(t1, TCGV_HIGH(arg1), c);
682 else
683 tcg_gen_shri_i32(t1, TCGV_HIGH(arg1), c);
684 tcg_gen_shri_i32(TCGV_LOW(ret), TCGV_LOW(arg1), c);
685 tcg_gen_or_i32(TCGV_LOW(ret), TCGV_LOW(ret), t0);
686 tcg_gen_mov_i32(TCGV_HIGH(ret), t1);
687 } else {
688 tcg_gen_shri_i32(t0, TCGV_LOW(arg1), 32 - c);
689 /* Note: ret can be the same as arg1, so we use t1 */
690 tcg_gen_shli_i32(t1, TCGV_LOW(arg1), c);
691 tcg_gen_shli_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), c);
692 tcg_gen_or_i32(TCGV_HIGH(ret), TCGV_HIGH(ret), t0);
693 tcg_gen_mov_i32(TCGV_LOW(ret), t1);
694 }
695 tcg_temp_free_i32(t0);
696 tcg_temp_free_i32(t1);
697 }
698}
699#endif
700
701static void tcg_reg_alloc_start(TCGContext *s)
702{
703 int i;
704 TCGTemp *ts;
705 for(i = 0; i < s->nb_globals; i++) {
706 ts = &s->temps[i];
707 if (ts->fixed_reg) {
708 ts->val_type = TEMP_VAL_REG;
709 } else {
710 ts->val_type = TEMP_VAL_MEM;
711 }
712 }
713 for(i = s->nb_globals; i < s->nb_temps; i++) {
714 ts = &s->temps[i];
715 ts->val_type = TEMP_VAL_DEAD;
716 ts->mem_allocated = 0;
717 ts->fixed_reg = 0;
718 }
719 for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
720 s->reg_to_temp[i] = -1;
721 }
722}
723
724static char *tcg_get_arg_str_idx(TCGContext *s, char *buf, int buf_size,
725 int idx)
726{
727 TCGTemp *ts;
728
729 ts = &s->temps[idx];
730 if (idx < s->nb_globals) {
731 pstrcpy(buf, buf_size, ts->name);
732 } else {
733 if (ts->temp_local)
734 snprintf(buf, buf_size, "loc%d", idx - s->nb_globals);
735 else
736 snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals);
737 }
738 return buf;
739}
740
741char *tcg_get_arg_str_i32(TCGContext *s, char *buf, int buf_size, TCGv_i32 arg)
742{
743 return tcg_get_arg_str_idx(s, buf, buf_size, GET_TCGV_I32(arg));
744}
745
746char *tcg_get_arg_str_i64(TCGContext *s, char *buf, int buf_size, TCGv_i64 arg)
747{
748 return tcg_get_arg_str_idx(s, buf, buf_size, GET_TCGV_I64(arg));
749}
750
751static int helper_cmp(const void *p1, const void *p2)
752{
753 const TCGHelperInfo *th1 = p1;
754 const TCGHelperInfo *th2 = p2;
755 if (th1->func < th2->func)
756 return -1;
757 else if (th1->func == th2->func)
758 return 0;
759 else
760 return 1;
761}
762
763/* find helper definition (Note: A hash table would be better) */
764static TCGHelperInfo *tcg_find_helper(TCGContext *s, tcg_target_ulong val)
765{
766 int m, m_min, m_max;
767 TCGHelperInfo *th;
768 tcg_target_ulong v;
769
770 if (unlikely(!s->helpers_sorted)) {
771#ifdef VBOX
772 qemu_qsort(s->helpers, s->nb_helpers, sizeof(TCGHelperInfo),
773 helper_cmp);
774#else
775 qsort(s->helpers, s->nb_helpers, sizeof(TCGHelperInfo),
776 helper_cmp);
777#endif
778 s->helpers_sorted = 1;
779 }
780
781 /* binary search */
782 m_min = 0;
783 m_max = s->nb_helpers - 1;
784 while (m_min <= m_max) {
785 m = (m_min + m_max) >> 1;
786 th = &s->helpers[m];
787 v = th->func;
788 if (v == val)
789 return th;
790 else if (val < v) {
791 m_max = m - 1;
792 } else {
793 m_min = m + 1;
794 }
795 }
796 return NULL;
797}
798
799static const char * const cond_name[] =
800{
801 [TCG_COND_EQ] = "eq",
802 [TCG_COND_NE] = "ne",
803 [TCG_COND_LT] = "lt",
804 [TCG_COND_GE] = "ge",
805 [TCG_COND_LE] = "le",
806 [TCG_COND_GT] = "gt",
807 [TCG_COND_LTU] = "ltu",
808 [TCG_COND_GEU] = "geu",
809 [TCG_COND_LEU] = "leu",
810 [TCG_COND_GTU] = "gtu"
811};
812
813void tcg_dump_ops(TCGContext *s, FILE *outfile)
814{
815 const uint16_t *opc_ptr;
816 const TCGArg *args;
817 TCGArg arg;
818 int c, i, k, nb_oargs, nb_iargs, nb_cargs, first_insn;
819 const TCGOpDef *def;
820 char buf[128];
821
822 first_insn = 1;
823 opc_ptr = gen_opc_buf;
824 args = gen_opparam_buf;
825 while (opc_ptr < gen_opc_ptr) {
826 c = *opc_ptr++;
827 def = &tcg_op_defs[c];
828 if (c == INDEX_op_debug_insn_start) {
829 uint64_t pc;
830#if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
831 pc = ((uint64_t)args[1] << 32) | args[0];
832#else
833 pc = args[0];
834#endif
835 if (!first_insn)
836 fprintf(outfile, "\n");
837 fprintf(outfile, " ---- 0x%" PRIx64, pc);
838 first_insn = 0;
839 nb_oargs = def->nb_oargs;
840 nb_iargs = def->nb_iargs;
841 nb_cargs = def->nb_cargs;
842 } else if (c == INDEX_op_call) {
843 TCGArg arg;
844
845 /* variable number of arguments */
846 arg = *args++;
847 nb_oargs = arg >> 16;
848 nb_iargs = arg & 0xffff;
849 nb_cargs = def->nb_cargs;
850
851 fprintf(outfile, " %s ", def->name);
852
853 /* function name */
854 fprintf(outfile, "%s",
855 tcg_get_arg_str_idx(s, buf, sizeof(buf), args[nb_oargs + nb_iargs - 1]));
856 /* flags */
857 fprintf(outfile, ",$0x%" TCG_PRIlx,
858 args[nb_oargs + nb_iargs]);
859 /* nb out args */
860 fprintf(outfile, ",$%d", nb_oargs);
861 for(i = 0; i < nb_oargs; i++) {
862 fprintf(outfile, ",");
863 fprintf(outfile, "%s",
864 tcg_get_arg_str_idx(s, buf, sizeof(buf), args[i]));
865 }
866 for(i = 0; i < (nb_iargs - 1); i++) {
867 fprintf(outfile, ",");
868 if (args[nb_oargs + i] == TCG_CALL_DUMMY_ARG) {
869 fprintf(outfile, "<dummy>");
870 } else {
871 fprintf(outfile, "%s",
872 tcg_get_arg_str_idx(s, buf, sizeof(buf), args[nb_oargs + i]));
873 }
874 }
875 } else if (c == INDEX_op_movi_i32
876#if TCG_TARGET_REG_BITS == 64
877 || c == INDEX_op_movi_i64
878#endif
879 ) {
880 tcg_target_ulong val;
881 TCGHelperInfo *th;
882
883 nb_oargs = def->nb_oargs;
884 nb_iargs = def->nb_iargs;
885 nb_cargs = def->nb_cargs;
886 fprintf(outfile, " %s %s,$", def->name,
887 tcg_get_arg_str_idx(s, buf, sizeof(buf), args[0]));
888 val = args[1];
889 th = tcg_find_helper(s, val);
890 if (th) {
891 fprintf(outfile, "%s", th->name);
892 } else {
893 if (c == INDEX_op_movi_i32)
894 fprintf(outfile, "0x%x", (uint32_t)val);
895 else
896 fprintf(outfile, "0x%" PRIx64 , (uint64_t)val);
897 }
898 } else {
899 fprintf(outfile, " %s ", def->name);
900 if (c == INDEX_op_nopn) {
901 /* variable number of arguments */
902 nb_cargs = *args;
903 nb_oargs = 0;
904 nb_iargs = 0;
905 } else {
906 nb_oargs = def->nb_oargs;
907 nb_iargs = def->nb_iargs;
908 nb_cargs = def->nb_cargs;
909 }
910
911 k = 0;
912 for(i = 0; i < nb_oargs; i++) {
913 if (k != 0)
914 fprintf(outfile, ",");
915 fprintf(outfile, "%s",
916 tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++]));
917 }
918 for(i = 0; i < nb_iargs; i++) {
919 if (k != 0)
920 fprintf(outfile, ",");
921 fprintf(outfile, "%s",
922 tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++]));
923 }
924 if (c == INDEX_op_brcond_i32
925#if TCG_TARGET_REG_BITS == 32
926 || c == INDEX_op_brcond2_i32
927#elif TCG_TARGET_REG_BITS == 64
928 || c == INDEX_op_brcond_i64
929#endif
930 ) {
931 if (args[k] < ARRAY_SIZE(cond_name) && cond_name[args[k]])
932 fprintf(outfile, ",%s", cond_name[args[k++]]);
933 else
934 fprintf(outfile, ",$0x%" TCG_PRIlx, args[k++]);
935 i = 1;
936 }
937 else
938 i = 0;
939 for(; i < nb_cargs; i++) {
940 if (k != 0)
941 fprintf(outfile, ",");
942 arg = args[k++];
943 fprintf(outfile, "$0x%" TCG_PRIlx, arg);
944 }
945 }
946 fprintf(outfile, "\n");
947 args += nb_iargs + nb_oargs + nb_cargs;
948 }
949}
950
951/* we give more priority to constraints with less registers */
952static int get_constraint_priority(const TCGOpDef *def, int k)
953{
954 const TCGArgConstraint *arg_ct;
955
956 int i, n;
957 arg_ct = &def->args_ct[k];
958 if (arg_ct->ct & TCG_CT_ALIAS) {
959 /* an alias is equivalent to a single register */
960 n = 1;
961 } else {
962 if (!(arg_ct->ct & TCG_CT_REG))
963 return 0;
964 n = 0;
965 for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
966 if (tcg_regset_test_reg(arg_ct->u.regs, i))
967 n++;
968 }
969 }
970 return TCG_TARGET_NB_REGS - n + 1;
971}
972
973/* sort from highest priority to lowest */
974static void sort_constraints(TCGOpDef *def, int start, int n)
975{
976 int i, j, p1, p2, tmp;
977
978 for(i = 0; i < n; i++)
979 def->sorted_args[start + i] = start + i;
980 if (n <= 1)
981 return;
982 for(i = 0; i < n - 1; i++) {
983 for(j = i + 1; j < n; j++) {
984 p1 = get_constraint_priority(def, def->sorted_args[start + i]);
985 p2 = get_constraint_priority(def, def->sorted_args[start + j]);
986 if (p1 < p2) {
987 tmp = def->sorted_args[start + i];
988 def->sorted_args[start + i] = def->sorted_args[start + j];
989 def->sorted_args[start + j] = tmp;
990 }
991 }
992 }
993}
994
995void tcg_add_target_add_op_defs(const TCGTargetOpDef *tdefs)
996{
997 int op;
998 TCGOpDef *def;
999 const char *ct_str;
1000 int i, nb_args;
1001
1002 for(;;) {
1003 if (tdefs->op < 0)
1004 break;
1005 op = tdefs->op;
1006 assert(op >= 0 && op < NB_OPS);
1007 def = &tcg_op_defs[op];
1008 nb_args = def->nb_iargs + def->nb_oargs;
1009 for(i = 0; i < nb_args; i++) {
1010 ct_str = tdefs->args_ct_str[i];
1011 tcg_regset_clear(def->args_ct[i].u.regs);
1012 def->args_ct[i].ct = 0;
1013 if (ct_str[0] >= '0' && ct_str[0] <= '9') {
1014 int oarg;
1015 oarg = ct_str[0] - '0';
1016 assert(oarg < def->nb_oargs);
1017 assert(def->args_ct[oarg].ct & TCG_CT_REG);
1018 /* TCG_CT_ALIAS is for the output arguments. The input
1019 argument is tagged with TCG_CT_IALIAS. */
1020 def->args_ct[i] = def->args_ct[oarg];
1021 def->args_ct[oarg].ct = TCG_CT_ALIAS;
1022 def->args_ct[oarg].alias_index = i;
1023 def->args_ct[i].ct |= TCG_CT_IALIAS;
1024 def->args_ct[i].alias_index = oarg;
1025 } else {
1026 for(;;) {
1027 if (*ct_str == '\0')
1028 break;
1029 switch(*ct_str) {
1030 case 'i':
1031 def->args_ct[i].ct |= TCG_CT_CONST;
1032 ct_str++;
1033 break;
1034 default:
1035 if (target_parse_constraint(&def->args_ct[i], &ct_str) < 0) {
1036 fprintf(stderr, "Invalid constraint '%s' for arg %d of operation '%s'\n",
1037 ct_str, i, def->name);
1038#ifdef VBOX
1039 tcg_exit(1);
1040#else
1041 exit(1);
1042#endif
1043 }
1044 }
1045 }
1046 }
1047 }
1048
1049 /* sort the constraints (XXX: this is just an heuristic) */
1050 sort_constraints(def, 0, def->nb_oargs);
1051 sort_constraints(def, def->nb_oargs, def->nb_iargs);
1052
1053#if 0
1054 {
1055 int i;
1056
1057 printf("%s: sorted=", def->name);
1058 for(i = 0; i < def->nb_oargs + def->nb_iargs; i++)
1059 printf(" %d", def->sorted_args[i]);
1060 printf("\n");
1061 }
1062#endif
1063 tdefs++;
1064 }
1065
1066}
1067
1068#ifdef USE_LIVENESS_ANALYSIS
1069
1070/* set a nop for an operation using 'nb_args' */
1071static inline void tcg_set_nop(TCGContext *s, uint16_t *opc_ptr,
1072 TCGArg *args, int nb_args)
1073{
1074 if (nb_args == 0) {
1075 *opc_ptr = INDEX_op_nop;
1076 } else {
1077 *opc_ptr = INDEX_op_nopn;
1078 args[0] = nb_args;
1079 args[nb_args - 1] = nb_args;
1080 }
1081}
1082
1083/* liveness analysis: end of function: globals are live, temps are
1084 dead. */
1085/* XXX: at this stage, not used as there would be little gains because
1086 most TBs end with a conditional jump. */
1087static inline void tcg_la_func_end(TCGContext *s, uint8_t *dead_temps)
1088{
1089 memset(dead_temps, 0, s->nb_globals);
1090 memset(dead_temps + s->nb_globals, 1, s->nb_temps - s->nb_globals);
1091}
1092
1093/* liveness analysis: end of basic block: globals are live, temps are
1094 dead, local temps are live. */
1095static inline void tcg_la_bb_end(TCGContext *s, uint8_t *dead_temps)
1096{
1097 int i;
1098 TCGTemp *ts;
1099
1100 memset(dead_temps, 0, s->nb_globals);
1101 ts = &s->temps[s->nb_globals];
1102 for(i = s->nb_globals; i < s->nb_temps; i++) {
1103 if (ts->temp_local)
1104 dead_temps[i] = 0;
1105 else
1106 dead_temps[i] = 1;
1107 ts++;
1108 }
1109}
1110
1111/* Liveness analysis : update the opc_dead_iargs array to tell if a
1112 given input arguments is dead. Instructions updating dead
1113 temporaries are removed. */
1114static void tcg_liveness_analysis(TCGContext *s)
1115{
1116 int i, op_index, op, nb_args, nb_iargs, nb_oargs, arg, nb_ops;
1117 TCGArg *args;
1118 const TCGOpDef *def;
1119 uint8_t *dead_temps;
1120 unsigned int dead_iargs;
1121
1122 gen_opc_ptr++; /* skip end */
1123
1124 nb_ops = gen_opc_ptr - gen_opc_buf;
1125
1126 s->op_dead_iargs = tcg_malloc(nb_ops * sizeof(uint16_t));
1127
1128 dead_temps = tcg_malloc(s->nb_temps);
1129 memset(dead_temps, 1, s->nb_temps);
1130
1131 args = gen_opparam_ptr;
1132 op_index = nb_ops - 1;
1133 while (op_index >= 0) {
1134 op = gen_opc_buf[op_index];
1135 def = &tcg_op_defs[op];
1136 switch(op) {
1137 case INDEX_op_call:
1138 {
1139 int call_flags;
1140
1141 nb_args = args[-1];
1142 args -= nb_args;
1143 nb_iargs = args[0] & 0xffff;
1144 nb_oargs = args[0] >> 16;
1145 args++;
1146 call_flags = args[nb_oargs + nb_iargs];
1147
1148 /* pure functions can be removed if their result is not
1149 used */
1150 if (call_flags & TCG_CALL_PURE) {
1151 for(i = 0; i < nb_oargs; i++) {
1152 arg = args[i];
1153 if (!dead_temps[arg])
1154 goto do_not_remove_call;
1155 }
1156 tcg_set_nop(s, gen_opc_buf + op_index,
1157 args - 1, nb_args);
1158 } else {
1159 do_not_remove_call:
1160
1161 /* output args are dead */
1162 for(i = 0; i < nb_oargs; i++) {
1163 arg = args[i];
1164 dead_temps[arg] = 1;
1165 }
1166
1167 if (!(call_flags & TCG_CALL_CONST)) {
1168 /* globals are live (they may be used by the call) */
1169 memset(dead_temps, 0, s->nb_globals);
1170 }
1171
1172 /* input args are live */
1173 dead_iargs = 0;
1174 for(i = 0; i < nb_iargs; i++) {
1175 arg = args[i + nb_oargs];
1176 if (arg != TCG_CALL_DUMMY_ARG) {
1177 if (dead_temps[arg]) {
1178 dead_iargs |= (1 << i);
1179 }
1180 dead_temps[arg] = 0;
1181 }
1182 }
1183 s->op_dead_iargs[op_index] = dead_iargs;
1184 }
1185 args--;
1186 }
1187 break;
1188 case INDEX_op_set_label:
1189 args--;
1190 /* mark end of basic block */
1191 tcg_la_bb_end(s, dead_temps);
1192 break;
1193 case INDEX_op_debug_insn_start:
1194 args -= def->nb_args;
1195 break;
1196 case INDEX_op_nopn:
1197 nb_args = args[-1];
1198 args -= nb_args;
1199 break;
1200 case INDEX_op_discard:
1201 args--;
1202 /* mark the temporary as dead */
1203 dead_temps[args[0]] = 1;
1204 break;
1205 case INDEX_op_end:
1206 break;
1207 /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */
1208 default:
1209 args -= def->nb_args;
1210 nb_iargs = def->nb_iargs;
1211 nb_oargs = def->nb_oargs;
1212
1213 /* Test if the operation can be removed because all
1214 its outputs are dead. We assume that nb_oargs == 0
1215 implies side effects */
1216 if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) {
1217 for(i = 0; i < nb_oargs; i++) {
1218 arg = args[i];
1219 if (!dead_temps[arg])
1220 goto do_not_remove;
1221 }
1222 tcg_set_nop(s, gen_opc_buf + op_index, args, def->nb_args);
1223#ifdef CONFIG_PROFILER
1224 s->del_op_count++;
1225#endif
1226 } else {
1227 do_not_remove:
1228
1229 /* output args are dead */
1230 for(i = 0; i < nb_oargs; i++) {
1231 arg = args[i];
1232 dead_temps[arg] = 1;
1233 }
1234
1235 /* if end of basic block, update */
1236 if (def->flags & TCG_OPF_BB_END) {
1237 tcg_la_bb_end(s, dead_temps);
1238 } else if (def->flags & TCG_OPF_CALL_CLOBBER) {
1239 /* globals are live */
1240 memset(dead_temps, 0, s->nb_globals);
1241 }
1242
1243 /* input args are live */
1244 dead_iargs = 0;
1245 for(i = 0; i < nb_iargs; i++) {
1246 arg = args[i + nb_oargs];
1247 if (dead_temps[arg]) {
1248 dead_iargs |= (1 << i);
1249 }
1250 dead_temps[arg] = 0;
1251 }
1252 s->op_dead_iargs[op_index] = dead_iargs;
1253 }
1254 break;
1255 }
1256 op_index--;
1257 }
1258
1259 if (args != gen_opparam_buf)
1260 tcg_abort();
1261}
1262#else
1263/* dummy liveness analysis */
1264void tcg_liveness_analysis(TCGContext *s)
1265{
1266 int nb_ops;
1267 nb_ops = gen_opc_ptr - gen_opc_buf;
1268
1269 s->op_dead_iargs = tcg_malloc(nb_ops * sizeof(uint16_t));
1270 memset(s->op_dead_iargs, 0, nb_ops * sizeof(uint16_t));
1271}
1272#endif
1273
1274#ifndef NDEBUG
1275static void dump_regs(TCGContext *s)
1276{
1277 TCGTemp *ts;
1278 int i;
1279 char buf[64];
1280
1281 for(i = 0; i < s->nb_temps; i++) {
1282 ts = &s->temps[i];
1283 printf(" %10s: ", tcg_get_arg_str_idx(s, buf, sizeof(buf), i));
1284 switch(ts->val_type) {
1285 case TEMP_VAL_REG:
1286 printf("%s", tcg_target_reg_names[ts->reg]);
1287 break;
1288 case TEMP_VAL_MEM:
1289 printf("%d(%s)", (int)ts->mem_offset, tcg_target_reg_names[ts->mem_reg]);
1290 break;
1291 case TEMP_VAL_CONST:
1292 printf("$0x%" TCG_PRIlx, ts->val);
1293 break;
1294 case TEMP_VAL_DEAD:
1295 printf("D");
1296 break;
1297 default:
1298 printf("???");
1299 break;
1300 }
1301 printf("\n");
1302 }
1303
1304 for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
1305 if (s->reg_to_temp[i] >= 0) {
1306 printf("%s: %s\n",
1307 tcg_target_reg_names[i],
1308 tcg_get_arg_str_idx(s, buf, sizeof(buf), s->reg_to_temp[i]));
1309 }
1310 }
1311}
1312
1313static void check_regs(TCGContext *s)
1314{
1315 int reg, k;
1316 TCGTemp *ts;
1317 char buf[64];
1318
1319 for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
1320 k = s->reg_to_temp[reg];
1321 if (k >= 0) {
1322 ts = &s->temps[k];
1323 if (ts->val_type != TEMP_VAL_REG ||
1324 ts->reg != reg) {
1325 printf("Inconsistency for register %s:\n",
1326 tcg_target_reg_names[reg]);
1327 goto fail;
1328 }
1329 }
1330 }
1331 for(k = 0; k < s->nb_temps; k++) {
1332 ts = &s->temps[k];
1333 if (ts->val_type == TEMP_VAL_REG &&
1334 !ts->fixed_reg &&
1335 s->reg_to_temp[ts->reg] != k) {
1336 printf("Inconsistency for temp %s:\n",
1337 tcg_get_arg_str_idx(s, buf, sizeof(buf), k));
1338 fail:
1339 printf("reg state:\n");
1340 dump_regs(s);
1341 tcg_abort();
1342 }
1343 }
1344}
1345#endif
1346
1347static void temp_allocate_frame(TCGContext *s, int temp)
1348{
1349 TCGTemp *ts;
1350 ts = &s->temps[temp];
1351 s->current_frame_offset = (s->current_frame_offset + sizeof(tcg_target_long) - 1) & ~(sizeof(tcg_target_long) - 1);
1352#ifndef VBOX
1353 if (s->current_frame_offset + sizeof(tcg_target_long) > s->frame_end)
1354#else
1355 if ((unsigned)s->current_frame_offset + sizeof(tcg_target_long) > s->frame_end)
1356#endif
1357 tcg_abort();
1358 ts->mem_offset = s->current_frame_offset;
1359 ts->mem_reg = s->frame_reg;
1360 ts->mem_allocated = 1;
1361 s->current_frame_offset += sizeof(tcg_target_long);
1362}
1363
1364/* free register 'reg' by spilling the corresponding temporary if necessary */
1365static void tcg_reg_free(TCGContext *s, int reg)
1366{
1367 TCGTemp *ts;
1368 int temp;
1369
1370 temp = s->reg_to_temp[reg];
1371 if (temp != -1) {
1372 ts = &s->temps[temp];
1373 assert(ts->val_type == TEMP_VAL_REG);
1374 if (!ts->mem_coherent) {
1375 if (!ts->mem_allocated)
1376 temp_allocate_frame(s, temp);
1377 tcg_out_st(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1378 }
1379 ts->val_type = TEMP_VAL_MEM;
1380 s->reg_to_temp[reg] = -1;
1381 }
1382}
1383
1384/* Allocate a register belonging to reg1 & ~reg2 */
1385static int tcg_reg_alloc(TCGContext *s, TCGRegSet reg1, TCGRegSet reg2)
1386{
1387 int i, reg;
1388 TCGRegSet reg_ct;
1389
1390 tcg_regset_andnot(reg_ct, reg1, reg2);
1391
1392 /* first try free registers */
1393 for(i = 0; i < ARRAY_SIZE(tcg_target_reg_alloc_order); i++) {
1394 reg = tcg_target_reg_alloc_order[i];
1395 if (tcg_regset_test_reg(reg_ct, reg) && s->reg_to_temp[reg] == -1)
1396 return reg;
1397 }
1398
1399 /* XXX: do better spill choice */
1400 for(i = 0; i < ARRAY_SIZE(tcg_target_reg_alloc_order); i++) {
1401 reg = tcg_target_reg_alloc_order[i];
1402 if (tcg_regset_test_reg(reg_ct, reg)) {
1403 tcg_reg_free(s, reg);
1404 return reg;
1405 }
1406 }
1407
1408 tcg_abort();
1409}
1410
1411/* save a temporary to memory. 'allocated_regs' is used in case a
1412 temporary registers needs to be allocated to store a constant. */
1413static void temp_save(TCGContext *s, int temp, TCGRegSet allocated_regs)
1414{
1415 TCGTemp *ts;
1416 int reg;
1417
1418 ts = &s->temps[temp];
1419 if (!ts->fixed_reg) {
1420 switch(ts->val_type) {
1421 case TEMP_VAL_REG:
1422 tcg_reg_free(s, ts->reg);
1423 break;
1424 case TEMP_VAL_DEAD:
1425 ts->val_type = TEMP_VAL_MEM;
1426 break;
1427 case TEMP_VAL_CONST:
1428 reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],
1429 allocated_regs);
1430 if (!ts->mem_allocated)
1431 temp_allocate_frame(s, temp);
1432 tcg_out_movi(s, ts->type, reg, ts->val);
1433 tcg_out_st(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1434 ts->val_type = TEMP_VAL_MEM;
1435 break;
1436 case TEMP_VAL_MEM:
1437 break;
1438 default:
1439 tcg_abort();
1440 }
1441 }
1442}
1443
1444/* save globals to their cannonical location and assume they can be
1445 modified be the following code. 'allocated_regs' is used in case a
1446 temporary registers needs to be allocated to store a constant. */
1447static void save_globals(TCGContext *s, TCGRegSet allocated_regs)
1448{
1449 int i;
1450
1451 for(i = 0; i < s->nb_globals; i++) {
1452 temp_save(s, i, allocated_regs);
1453 }
1454}
1455
1456/* at the end of a basic block, we assume all temporaries are dead and
1457 all globals are stored at their canonical location. */
1458static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs)
1459{
1460 TCGTemp *ts;
1461 int i;
1462
1463 for(i = s->nb_globals; i < s->nb_temps; i++) {
1464 ts = &s->temps[i];
1465 if (ts->temp_local) {
1466 temp_save(s, i, allocated_regs);
1467 } else {
1468 if (ts->val_type == TEMP_VAL_REG) {
1469 s->reg_to_temp[ts->reg] = -1;
1470 }
1471 ts->val_type = TEMP_VAL_DEAD;
1472 }
1473 }
1474
1475 save_globals(s, allocated_regs);
1476}
1477
1478#define IS_DEAD_IARG(n) ((dead_iargs >> (n)) & 1)
1479
1480static void tcg_reg_alloc_movi(TCGContext *s, const TCGArg *args)
1481{
1482 TCGTemp *ots;
1483 tcg_target_ulong val;
1484
1485 ots = &s->temps[args[0]];
1486 val = args[1];
1487
1488 if (ots->fixed_reg) {
1489 /* for fixed registers, we do not do any constant
1490 propagation */
1491 tcg_out_movi(s, ots->type, ots->reg, val);
1492 } else {
1493 /* The movi is not explicitly generated here */
1494 if (ots->val_type == TEMP_VAL_REG)
1495 s->reg_to_temp[ots->reg] = -1;
1496 ots->val_type = TEMP_VAL_CONST;
1497 ots->val = val;
1498 }
1499}
1500
1501static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def,
1502 const TCGArg *args,
1503 unsigned int dead_iargs)
1504{
1505 TCGTemp *ts, *ots;
1506 int reg;
1507 const TCGArgConstraint *arg_ct;
1508
1509 ots = &s->temps[args[0]];
1510 ts = &s->temps[args[1]];
1511 arg_ct = &def->args_ct[0];
1512
1513 /* XXX: always mark arg dead if IS_DEAD_IARG(0) */
1514 if (ts->val_type == TEMP_VAL_REG) {
1515 if (IS_DEAD_IARG(0) && !ts->fixed_reg && !ots->fixed_reg) {
1516 /* the mov can be suppressed */
1517 if (ots->val_type == TEMP_VAL_REG)
1518 s->reg_to_temp[ots->reg] = -1;
1519 reg = ts->reg;
1520 s->reg_to_temp[reg] = -1;
1521 ts->val_type = TEMP_VAL_DEAD;
1522 } else {
1523 if (ots->val_type == TEMP_VAL_REG) {
1524 reg = ots->reg;
1525 } else {
1526 reg = tcg_reg_alloc(s, arg_ct->u.regs, s->reserved_regs);
1527 }
1528 if (ts->reg != reg) {
1529 tcg_out_mov(s, reg, ts->reg);
1530 }
1531 }
1532 } else if (ts->val_type == TEMP_VAL_MEM) {
1533 if (ots->val_type == TEMP_VAL_REG) {
1534 reg = ots->reg;
1535 } else {
1536 reg = tcg_reg_alloc(s, arg_ct->u.regs, s->reserved_regs);
1537 }
1538 tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1539 } else if (ts->val_type == TEMP_VAL_CONST) {
1540 if (ots->fixed_reg) {
1541 reg = ots->reg;
1542 tcg_out_movi(s, ots->type, reg, ts->val);
1543 } else {
1544 /* propagate constant */
1545 if (ots->val_type == TEMP_VAL_REG)
1546 s->reg_to_temp[ots->reg] = -1;
1547 ots->val_type = TEMP_VAL_CONST;
1548 ots->val = ts->val;
1549 return;
1550 }
1551 } else {
1552 tcg_abort();
1553 }
1554 s->reg_to_temp[reg] = args[0];
1555 ots->reg = reg;
1556 ots->val_type = TEMP_VAL_REG;
1557 ots->mem_coherent = 0;
1558}
1559
1560static void tcg_reg_alloc_op(TCGContext *s,
1561 const TCGOpDef *def, int opc,
1562 const TCGArg *args,
1563 unsigned int dead_iargs)
1564{
1565 TCGRegSet allocated_regs;
1566 int i, k, nb_iargs, nb_oargs, reg;
1567 TCGArg arg;
1568 const TCGArgConstraint *arg_ct;
1569 TCGTemp *ts;
1570 TCGArg new_args[TCG_MAX_OP_ARGS];
1571 int const_args[TCG_MAX_OP_ARGS];
1572
1573 nb_oargs = def->nb_oargs;
1574 nb_iargs = def->nb_iargs;
1575
1576 /* copy constants */
1577 memcpy(new_args + nb_oargs + nb_iargs,
1578 args + nb_oargs + nb_iargs,
1579 sizeof(TCGArg) * def->nb_cargs);
1580
1581 /* satisfy input constraints */
1582 tcg_regset_set(allocated_regs, s->reserved_regs);
1583 for(k = 0; k < nb_iargs; k++) {
1584 i = def->sorted_args[nb_oargs + k];
1585 arg = args[i];
1586 arg_ct = &def->args_ct[i];
1587 ts = &s->temps[arg];
1588 if (ts->val_type == TEMP_VAL_MEM) {
1589 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1590 tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1591 ts->val_type = TEMP_VAL_REG;
1592 ts->reg = reg;
1593 ts->mem_coherent = 1;
1594 s->reg_to_temp[reg] = arg;
1595 } else if (ts->val_type == TEMP_VAL_CONST) {
1596 if (tcg_target_const_match(ts->val, arg_ct)) {
1597 /* constant is OK for instruction */
1598 const_args[i] = 1;
1599 new_args[i] = ts->val;
1600 goto iarg_end;
1601 } else {
1602 /* need to move to a register */
1603 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1604 tcg_out_movi(s, ts->type, reg, ts->val);
1605 ts->val_type = TEMP_VAL_REG;
1606 ts->reg = reg;
1607 ts->mem_coherent = 0;
1608 s->reg_to_temp[reg] = arg;
1609 }
1610 }
1611 assert(ts->val_type == TEMP_VAL_REG);
1612 if (arg_ct->ct & TCG_CT_IALIAS) {
1613 if (ts->fixed_reg) {
1614 /* if fixed register, we must allocate a new register
1615 if the alias is not the same register */
1616 if (arg != args[arg_ct->alias_index])
1617 goto allocate_in_reg;
1618 } else {
1619 /* if the input is aliased to an output and if it is
1620 not dead after the instruction, we must allocate
1621 a new register and move it */
1622 if (!IS_DEAD_IARG(i - nb_oargs))
1623 goto allocate_in_reg;
1624 }
1625 }
1626 reg = ts->reg;
1627 if (tcg_regset_test_reg(arg_ct->u.regs, reg)) {
1628 /* nothing to do : the constraint is satisfied */
1629 } else {
1630 allocate_in_reg:
1631 /* allocate a new register matching the constraint
1632 and move the temporary register into it */
1633 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1634 tcg_out_mov(s, reg, ts->reg);
1635 }
1636 new_args[i] = reg;
1637 const_args[i] = 0;
1638 tcg_regset_set_reg(allocated_regs, reg);
1639 iarg_end: ;
1640 }
1641
1642 if (def->flags & TCG_OPF_BB_END) {
1643 tcg_reg_alloc_bb_end(s, allocated_regs);
1644 } else {
1645 /* mark dead temporaries and free the associated registers */
1646 for(i = 0; i < nb_iargs; i++) {
1647 arg = args[nb_oargs + i];
1648 if (IS_DEAD_IARG(i)) {
1649 ts = &s->temps[arg];
1650 if (!ts->fixed_reg) {
1651 if (ts->val_type == TEMP_VAL_REG)
1652 s->reg_to_temp[ts->reg] = -1;
1653 ts->val_type = TEMP_VAL_DEAD;
1654 }
1655 }
1656 }
1657
1658 if (def->flags & TCG_OPF_CALL_CLOBBER) {
1659 /* XXX: permit generic clobber register list ? */
1660 for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
1661 if (tcg_regset_test_reg(tcg_target_call_clobber_regs, reg)) {
1662 tcg_reg_free(s, reg);
1663 }
1664 }
1665 /* XXX: for load/store we could do that only for the slow path
1666 (i.e. when a memory callback is called) */
1667
1668 /* store globals and free associated registers (we assume the insn
1669 can modify any global. */
1670 save_globals(s, allocated_regs);
1671 }
1672
1673 /* satisfy the output constraints */
1674 tcg_regset_set(allocated_regs, s->reserved_regs);
1675 for(k = 0; k < nb_oargs; k++) {
1676 i = def->sorted_args[k];
1677 arg = args[i];
1678 arg_ct = &def->args_ct[i];
1679 ts = &s->temps[arg];
1680 if (arg_ct->ct & TCG_CT_ALIAS) {
1681 reg = new_args[arg_ct->alias_index];
1682 } else {
1683 /* if fixed register, we try to use it */
1684 reg = ts->reg;
1685 if (ts->fixed_reg &&
1686 tcg_regset_test_reg(arg_ct->u.regs, reg)) {
1687 goto oarg_end;
1688 }
1689 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1690 }
1691 tcg_regset_set_reg(allocated_regs, reg);
1692 /* if a fixed register is used, then a move will be done afterwards */
1693 if (!ts->fixed_reg) {
1694 if (ts->val_type == TEMP_VAL_REG)
1695 s->reg_to_temp[ts->reg] = -1;
1696 ts->val_type = TEMP_VAL_REG;
1697 ts->reg = reg;
1698 /* temp value is modified, so the value kept in memory is
1699 potentially not the same */
1700 ts->mem_coherent = 0;
1701 s->reg_to_temp[reg] = arg;
1702 }
1703 oarg_end:
1704 new_args[i] = reg;
1705 }
1706 }
1707
1708 /* emit instruction */
1709 tcg_out_op(s, opc, new_args, const_args);
1710
1711 /* move the outputs in the correct register if needed */
1712 for(i = 0; i < nb_oargs; i++) {
1713 ts = &s->temps[args[i]];
1714 reg = new_args[i];
1715 if (ts->fixed_reg && ts->reg != reg) {
1716 tcg_out_mov(s, ts->reg, reg);
1717 }
1718 }
1719}
1720
1721#ifdef TCG_TARGET_STACK_GROWSUP
1722#define STACK_DIR(x) (-(x))
1723#else
1724#define STACK_DIR(x) (x)
1725#endif
1726
1727static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def,
1728 int opc, const TCGArg *args,
1729 unsigned int dead_iargs)
1730{
1731 int nb_iargs, nb_oargs, flags, nb_regs, i, reg, nb_params;
1732 TCGArg arg, func_arg;
1733 TCGTemp *ts;
1734 tcg_target_long stack_offset, call_stack_size, func_addr;
1735 int const_func_arg, allocate_args;
1736 TCGRegSet allocated_regs;
1737 const TCGArgConstraint *arg_ct;
1738
1739 arg = *args++;
1740
1741 nb_oargs = arg >> 16;
1742 nb_iargs = arg & 0xffff;
1743 nb_params = nb_iargs - 1;
1744
1745 flags = args[nb_oargs + nb_iargs];
1746
1747 nb_regs = tcg_target_get_call_iarg_regs_count(flags);
1748 if (nb_regs > nb_params)
1749 nb_regs = nb_params;
1750
1751 /* assign stack slots first */
1752 /* XXX: preallocate call stack */
1753 call_stack_size = (nb_params - nb_regs) * sizeof(tcg_target_long);
1754 call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) &
1755 ~(TCG_TARGET_STACK_ALIGN - 1);
1756 allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE);
1757 if (allocate_args) {
1758 tcg_out_addi(s, TCG_REG_CALL_STACK, -STACK_DIR(call_stack_size));
1759 }
1760
1761 stack_offset = TCG_TARGET_CALL_STACK_OFFSET;
1762 for(i = nb_regs; i < nb_params; i++) {
1763 arg = args[nb_oargs + i];
1764#ifdef TCG_TARGET_STACK_GROWSUP
1765 stack_offset -= sizeof(tcg_target_long);
1766#endif
1767 if (arg != TCG_CALL_DUMMY_ARG) {
1768 ts = &s->temps[arg];
1769 if (ts->val_type == TEMP_VAL_REG) {
1770 tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, stack_offset);
1771 } else if (ts->val_type == TEMP_VAL_MEM) {
1772 reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],
1773 s->reserved_regs);
1774 /* XXX: not correct if reading values from the stack */
1775 tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1776 tcg_out_st(s, ts->type, reg, TCG_REG_CALL_STACK, stack_offset);
1777 } else if (ts->val_type == TEMP_VAL_CONST) {
1778 reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],
1779 s->reserved_regs);
1780 /* XXX: sign extend may be needed on some targets */
1781 tcg_out_movi(s, ts->type, reg, ts->val);
1782 tcg_out_st(s, ts->type, reg, TCG_REG_CALL_STACK, stack_offset);
1783 } else {
1784 tcg_abort();
1785 }
1786 }
1787#ifndef TCG_TARGET_STACK_GROWSUP
1788 stack_offset += sizeof(tcg_target_long);
1789#endif
1790 }
1791
1792 /* assign input registers */
1793 tcg_regset_set(allocated_regs, s->reserved_regs);
1794 for(i = 0; i < nb_regs; i++) {
1795 arg = args[nb_oargs + i];
1796 if (arg != TCG_CALL_DUMMY_ARG) {
1797 ts = &s->temps[arg];
1798 reg = tcg_target_call_iarg_regs[i];
1799 tcg_reg_free(s, reg);
1800 if (ts->val_type == TEMP_VAL_REG) {
1801 if (ts->reg != reg) {
1802 tcg_out_mov(s, reg, ts->reg);
1803 }
1804 } else if (ts->val_type == TEMP_VAL_MEM) {
1805 tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1806 } else if (ts->val_type == TEMP_VAL_CONST) {
1807 /* XXX: sign extend ? */
1808 tcg_out_movi(s, ts->type, reg, ts->val);
1809 } else {
1810 tcg_abort();
1811 }
1812 tcg_regset_set_reg(allocated_regs, reg);
1813 }
1814 }
1815
1816 /* assign function address */
1817 func_arg = args[nb_oargs + nb_iargs - 1];
1818 arg_ct = &def->args_ct[0];
1819 ts = &s->temps[func_arg];
1820 func_addr = ts->val;
1821 const_func_arg = 0;
1822 if (ts->val_type == TEMP_VAL_MEM) {
1823 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1824 tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1825 func_arg = reg;
1826 tcg_regset_set_reg(allocated_regs, reg);
1827 } else if (ts->val_type == TEMP_VAL_REG) {
1828 reg = ts->reg;
1829 if (!tcg_regset_test_reg(arg_ct->u.regs, reg)) {
1830 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1831 tcg_out_mov(s, reg, ts->reg);
1832 }
1833 func_arg = reg;
1834 tcg_regset_set_reg(allocated_regs, reg);
1835 } else if (ts->val_type == TEMP_VAL_CONST) {
1836 if (tcg_target_const_match(func_addr, arg_ct)) {
1837 const_func_arg = 1;
1838 func_arg = func_addr;
1839 } else {
1840 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1841 tcg_out_movi(s, ts->type, reg, func_addr);
1842 func_arg = reg;
1843 tcg_regset_set_reg(allocated_regs, reg);
1844 }
1845 } else {
1846 tcg_abort();
1847 }
1848
1849
1850 /* mark dead temporaries and free the associated registers */
1851 for(i = 0; i < nb_iargs; i++) {
1852 arg = args[nb_oargs + i];
1853 if (IS_DEAD_IARG(i)) {
1854 ts = &s->temps[arg];
1855 if (!ts->fixed_reg) {
1856 if (ts->val_type == TEMP_VAL_REG)
1857 s->reg_to_temp[ts->reg] = -1;
1858 ts->val_type = TEMP_VAL_DEAD;
1859 }
1860 }
1861 }
1862
1863 /* clobber call registers */
1864 for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
1865 if (tcg_regset_test_reg(tcg_target_call_clobber_regs, reg)) {
1866 tcg_reg_free(s, reg);
1867 }
1868 }
1869
1870 /* store globals and free associated registers (we assume the call
1871 can modify any global. */
1872 if (!(flags & TCG_CALL_CONST)) {
1873 save_globals(s, allocated_regs);
1874 }
1875
1876 tcg_out_op(s, opc, &func_arg, &const_func_arg);
1877
1878 if (allocate_args) {
1879 tcg_out_addi(s, TCG_REG_CALL_STACK, STACK_DIR(call_stack_size));
1880 }
1881
1882 /* assign output registers and emit moves if needed */
1883 for(i = 0; i < nb_oargs; i++) {
1884 arg = args[i];
1885 ts = &s->temps[arg];
1886 reg = tcg_target_call_oarg_regs[i];
1887 assert(s->reg_to_temp[reg] == -1);
1888 if (ts->fixed_reg) {
1889 if (ts->reg != reg) {
1890 tcg_out_mov(s, ts->reg, reg);
1891 }
1892 } else {
1893 if (ts->val_type == TEMP_VAL_REG)
1894 s->reg_to_temp[ts->reg] = -1;
1895 ts->val_type = TEMP_VAL_REG;
1896 ts->reg = reg;
1897 ts->mem_coherent = 0;
1898 s->reg_to_temp[reg] = arg;
1899 }
1900 }
1901
1902 return nb_iargs + nb_oargs + def->nb_cargs + 1;
1903}
1904
1905#ifdef CONFIG_PROFILER
1906
1907static int64_t tcg_table_op_count[NB_OPS];
1908
1909static void dump_op_count(void)
1910{
1911 int i;
1912 FILE *f;
1913 f = fopen("/tmp/op.log", "w");
1914 for(i = INDEX_op_end; i < NB_OPS; i++) {
1915 fprintf(f, "%s %" PRId64 "\n", tcg_op_defs[i].name, tcg_table_op_count[i]);
1916 }
1917 fclose(f);
1918}
1919#endif
1920
1921
1922static inline int tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf,
1923 long search_pc)
1924{
1925 int opc, op_index;
1926 const TCGOpDef *def;
1927 unsigned int dead_iargs;
1928 const TCGArg *args;
1929
1930#ifdef DEBUG_DISAS
1931 if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP))) {
1932 qemu_log("OP:\n");
1933 tcg_dump_ops(s, logfile);
1934 qemu_log("\n");
1935 }
1936#endif
1937
1938#ifdef CONFIG_PROFILER
1939 s->la_time -= profile_getclock();
1940#endif
1941 tcg_liveness_analysis(s);
1942#ifdef CONFIG_PROFILER
1943 s->la_time += profile_getclock();
1944#endif
1945
1946#ifdef DEBUG_DISAS
1947# ifdef USE_LIVENESS_ANALYSIS /* vbox */
1948 if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT))) {
1949 qemu_log("OP after liveness analysis:\n");
1950 tcg_dump_ops(s, logfile);
1951 qemu_log("\n");
1952 }
1953# endif /* USE_LIVENESS_ANALYSIS - vbox */
1954#endif
1955
1956 tcg_reg_alloc_start(s);
1957
1958 s->code_buf = gen_code_buf;
1959 s->code_ptr = gen_code_buf;
1960
1961 args = gen_opparam_buf;
1962 op_index = 0;
1963
1964 for(;;) {
1965 opc = gen_opc_buf[op_index];
1966#ifdef CONFIG_PROFILER
1967 tcg_table_op_count[opc]++;
1968#endif
1969 def = &tcg_op_defs[opc];
1970#if 0
1971 printf("%s: %d %d %d\n", def->name,
1972 def->nb_oargs, def->nb_iargs, def->nb_cargs);
1973 // dump_regs(s);
1974#endif
1975 switch(opc) {
1976 case INDEX_op_mov_i32:
1977#if TCG_TARGET_REG_BITS == 64
1978 case INDEX_op_mov_i64:
1979#endif
1980 dead_iargs = s->op_dead_iargs[op_index];
1981 tcg_reg_alloc_mov(s, def, args, dead_iargs);
1982 break;
1983 case INDEX_op_movi_i32:
1984#if TCG_TARGET_REG_BITS == 64
1985 case INDEX_op_movi_i64:
1986#endif
1987 tcg_reg_alloc_movi(s, args);
1988 break;
1989 case INDEX_op_debug_insn_start:
1990 /* debug instruction */
1991//#ifdef VBOX /* HACK ALERT: GROSS HACK to work around registister allocation bugs in v0.12.5 */
1992// save_globals(s, s->reserved_regs);
1993//#endif
1994 break;
1995 case INDEX_op_nop:
1996 case INDEX_op_nop1:
1997 case INDEX_op_nop2:
1998 case INDEX_op_nop3:
1999 break;
2000 case INDEX_op_nopn:
2001 args += args[0];
2002 goto next;
2003 case INDEX_op_discard:
2004 {
2005 TCGTemp *ts;
2006 ts = &s->temps[args[0]];
2007 /* mark the temporary as dead */
2008 if (!ts->fixed_reg) {
2009 if (ts->val_type == TEMP_VAL_REG)
2010 s->reg_to_temp[ts->reg] = -1;
2011 ts->val_type = TEMP_VAL_DEAD;
2012 }
2013 }
2014 break;
2015 case INDEX_op_set_label:
2016 tcg_reg_alloc_bb_end(s, s->reserved_regs);
2017 tcg_out_label(s, args[0], (long)s->code_ptr);
2018 break;
2019 case INDEX_op_call:
2020 dead_iargs = s->op_dead_iargs[op_index];
2021 args += tcg_reg_alloc_call(s, def, opc, args, dead_iargs);
2022 goto next;
2023 case INDEX_op_end:
2024 goto the_end;
2025 default:
2026 /* Note: in order to speed up the code, it would be much
2027 faster to have specialized register allocator functions for
2028 some common argument patterns */
2029 dead_iargs = s->op_dead_iargs[op_index];
2030 tcg_reg_alloc_op(s, def, opc, args, dead_iargs);
2031 break;
2032 }
2033 args += def->nb_args;
2034 next:
2035 if (search_pc >= 0 && search_pc < s->code_ptr - gen_code_buf) {
2036 return op_index;
2037 }
2038 op_index++;
2039#ifndef NDEBUG
2040 check_regs(s);
2041#endif
2042 }
2043 the_end:
2044 return -1;
2045}
2046
2047int tcg_gen_code(TCGContext *s, uint8_t *gen_code_buf)
2048{
2049#ifdef CONFIG_PROFILER
2050 {
2051 int n;
2052 n = (gen_opc_ptr - gen_opc_buf);
2053 s->op_count += n;
2054 if (n > s->op_count_max)
2055 s->op_count_max = n;
2056
2057 s->temp_count += s->nb_temps;
2058 if (s->nb_temps > s->temp_count_max)
2059 s->temp_count_max = s->nb_temps;
2060 }
2061#endif
2062
2063 tcg_gen_code_common(s, gen_code_buf, -1);
2064
2065 /* flush instruction cache */
2066 flush_icache_range((unsigned long)gen_code_buf,
2067 (unsigned long)s->code_ptr);
2068 return s->code_ptr - gen_code_buf;
2069}
2070
2071/* Return the index of the micro operation such as the pc after is <
2072 offset bytes from the start of the TB. The contents of gen_code_buf must
2073 not be changed, though writing the same values is ok.
2074 Return -1 if not found. */
2075int tcg_gen_code_search_pc(TCGContext *s, uint8_t *gen_code_buf, long offset)
2076{
2077 return tcg_gen_code_common(s, gen_code_buf, offset);
2078}
2079
2080#ifdef CONFIG_PROFILER
2081void tcg_dump_info(FILE *f,
2082 int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
2083{
2084 TCGContext *s = &tcg_ctx;
2085 int64_t tot;
2086
2087 tot = s->interm_time + s->code_time;
2088 cpu_fprintf(f, "JIT cycles %" PRId64 " (%0.3f s at 2.4 GHz)\n",
2089 tot, tot / 2.4e9);
2090 cpu_fprintf(f, "translated TBs %" PRId64 " (aborted=%" PRId64 " %0.1f%%)\n",
2091 s->tb_count,
2092 s->tb_count1 - s->tb_count,
2093 s->tb_count1 ? (double)(s->tb_count1 - s->tb_count) / s->tb_count1 * 100.0 : 0);
2094 cpu_fprintf(f, "avg ops/TB %0.1f max=%d\n",
2095 s->tb_count ? (double)s->op_count / s->tb_count : 0, s->op_count_max);
2096 cpu_fprintf(f, "deleted ops/TB %0.2f\n",
2097 s->tb_count ?
2098 (double)s->del_op_count / s->tb_count : 0);
2099 cpu_fprintf(f, "avg temps/TB %0.2f max=%d\n",
2100 s->tb_count ?
2101 (double)s->temp_count / s->tb_count : 0,
2102 s->temp_count_max);
2103
2104 cpu_fprintf(f, "cycles/op %0.1f\n",
2105 s->op_count ? (double)tot / s->op_count : 0);
2106 cpu_fprintf(f, "cycles/in byte %0.1f\n",
2107 s->code_in_len ? (double)tot / s->code_in_len : 0);
2108 cpu_fprintf(f, "cycles/out byte %0.1f\n",
2109 s->code_out_len ? (double)tot / s->code_out_len : 0);
2110 if (tot == 0)
2111 tot = 1;
2112 cpu_fprintf(f, " gen_interm time %0.1f%%\n",
2113 (double)s->interm_time / tot * 100.0);
2114 cpu_fprintf(f, " gen_code time %0.1f%%\n",
2115 (double)s->code_time / tot * 100.0);
2116 cpu_fprintf(f, "liveness/code time %0.1f%%\n",
2117 (double)s->la_time / (s->code_time ? s->code_time : 1) * 100.0);
2118 cpu_fprintf(f, "cpu_restore count %" PRId64 "\n",
2119 s->restore_count);
2120 cpu_fprintf(f, " avg cycles %0.1f\n",
2121 s->restore_count ? (double)s->restore_time / s->restore_count : 0);
2122
2123 dump_op_count();
2124}
2125#else
2126void tcg_dump_info(FILE *f,
2127 int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
2128{
2129 cpu_fprintf(f, "[TCG profiler not compiled]\n");
2130}
2131#endif
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette