VirtualBox

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

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

*: spelling fixes, thanks Timeless!

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