VirtualBox

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

最後變更 在這個檔案從41999是 37693,由 vboxsync 提交於 13 年 前

Windows fixes

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

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