VirtualBox

source: vbox/trunk/src/recompiler_new/tcg/tcg.c@ 14975

Last change on this file since 14975 was 14975, checked in by vboxsync, 16 years ago

use correct flush function

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