VirtualBox

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

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

rem: synced up to svn://svn.savannah.nongnu.org/qemu/trunk@6686 (repo UUID c046a42c-6fe2-441c-8c8c-71466251a162).

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

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