VirtualBox

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

Last change on this file since 36125 was 36125, checked in by vboxsync, 14 years ago

recompiler: Removing traces of attempts at making the recompiler compile with the microsoft compiler. (untested)

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

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