VirtualBox

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

最後變更 在這個檔案從37419是 36175,由 vboxsync 提交於 14 年 前

rem: Synced up to v0.11.1 (35bfc7324e2e6946c4113ada5db30553a1a7c40b) from git://git.savannah.nongnu.org/qemu.git.

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

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