VirtualBox

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

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

recompiler: Merged in changes from 0.13.0.

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