VirtualBox

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

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

eol

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