2 * Tiny Code Generator for QEMU
4 * Copyright (c) 2008 Fabrice Bellard
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:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
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
25 /* define it to suppress various consistency checks (faster) */
28 /* define it to use liveness analysis (better code) */
29 #define USE_LIVENESS_ANALYSIS
42 #include "qemu-common.h"
44 /* Note: the long term plan is to reduce the dependancies on the QEMU
45 CPU definitions. Currently they are used for qemu_ld/st
47 #define NO_CPU_IO_DEFS
55 static void patch_reloc(uint8_t *code_ptr, int type,
56 tcg_target_long value, tcg_target_long addend);
58 TCGOpDef tcg_op_defs[] = {
59 #define DEF(s, n, copy_size) { #s, 0, 0, n, n, 0, copy_size },
60 #define DEF2(s, iargs, oargs, cargs, flags) { #s, iargs, oargs, cargs, iargs + oargs + cargs, flags, 0 },
66 TCGRegSet tcg_target_available_regs[2];
67 TCGRegSet tcg_target_call_clobber_regs;
69 /* XXX: move that inside the context */
70 uint16_t *gen_opc_ptr;
71 TCGArg *gen_opparam_ptr;
73 static inline void tcg_out8(TCGContext *s, uint8_t v)
78 static inline void tcg_out16(TCGContext *s, uint16_t v)
80 *(uint16_t *)s->code_ptr = v;
84 static inline void tcg_out32(TCGContext *s, uint32_t v)
86 *(uint32_t *)s->code_ptr = v;
90 /* label relocation processing */
92 void tcg_out_reloc(TCGContext *s, uint8_t *code_ptr, int type,
93 int label_index, long addend)
98 l = &s->labels[label_index];
100 /* FIXME: This may break relocations on RISC targets that
101 modify instruction fields in place. The caller may not have
102 written the initial value. */
103 patch_reloc(code_ptr, type, l->u.value, addend);
105 /* add a new relocation entry */
106 r = tcg_malloc(sizeof(TCGRelocation));
110 r->next = l->u.first_reloc;
111 l->u.first_reloc = r;
115 static void tcg_out_label(TCGContext *s, int label_index,
116 tcg_target_long value)
121 l = &s->labels[label_index];
124 r = l->u.first_reloc;
126 patch_reloc(r->ptr, r->type, value, r->addend);
133 int gen_new_label(void)
135 TCGContext *s = &tcg_ctx;
139 if (s->nb_labels >= TCG_MAX_LABELS)
141 idx = s->nb_labels++;
144 l->u.first_reloc = NULL;
148 #include "tcg-target.c"
150 /* pool based memory allocation */
151 void *tcg_malloc_internal(TCGContext *s, int size)
156 if (size > TCG_POOL_CHUNK_SIZE) {
157 /* big malloc: insert a new pool (XXX: could optimize) */
158 p = qemu_malloc(sizeof(TCGPool) + size);
161 s->pool_current->next = p;
164 p->next = s->pool_current;
174 pool_size = TCG_POOL_CHUNK_SIZE;
175 p = qemu_malloc(sizeof(TCGPool) + pool_size);
179 s->pool_current->next = p;
188 s->pool_cur = p->data + size;
189 s->pool_end = p->data + p->size;
193 void tcg_pool_reset(TCGContext *s)
195 s->pool_cur = s->pool_end = NULL;
196 s->pool_current = NULL;
199 /* free all the pool */
200 void tcg_pool_free(TCGContext *s)
204 for(p = s->pool_first; p != NULL; p = p1) {
208 s->pool_first = NULL;
209 s->pool_cur = s->pool_end = NULL;
212 void tcg_context_init(TCGContext *s)
214 int op, total_args, n;
216 TCGArgConstraint *args_ct;
219 memset(s, 0, sizeof(*s));
220 s->temps = s->static_temps;
223 /* Count total number of arguments and allocate the corresponding
226 for(op = 0; op < NB_OPS; op++) {
227 def = &tcg_op_defs[op];
228 n = def->nb_iargs + def->nb_oargs;
232 args_ct = qemu_malloc(sizeof(TCGArgConstraint) * total_args);
233 sorted_args = qemu_malloc(sizeof(int) * total_args);
235 for(op = 0; op < NB_OPS; op++) {
236 def = &tcg_op_defs[op];
237 def->args_ct = args_ct;
238 def->sorted_args = sorted_args;
239 n = def->nb_iargs + def->nb_oargs;
246 /* init global prologue and epilogue */
247 s->code_buf = code_gen_prologue;
248 s->code_ptr = s->code_buf;
249 tcg_target_qemu_prologue(s);
250 flush_icache_range((unsigned long)s->code_buf,
251 (unsigned long)s->code_ptr);
254 void tcg_set_frame(TCGContext *s, int reg,
255 tcg_target_long start, tcg_target_long size)
257 s->frame_start = start;
258 s->frame_end = start + size;
262 void tcg_set_macro_func(TCGContext *s, TCGMacroFunc *func)
264 s->macro_func = func;
267 void tcg_func_start(TCGContext *s)
270 s->nb_temps = s->nb_globals;
271 s->labels = tcg_malloc(sizeof(TCGLabel) * TCG_MAX_LABELS);
273 s->current_frame_offset = s->frame_start;
275 gen_opc_ptr = gen_opc_buf;
276 gen_opparam_ptr = gen_opparam_buf;
279 static inline void tcg_temp_alloc(TCGContext *s, int n)
281 if (n > TCG_MAX_TEMPS)
285 TCGv tcg_global_reg_new(TCGType type, int reg, const char *name)
287 TCGContext *s = &tcg_ctx;
291 #if TCG_TARGET_REG_BITS == 32
292 if (type != TCG_TYPE_I32)
295 if (tcg_regset_test_reg(s->reserved_regs, reg))
298 tcg_temp_alloc(s, s->nb_globals + 1);
299 ts = &s->temps[s->nb_globals];
300 ts->base_type = type;
304 ts->val_type = TEMP_VAL_REG;
307 tcg_regset_set_reg(s->reserved_regs, reg);
308 return MAKE_TCGV(idx);
311 #if TCG_TARGET_REG_BITS == 32
312 /* temporary hack to avoid register shortage for tcg_qemu_st64() */
313 TCGv tcg_global_reg2_new_hack(TCGType type, int reg1, int reg2,
316 TCGContext *s = &tcg_ctx;
321 if (type != TCG_TYPE_I64)
324 tcg_temp_alloc(s, s->nb_globals + 2);
325 ts = &s->temps[s->nb_globals];
326 ts->base_type = type;
327 ts->type = TCG_TYPE_I32;
330 ts->val_type = TEMP_VAL_REG;
331 pstrcpy(buf, sizeof(buf), name);
332 pstrcat(buf, sizeof(buf), "_0");
333 ts->name = strdup(buf);
336 ts->base_type = type;
337 ts->type = TCG_TYPE_I32;
340 ts->val_type = TEMP_VAL_REG;
341 pstrcpy(buf, sizeof(buf), name);
342 pstrcat(buf, sizeof(buf), "_1");
343 ts->name = strdup(buf);
346 return MAKE_TCGV(idx);
350 TCGv tcg_global_mem_new(TCGType type, int reg, tcg_target_long offset,
353 TCGContext *s = &tcg_ctx;
358 #if TCG_TARGET_REG_BITS == 32
359 if (type == TCG_TYPE_I64) {
361 tcg_temp_alloc(s, s->nb_globals + 1);
362 ts = &s->temps[s->nb_globals];
363 ts->base_type = type;
364 ts->type = TCG_TYPE_I32;
366 ts->mem_allocated = 1;
368 #ifdef TCG_TARGET_WORDS_BIGENDIAN
369 ts->mem_offset = offset + 4;
371 ts->mem_offset = offset;
373 ts->val_type = TEMP_VAL_MEM;
374 pstrcpy(buf, sizeof(buf), name);
375 pstrcat(buf, sizeof(buf), "_0");
376 ts->name = strdup(buf);
379 ts->base_type = type;
380 ts->type = TCG_TYPE_I32;
382 ts->mem_allocated = 1;
384 #ifdef TCG_TARGET_WORDS_BIGENDIAN
385 ts->mem_offset = offset;
387 ts->mem_offset = offset + 4;
389 ts->val_type = TEMP_VAL_MEM;
390 pstrcpy(buf, sizeof(buf), name);
391 pstrcat(buf, sizeof(buf), "_1");
392 ts->name = strdup(buf);
398 tcg_temp_alloc(s, s->nb_globals + 1);
399 ts = &s->temps[s->nb_globals];
400 ts->base_type = type;
403 ts->mem_allocated = 1;
405 ts->mem_offset = offset;
406 ts->val_type = TEMP_VAL_MEM;
410 return MAKE_TCGV(idx);
413 TCGv tcg_temp_new(TCGType type)
415 TCGContext *s = &tcg_ctx;
420 #if TCG_TARGET_REG_BITS == 32
421 if (type == TCG_TYPE_I64) {
422 tcg_temp_alloc(s, s->nb_temps + 1);
423 ts = &s->temps[s->nb_temps];
424 ts->base_type = type;
425 ts->type = TCG_TYPE_I32;
427 ts->val_type = TEMP_VAL_DEAD;
428 ts->mem_allocated = 0;
431 ts->base_type = TCG_TYPE_I32;
432 ts->type = TCG_TYPE_I32;
433 ts->val_type = TEMP_VAL_DEAD;
435 ts->mem_allocated = 0;
441 tcg_temp_alloc(s, s->nb_temps + 1);
442 ts = &s->temps[s->nb_temps];
443 ts->base_type = type;
446 ts->val_type = TEMP_VAL_DEAD;
447 ts->mem_allocated = 0;
451 return MAKE_TCGV(idx);
454 TCGv tcg_const_i32(int32_t val)
456 TCGContext *s = &tcg_ctx;
461 tcg_temp_alloc(s, idx + 1);
463 ts->base_type = ts->type = TCG_TYPE_I32;
464 ts->val_type = TEMP_VAL_CONST;
468 return MAKE_TCGV(idx);
471 TCGv tcg_const_i64(int64_t val)
473 TCGContext *s = &tcg_ctx;
478 #if TCG_TARGET_REG_BITS == 32
479 tcg_temp_alloc(s, idx + 2);
481 ts->base_type = TCG_TYPE_I64;
482 ts->type = TCG_TYPE_I32;
483 ts->val_type = TEMP_VAL_CONST;
487 ts->base_type = TCG_TYPE_I32;
488 ts->type = TCG_TYPE_I32;
489 ts->val_type = TEMP_VAL_CONST;
494 tcg_temp_alloc(s, idx + 1);
496 ts->base_type = ts->type = TCG_TYPE_I64;
497 ts->val_type = TEMP_VAL_CONST;
502 return MAKE_TCGV(idx);
505 void tcg_register_helper(void *func, const char *name)
507 TCGContext *s = &tcg_ctx;
509 if ((s->nb_helpers + 1) > s->allocated_helpers) {
510 n = s->allocated_helpers;
516 s->helpers = realloc(s->helpers, n * sizeof(TCGHelperInfo));
517 s->allocated_helpers = n;
519 s->helpers[s->nb_helpers].func = (tcg_target_ulong)func;
520 s->helpers[s->nb_helpers].name = name;
524 static inline TCGType tcg_get_base_type(TCGContext *s, TCGv arg)
526 return s->temps[GET_TCGV(arg)].base_type;
529 static void tcg_gen_call_internal(TCGContext *s, TCGv func,
531 unsigned int nb_rets, const TCGv *rets,
532 unsigned int nb_params, const TCGv *params)
535 *gen_opc_ptr++ = INDEX_op_call;
536 *gen_opparam_ptr++ = (nb_rets << 16) | (nb_params + 1);
537 for(i = 0; i < nb_rets; i++) {
538 *gen_opparam_ptr++ = GET_TCGV(rets[i]);
540 for(i = 0; i < nb_params; i++) {
541 *gen_opparam_ptr++ = GET_TCGV(params[i]);
543 *gen_opparam_ptr++ = GET_TCGV(func);
545 *gen_opparam_ptr++ = flags;
546 /* total parameters, needed to go backward in the instruction stream */
547 *gen_opparam_ptr++ = 1 + nb_rets + nb_params + 3;
551 #if TCG_TARGET_REG_BITS < 64
552 /* Note: we convert the 64 bit args to 32 bit and do some alignment
553 and endian swap. Maybe it would be better to do the alignment
554 and endian swap in tcg_reg_alloc_call(). */
555 void tcg_gen_call(TCGContext *s, TCGv func, unsigned int flags,
556 unsigned int nb_rets, const TCGv *rets,
557 unsigned int nb_params, const TCGv *args1)
559 TCGv ret, *args2, rets_2[2], arg;
564 if (tcg_get_base_type(s, ret) == TCG_TYPE_I64) {
566 #ifdef TCG_TARGET_WORDS_BIGENDIAN
567 rets_2[0] = TCGV_HIGH(ret);
571 rets_2[1] = TCGV_HIGH(ret);
576 args2 = alloca((nb_params * 3) * sizeof(TCGv));
578 call_type = (flags & TCG_CALL_TYPE_MASK);
579 for(i = 0; i < nb_params; i++) {
581 if (tcg_get_base_type(s, arg) == TCG_TYPE_I64) {
582 #ifdef TCG_TARGET_I386
583 /* REGPARM case: if the third parameter is 64 bit, it is
584 allocated on the stack */
585 if (j == 2 && call_type == TCG_CALL_TYPE_REGPARM) {
586 call_type = TCG_CALL_TYPE_REGPARM_2;
587 flags = (flags & ~TCG_CALL_TYPE_MASK) | call_type;
590 args2[j++] = TCGV_HIGH(arg);
592 #ifdef TCG_TARGET_CALL_ALIGN_ARGS
593 /* some targets want aligned 64 bit args */
595 args2[j++] = TCG_CALL_DUMMY_ARG;
598 #ifdef TCG_TARGET_WORDS_BIGENDIAN
599 args2[j++] = TCGV_HIGH(arg);
603 args2[j++] = TCGV_HIGH(arg);
610 tcg_gen_call_internal(s, func, flags,
611 nb_rets, rets, j, args2);
614 void tcg_gen_call(TCGContext *s, TCGv func, unsigned int flags,
615 unsigned int nb_rets, const TCGv *rets,
616 unsigned int nb_params, const TCGv *args1)
618 tcg_gen_call_internal(s, func, flags,
619 nb_rets, rets, nb_params, args1);
623 #if TCG_TARGET_REG_BITS == 32
624 void tcg_gen_shifti_i64(TCGv ret, TCGv arg1,
625 int c, int right, int arith)
628 tcg_gen_mov_i32(ret, arg1);
629 tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1));
630 } else if (c >= 32) {
634 tcg_gen_sari_i32(ret, TCGV_HIGH(arg1), c);
635 tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), 31);
637 tcg_gen_shri_i32(ret, TCGV_HIGH(arg1), c);
638 tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
641 tcg_gen_shli_i32(TCGV_HIGH(ret), arg1, c);
642 tcg_gen_movi_i32(ret, 0);
647 t0 = tcg_temp_new(TCG_TYPE_I32);
648 t1 = tcg_temp_new(TCG_TYPE_I32);
650 tcg_gen_shli_i32(t0, TCGV_HIGH(arg1), 32 - c);
652 tcg_gen_sari_i32(t1, TCGV_HIGH(arg1), c);
654 tcg_gen_shri_i32(t1, TCGV_HIGH(arg1), c);
655 tcg_gen_shri_i32(ret, arg1, c);
656 tcg_gen_or_i32(ret, ret, t0);
657 tcg_gen_mov_i32(TCGV_HIGH(ret), t1);
659 tcg_gen_shri_i32(t0, arg1, 32 - c);
660 /* Note: ret can be the same as arg1, so we use t1 */
661 tcg_gen_shli_i32(t1, arg1, c);
662 tcg_gen_shli_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), c);
663 tcg_gen_or_i32(TCGV_HIGH(ret), TCGV_HIGH(ret), t0);
664 tcg_gen_mov_i32(ret, t1);
670 void tcg_reg_alloc_start(TCGContext *s)
674 for(i = 0; i < s->nb_globals; i++) {
677 ts->val_type = TEMP_VAL_REG;
679 ts->val_type = TEMP_VAL_MEM;
682 for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
683 s->reg_to_temp[i] = -1;
687 static char *tcg_get_arg_str_idx(TCGContext *s, char *buf, int buf_size,
693 if (idx < s->nb_globals) {
694 pstrcpy(buf, buf_size, ts->name);
696 if (ts->val_type == TEMP_VAL_CONST) {
697 snprintf(buf, buf_size, "$0x%" TCG_PRIlx , ts->val);
699 snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals);
705 char *tcg_get_arg_str(TCGContext *s, char *buf, int buf_size, TCGv arg)
707 return tcg_get_arg_str_idx(s, buf, buf_size, GET_TCGV(arg));
710 /* find helper definition (XXX: inefficient) */
711 static TCGHelperInfo *tcg_find_helper(TCGContext *s, tcg_target_ulong val)
714 for(i = 0; i < s->nb_helpers; i++) {
715 if (s->helpers[i].func == val)
716 return &s->helpers[i];
721 static const char *tcg_get_helper_str_idx(TCGContext *s, char *buf, int buf_size,
728 if (ts->val_type == TEMP_VAL_CONST) {
729 /* find helper name (XXX: inefficient) */
730 th = tcg_find_helper(s, ts->val);
732 pstrcpy(buf, buf_size, "$");
733 pstrcat(buf, buf_size, th->name);
737 return tcg_get_arg_str_idx(s, buf, buf_size, idx);
741 void tcg_dump_ops(TCGContext *s, FILE *outfile)
743 const uint16_t *opc_ptr;
746 int c, i, k, nb_oargs, nb_iargs, nb_cargs;
750 opc_ptr = gen_opc_buf;
751 args = gen_opparam_buf;
752 while (opc_ptr < gen_opc_ptr) {
754 def = &tcg_op_defs[c];
755 fprintf(outfile, " %s ", def->name);
756 if (c == INDEX_op_call) {
759 /* variable number of arguments */
761 nb_oargs = arg >> 16;
762 nb_iargs = arg & 0xffff;
763 nb_cargs = def->nb_cargs;
766 fprintf(outfile, "%s",
767 tcg_get_helper_str_idx(s, buf, sizeof(buf), args[nb_oargs + nb_iargs - 1]));
769 fprintf(outfile, ",$0x%" TCG_PRIlx,
770 args[nb_oargs + nb_iargs]);
772 fprintf(outfile, ",$%d", nb_oargs);
773 for(i = 0; i < nb_oargs; i++) {
774 fprintf(outfile, ",");
775 fprintf(outfile, "%s",
776 tcg_get_arg_str_idx(s, buf, sizeof(buf), args[i]));
778 for(i = 0; i < (nb_iargs - 1); i++) {
779 fprintf(outfile, ",");
780 if (args[nb_oargs + i] == TCG_CALL_DUMMY_ARG) {
781 fprintf(outfile, "<dummy>");
783 fprintf(outfile, "%s",
784 tcg_get_arg_str_idx(s, buf, sizeof(buf), args[nb_oargs + i]));
788 if (c == INDEX_op_nopn) {
789 /* variable number of arguments */
794 nb_oargs = def->nb_oargs;
795 nb_iargs = def->nb_iargs;
796 nb_cargs = def->nb_cargs;
800 for(i = 0; i < nb_oargs; i++) {
802 fprintf(outfile, ",");
803 fprintf(outfile, "%s",
804 tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++]));
806 for(i = 0; i < nb_iargs; i++) {
808 fprintf(outfile, ",");
809 fprintf(outfile, "%s",
810 tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++]));
812 for(i = 0; i < nb_cargs; i++) {
814 fprintf(outfile, ",");
816 fprintf(outfile, "$0x%" TCG_PRIlx, arg);
819 fprintf(outfile, "\n");
820 args += nb_iargs + nb_oargs + nb_cargs;
824 /* we give more priority to constraints with less registers */
825 static int get_constraint_priority(const TCGOpDef *def, int k)
827 const TCGArgConstraint *arg_ct;
830 arg_ct = &def->args_ct[k];
831 if (arg_ct->ct & TCG_CT_ALIAS) {
832 /* an alias is equivalent to a single register */
835 if (!(arg_ct->ct & TCG_CT_REG))
838 for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
839 if (tcg_regset_test_reg(arg_ct->u.regs, i))
843 return TCG_TARGET_NB_REGS - n + 1;
846 /* sort from highest priority to lowest */
847 static void sort_constraints(TCGOpDef *def, int start, int n)
849 int i, j, p1, p2, tmp;
851 for(i = 0; i < n; i++)
852 def->sorted_args[start + i] = start + i;
855 for(i = 0; i < n - 1; i++) {
856 for(j = i + 1; j < n; j++) {
857 p1 = get_constraint_priority(def, def->sorted_args[start + i]);
858 p2 = get_constraint_priority(def, def->sorted_args[start + j]);
860 tmp = def->sorted_args[start + i];
861 def->sorted_args[start + i] = def->sorted_args[start + j];
862 def->sorted_args[start + j] = tmp;
868 void tcg_add_target_add_op_defs(const TCGTargetOpDef *tdefs)
879 assert(op >= 0 && op < NB_OPS);
880 def = &tcg_op_defs[op];
881 nb_args = def->nb_iargs + def->nb_oargs;
882 for(i = 0; i < nb_args; i++) {
883 ct_str = tdefs->args_ct_str[i];
884 tcg_regset_clear(def->args_ct[i].u.regs);
885 def->args_ct[i].ct = 0;
886 if (ct_str[0] >= '0' && ct_str[0] <= '9') {
888 oarg = ct_str[0] - '0';
889 assert(oarg < def->nb_oargs);
890 assert(def->args_ct[oarg].ct & TCG_CT_REG);
891 /* TCG_CT_ALIAS is for the output arguments. The input
892 argument is tagged with TCG_CT_IALIAS. */
893 def->args_ct[i] = def->args_ct[oarg];
894 def->args_ct[oarg].ct = TCG_CT_ALIAS;
895 def->args_ct[oarg].alias_index = i;
896 def->args_ct[i].ct |= TCG_CT_IALIAS;
897 def->args_ct[i].alias_index = oarg;
904 def->args_ct[i].ct |= TCG_CT_CONST;
908 if (target_parse_constraint(&def->args_ct[i], &ct_str) < 0) {
909 fprintf(stderr, "Invalid constraint '%s' for arg %d of operation '%s'\n",
910 ct_str, i, def->name);
918 /* sort the constraints (XXX: this is just an heuristic) */
919 sort_constraints(def, 0, def->nb_oargs);
920 sort_constraints(def, def->nb_oargs, def->nb_iargs);
926 printf("%s: sorted=", def->name);
927 for(i = 0; i < def->nb_oargs + def->nb_iargs; i++)
928 printf(" %d", def->sorted_args[i]);
937 #ifdef USE_LIVENESS_ANALYSIS
939 /* set a nop for an operation using 'nb_args' */
940 static inline void tcg_set_nop(TCGContext *s, uint16_t *opc_ptr,
941 TCGArg *args, int nb_args)
944 *opc_ptr = INDEX_op_nop;
946 *opc_ptr = INDEX_op_nopn;
948 args[nb_args - 1] = nb_args;
952 /* liveness analysis: end of basic block: globals are live, temps are dead */
953 static inline void tcg_la_bb_end(TCGContext *s, uint8_t *dead_temps)
955 memset(dead_temps, 0, s->nb_globals);
956 memset(dead_temps + s->nb_globals, 1, s->nb_temps - s->nb_globals);
959 /* Liveness analysis : update the opc_dead_iargs array to tell if a
960 given input arguments is dead. Instructions updating dead
961 temporaries are removed. */
962 void tcg_liveness_analysis(TCGContext *s)
964 int i, op_index, op, nb_args, nb_iargs, nb_oargs, arg, nb_ops;
968 unsigned int dead_iargs;
970 gen_opc_ptr++; /* skip end */
972 nb_ops = gen_opc_ptr - gen_opc_buf;
974 /* XXX: make it really dynamic */
975 s->op_dead_iargs = tcg_malloc(OPC_BUF_SIZE * sizeof(uint16_t));
977 dead_temps = tcg_malloc(s->nb_temps);
978 memset(dead_temps, 1, s->nb_temps);
980 args = gen_opparam_ptr;
981 op_index = nb_ops - 1;
982 while (op_index >= 0) {
983 op = gen_opc_buf[op_index];
984 def = &tcg_op_defs[op];
992 nb_iargs = args[0] & 0xffff;
993 nb_oargs = args[0] >> 16;
995 call_flags = args[nb_oargs + nb_iargs];
997 /* pure functions can be removed if their result is not
999 if (call_flags & TCG_CALL_PURE) {
1000 for(i = 0; i < nb_oargs; i++) {
1002 if (!dead_temps[arg])
1003 goto do_not_remove_call;
1005 tcg_set_nop(s, gen_opc_buf + op_index,
1010 /* output args are dead */
1011 for(i = 0; i < nb_oargs; i++) {
1013 dead_temps[arg] = 1;
1016 /* globals are live (they may be used by the call) */
1017 memset(dead_temps, 0, s->nb_globals);
1019 /* input args are live */
1021 for(i = 0; i < nb_iargs; i++) {
1022 arg = args[i + nb_oargs];
1023 if (arg != TCG_CALL_DUMMY_ARG) {
1024 if (dead_temps[arg]) {
1025 dead_iargs |= (1 << i);
1027 dead_temps[arg] = 0;
1030 s->op_dead_iargs[op_index] = dead_iargs;
1035 case INDEX_op_set_label:
1037 /* mark end of basic block */
1038 tcg_la_bb_end(s, dead_temps);
1044 case INDEX_op_discard:
1046 /* mark the temporary as dead */
1047 dead_temps[args[0]] = 1;
1049 case INDEX_op_macro_2:
1051 int dead_args[2], macro_id;
1052 int saved_op_index, saved_arg_index;
1053 int macro_op_index, macro_arg_index;
1054 int macro_end_op_index, macro_end_arg_index;
1059 dead_args[0] = dead_temps[args[0]];
1060 dead_args[1] = dead_temps[args[1]];
1063 /* call the macro function which generate code
1064 depending on the live outputs */
1065 saved_op_index = op_index;
1066 saved_arg_index = args - gen_opparam_buf;
1068 /* add a macro start instruction */
1069 *gen_opc_ptr++ = INDEX_op_macro_start;
1070 *gen_opparam_ptr++ = saved_op_index;
1071 *gen_opparam_ptr++ = saved_arg_index;
1073 macro_op_index = gen_opc_ptr - gen_opc_buf;
1074 macro_arg_index = gen_opparam_ptr - gen_opparam_buf;
1076 last_nb_temps = s->nb_temps;
1078 s->macro_func(s, macro_id, dead_args);
1080 /* realloc temp info (XXX: make it faster) */
1081 if (s->nb_temps > last_nb_temps) {
1082 uint8_t *new_dead_temps;
1084 new_dead_temps = tcg_malloc(s->nb_temps);
1085 memcpy(new_dead_temps, dead_temps, last_nb_temps);
1086 memset(new_dead_temps + last_nb_temps, 1,
1087 s->nb_temps - last_nb_temps);
1088 dead_temps = new_dead_temps;
1091 macro_end_op_index = gen_opc_ptr - gen_opc_buf;
1092 macro_end_arg_index = gen_opparam_ptr - gen_opparam_buf;
1094 /* end of macro: add a goto to the next instruction */
1095 *gen_opc_ptr++ = INDEX_op_macro_end;
1096 *gen_opparam_ptr++ = op_index + 1;
1097 *gen_opparam_ptr++ = saved_arg_index + nb_args;
1099 /* modify the macro operation to be a macro_goto */
1100 gen_opc_buf[op_index] = INDEX_op_macro_goto;
1101 args[0] = macro_op_index;
1102 args[1] = macro_arg_index;
1103 args[2] = 0; /* dummy third arg to match the
1106 /* set the next instruction to the end of the macro */
1107 op_index = macro_end_op_index;
1108 args = macro_end_arg_index + gen_opparam_buf;
1111 case INDEX_op_macro_start:
1114 args = gen_opparam_buf + args[1];
1116 case INDEX_op_macro_goto:
1117 case INDEX_op_macro_end:
1118 tcg_abort(); /* should never happen in liveness analysis */
1121 /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */
1123 if (op > INDEX_op_end) {
1124 args -= def->nb_args;
1125 nb_iargs = def->nb_iargs;
1126 nb_oargs = def->nb_oargs;
1128 /* Test if the operation can be removed because all
1129 its outputs are dead. We assume that nb_oargs == 0
1130 implies side effects */
1131 if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) {
1132 for(i = 0; i < nb_oargs; i++) {
1134 if (!dead_temps[arg])
1137 tcg_set_nop(s, gen_opc_buf + op_index, args, def->nb_args);
1138 #ifdef CONFIG_PROFILER
1140 extern int64_t dyngen_tcg_del_op_count;
1141 dyngen_tcg_del_op_count++;
1147 /* output args are dead */
1148 for(i = 0; i < nb_oargs; i++) {
1150 dead_temps[arg] = 1;
1153 /* if end of basic block, update */
1154 if (def->flags & TCG_OPF_BB_END) {
1155 tcg_la_bb_end(s, dead_temps);
1156 } else if (def->flags & TCG_OPF_CALL_CLOBBER) {
1157 /* globals are live */
1158 memset(dead_temps, 0, s->nb_globals);
1161 /* input args are live */
1163 for(i = 0; i < nb_iargs; i++) {
1164 arg = args[i + nb_oargs];
1165 if (dead_temps[arg]) {
1166 dead_iargs |= (1 << i);
1168 dead_temps[arg] = 0;
1170 s->op_dead_iargs[op_index] = dead_iargs;
1173 /* legacy dyngen operations */
1174 args -= def->nb_args;
1175 /* mark end of basic block */
1176 tcg_la_bb_end(s, dead_temps);
1183 if (args != gen_opparam_buf)
1187 /* dummy liveness analysis */
1188 void tcg_liveness_analysis(TCGContext *s)
1191 nb_ops = gen_opc_ptr - gen_opc_buf;
1193 s->op_dead_iargs = tcg_malloc(nb_ops * sizeof(uint16_t));
1194 memset(s->op_dead_iargs, 0, nb_ops * sizeof(uint16_t));
1199 static void dump_regs(TCGContext *s)
1205 for(i = 0; i < s->nb_temps; i++) {
1207 printf(" %10s: ", tcg_get_arg_str_idx(s, buf, sizeof(buf), i));
1208 switch(ts->val_type) {
1210 printf("%s", tcg_target_reg_names[ts->reg]);
1213 printf("%d(%s)", (int)ts->mem_offset, tcg_target_reg_names[ts->mem_reg]);
1215 case TEMP_VAL_CONST:
1216 printf("$0x%" TCG_PRIlx, ts->val);
1228 for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
1229 if (s->reg_to_temp[i] >= 0) {
1231 tcg_target_reg_names[i],
1232 tcg_get_arg_str_idx(s, buf, sizeof(buf), s->reg_to_temp[i]));
1237 static void check_regs(TCGContext *s)
1243 for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
1244 k = s->reg_to_temp[reg];
1247 if (ts->val_type != TEMP_VAL_REG ||
1249 printf("Inconsistency for register %s:\n",
1250 tcg_target_reg_names[reg]);
1255 for(k = 0; k < s->nb_temps; k++) {
1257 if (ts->val_type == TEMP_VAL_REG &&
1259 s->reg_to_temp[ts->reg] != k) {
1260 printf("Inconsistency for temp %s:\n",
1261 tcg_get_arg_str_idx(s, buf, sizeof(buf), k));
1263 printf("reg state:\n");
1267 if (ts->val_type == TEMP_VAL_CONST && k < s->nb_globals) {
1268 printf("constant forbidden in global %s\n",
1269 tcg_get_arg_str_idx(s, buf, sizeof(buf), k));
1276 static void temp_allocate_frame(TCGContext *s, int temp)
1279 ts = &s->temps[temp];
1280 s->current_frame_offset = (s->current_frame_offset + sizeof(tcg_target_long) - 1) & ~(sizeof(tcg_target_long) - 1);
1281 if (s->current_frame_offset + sizeof(tcg_target_long) > s->frame_end)
1283 ts->mem_offset = s->current_frame_offset;
1284 ts->mem_reg = s->frame_reg;
1285 ts->mem_allocated = 1;
1286 s->current_frame_offset += sizeof(tcg_target_long);
1289 /* free register 'reg' by spilling the corresponding temporary if necessary */
1290 static void tcg_reg_free(TCGContext *s, int reg)
1295 temp = s->reg_to_temp[reg];
1297 ts = &s->temps[temp];
1298 assert(ts->val_type == TEMP_VAL_REG);
1299 if (!ts->mem_coherent) {
1300 if (!ts->mem_allocated)
1301 temp_allocate_frame(s, temp);
1302 tcg_out_st(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1304 ts->val_type = TEMP_VAL_MEM;
1305 s->reg_to_temp[reg] = -1;
1309 /* Allocate a register belonging to reg1 & ~reg2 */
1310 static int tcg_reg_alloc(TCGContext *s, TCGRegSet reg1, TCGRegSet reg2)
1315 tcg_regset_andnot(reg_ct, reg1, reg2);
1317 /* first try free registers */
1318 for(i = 0; i < ARRAY_SIZE(tcg_target_reg_alloc_order); i++) {
1319 reg = tcg_target_reg_alloc_order[i];
1320 if (tcg_regset_test_reg(reg_ct, reg) && s->reg_to_temp[reg] == -1)
1324 /* XXX: do better spill choice */
1325 for(i = 0; i < ARRAY_SIZE(tcg_target_reg_alloc_order); i++) {
1326 reg = tcg_target_reg_alloc_order[i];
1327 if (tcg_regset_test_reg(reg_ct, reg)) {
1328 tcg_reg_free(s, reg);
1336 /* save globals to their cannonical location and assume they can be
1337 modified be the following code. */
1338 static void save_globals(TCGContext *s)
1343 for(i = 0; i < s->nb_globals; i++) {
1345 if (!ts->fixed_reg) {
1346 if (ts->val_type == TEMP_VAL_REG) {
1347 tcg_reg_free(s, ts->reg);
1348 } else if (ts->val_type == TEMP_VAL_DEAD) {
1349 ts->val_type = TEMP_VAL_MEM;
1355 /* at the end of a basic block, we assume all temporaries are dead and
1356 all globals are stored at their canonical location */
1357 /* XXX: optimize by handling constants in another array ? */
1358 void tcg_reg_alloc_bb_end(TCGContext *s)
1365 for(i = s->nb_globals; i < s->nb_temps; i++) {
1367 if (ts->val_type != TEMP_VAL_CONST) {
1368 if (ts->val_type == TEMP_VAL_REG) {
1369 s->reg_to_temp[ts->reg] = -1;
1371 ts->val_type = TEMP_VAL_DEAD;
1376 #define IS_DEAD_IARG(n) ((dead_iargs >> (n)) & 1)
1378 static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def,
1380 unsigned int dead_iargs)
1384 const TCGArgConstraint *arg_ct;
1386 ots = &s->temps[args[0]];
1387 ts = &s->temps[args[1]];
1388 arg_ct = &def->args_ct[0];
1390 if (ts->val_type == TEMP_VAL_REG) {
1391 if (IS_DEAD_IARG(0) && !ts->fixed_reg && !ots->fixed_reg) {
1392 /* the mov can be suppressed */
1393 if (ots->val_type == TEMP_VAL_REG)
1394 s->reg_to_temp[ots->reg] = -1;
1396 s->reg_to_temp[reg] = -1;
1397 ts->val_type = TEMP_VAL_DEAD;
1399 if (ots->val_type == TEMP_VAL_REG) {
1402 reg = tcg_reg_alloc(s, arg_ct->u.regs, s->reserved_regs);
1404 if (ts->reg != reg) {
1405 tcg_out_mov(s, reg, ts->reg);
1408 } else if (ts->val_type == TEMP_VAL_MEM) {
1409 if (ots->val_type == TEMP_VAL_REG) {
1412 reg = tcg_reg_alloc(s, arg_ct->u.regs, s->reserved_regs);
1414 tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1415 } else if (ts->val_type == TEMP_VAL_CONST) {
1416 if (ots->val_type == TEMP_VAL_REG) {
1419 reg = tcg_reg_alloc(s, arg_ct->u.regs, s->reserved_regs);
1421 tcg_out_movi(s, ots->type, reg, ts->val);
1425 s->reg_to_temp[reg] = args[0];
1427 ots->val_type = TEMP_VAL_REG;
1428 ots->mem_coherent = 0;
1431 static void tcg_reg_alloc_op(TCGContext *s,
1432 const TCGOpDef *def, int opc,
1434 unsigned int dead_iargs)
1436 TCGRegSet allocated_regs;
1437 int i, k, nb_iargs, nb_oargs, reg;
1439 const TCGArgConstraint *arg_ct;
1441 TCGArg new_args[TCG_MAX_OP_ARGS];
1442 int const_args[TCG_MAX_OP_ARGS];
1444 nb_oargs = def->nb_oargs;
1445 nb_iargs = def->nb_iargs;
1447 /* copy constants */
1448 memcpy(new_args + nb_oargs + nb_iargs,
1449 args + nb_oargs + nb_iargs,
1450 sizeof(TCGArg) * def->nb_cargs);
1452 /* satisfy input constraints */
1453 tcg_regset_set(allocated_regs, s->reserved_regs);
1454 for(k = 0; k < nb_iargs; k++) {
1455 i = def->sorted_args[nb_oargs + k];
1457 arg_ct = &def->args_ct[i];
1458 ts = &s->temps[arg];
1459 if (ts->val_type == TEMP_VAL_MEM) {
1460 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1461 tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1462 ts->val_type = TEMP_VAL_REG;
1464 ts->mem_coherent = 1;
1465 s->reg_to_temp[reg] = arg;
1466 } else if (ts->val_type == TEMP_VAL_CONST) {
1467 if (tcg_target_const_match(ts->val, arg_ct)) {
1468 /* constant is OK for instruction */
1470 new_args[i] = ts->val;
1473 /* need to move to a register*/
1474 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1475 tcg_out_movi(s, ts->type, reg, ts->val);
1479 assert(ts->val_type == TEMP_VAL_REG);
1480 if (arg_ct->ct & TCG_CT_IALIAS) {
1481 if (ts->fixed_reg) {
1482 /* if fixed register, we must allocate a new register
1483 if the alias is not the same register */
1484 if (arg != args[arg_ct->alias_index])
1485 goto allocate_in_reg;
1487 /* if the input is aliased to an output and if it is
1488 not dead after the instruction, we must allocate
1489 a new register and move it */
1490 if (!IS_DEAD_IARG(i - nb_oargs))
1491 goto allocate_in_reg;
1495 if (tcg_regset_test_reg(arg_ct->u.regs, reg)) {
1496 /* nothing to do : the constraint is satisfied */
1499 /* allocate a new register matching the constraint
1500 and move the temporary register into it */
1501 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1502 tcg_out_mov(s, reg, ts->reg);
1507 tcg_regset_set_reg(allocated_regs, reg);
1511 /* mark dead temporaries and free the associated registers */
1512 for(i = 0; i < nb_iargs; i++) {
1513 arg = args[nb_oargs + i];
1514 if (IS_DEAD_IARG(i)) {
1515 ts = &s->temps[arg];
1516 if (ts->val_type != TEMP_VAL_CONST && !ts->fixed_reg) {
1517 if (ts->val_type == TEMP_VAL_REG)
1518 s->reg_to_temp[ts->reg] = -1;
1519 ts->val_type = TEMP_VAL_DEAD;
1524 if (def->flags & TCG_OPF_CALL_CLOBBER) {
1525 /* XXX: permit generic clobber register list ? */
1526 for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
1527 if (tcg_regset_test_reg(tcg_target_call_clobber_regs, reg)) {
1528 tcg_reg_free(s, reg);
1531 /* XXX: for load/store we could do that only for the slow path
1532 (i.e. when a memory callback is called) */
1534 /* store globals and free associated registers (we assume the insn
1535 can modify any global. */
1539 /* satisfy the output constraints */
1540 tcg_regset_set(allocated_regs, s->reserved_regs);
1541 for(k = 0; k < nb_oargs; k++) {
1542 i = def->sorted_args[k];
1544 arg_ct = &def->args_ct[i];
1545 ts = &s->temps[arg];
1546 if (arg_ct->ct & TCG_CT_ALIAS) {
1547 reg = new_args[arg_ct->alias_index];
1549 /* if fixed register, we try to use it */
1551 if (ts->fixed_reg &&
1552 tcg_regset_test_reg(arg_ct->u.regs, reg)) {
1555 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1557 tcg_regset_set_reg(allocated_regs, reg);
1558 /* if a fixed register is used, then a move will be done afterwards */
1559 if (!ts->fixed_reg) {
1560 if (ts->val_type == TEMP_VAL_REG)
1561 s->reg_to_temp[ts->reg] = -1;
1562 ts->val_type = TEMP_VAL_REG;
1564 /* temp value is modified, so the value kept in memory is
1565 potentially not the same */
1566 ts->mem_coherent = 0;
1567 s->reg_to_temp[reg] = arg;
1573 if (def->flags & TCG_OPF_BB_END)
1574 tcg_reg_alloc_bb_end(s);
1576 /* emit instruction */
1577 tcg_out_op(s, opc, new_args, const_args);
1579 /* move the outputs in the correct register if needed */
1580 for(i = 0; i < nb_oargs; i++) {
1581 ts = &s->temps[args[i]];
1583 if (ts->fixed_reg && ts->reg != reg) {
1584 tcg_out_mov(s, ts->reg, reg);
1589 #ifdef TCG_TARGET_STACK_GROWSUP
1590 #define STACK_DIR(x) (-(x))
1592 #define STACK_DIR(x) (x)
1595 static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def,
1596 int opc, const TCGArg *args,
1597 unsigned int dead_iargs)
1599 int nb_iargs, nb_oargs, flags, nb_regs, i, reg, nb_params;
1600 TCGArg arg, func_arg;
1602 tcg_target_long stack_offset, call_stack_size, func_addr;
1603 int const_func_arg, allocate_args;
1604 TCGRegSet allocated_regs;
1605 const TCGArgConstraint *arg_ct;
1609 nb_oargs = arg >> 16;
1610 nb_iargs = arg & 0xffff;
1611 nb_params = nb_iargs - 1;
1613 flags = args[nb_oargs + nb_iargs];
1615 nb_regs = tcg_target_get_call_iarg_regs_count(flags);
1616 if (nb_regs > nb_params)
1617 nb_regs = nb_params;
1619 /* assign stack slots first */
1620 /* XXX: preallocate call stack */
1621 call_stack_size = (nb_params - nb_regs) * sizeof(tcg_target_long);
1622 call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) &
1623 ~(TCG_TARGET_STACK_ALIGN - 1);
1624 allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE);
1625 if (allocate_args) {
1626 tcg_out_addi(s, TCG_REG_CALL_STACK, -STACK_DIR(call_stack_size));
1629 stack_offset = TCG_TARGET_CALL_STACK_OFFSET;
1630 for(i = nb_regs; i < nb_params; i++) {
1631 arg = args[nb_oargs + i];
1632 #ifdef TCG_TARGET_STACK_GROWSUP
1633 stack_offset -= sizeof(tcg_target_long);
1635 if (arg != TCG_CALL_DUMMY_ARG) {
1636 ts = &s->temps[arg];
1637 if (ts->val_type == TEMP_VAL_REG) {
1638 tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, stack_offset);
1639 } else if (ts->val_type == TEMP_VAL_MEM) {
1640 reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],
1642 /* XXX: not correct if reading values from the stack */
1643 tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1644 tcg_out_st(s, ts->type, reg, TCG_REG_CALL_STACK, stack_offset);
1645 } else if (ts->val_type == TEMP_VAL_CONST) {
1646 reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],
1648 /* XXX: sign extend may be needed on some targets */
1649 tcg_out_movi(s, ts->type, reg, ts->val);
1650 tcg_out_st(s, ts->type, reg, TCG_REG_CALL_STACK, stack_offset);
1655 #ifndef TCG_TARGET_STACK_GROWSUP
1656 stack_offset += sizeof(tcg_target_long);
1660 /* assign input registers */
1661 tcg_regset_set(allocated_regs, s->reserved_regs);
1662 for(i = 0; i < nb_regs; i++) {
1663 arg = args[nb_oargs + i];
1664 if (arg != TCG_CALL_DUMMY_ARG) {
1665 ts = &s->temps[arg];
1666 reg = tcg_target_call_iarg_regs[i];
1667 tcg_reg_free(s, reg);
1668 if (ts->val_type == TEMP_VAL_REG) {
1669 if (ts->reg != reg) {
1670 tcg_out_mov(s, reg, ts->reg);
1672 } else if (ts->val_type == TEMP_VAL_MEM) {
1673 tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1674 } else if (ts->val_type == TEMP_VAL_CONST) {
1675 /* XXX: sign extend ? */
1676 tcg_out_movi(s, ts->type, reg, ts->val);
1680 tcg_regset_set_reg(allocated_regs, reg);
1684 /* assign function address */
1685 func_arg = args[nb_oargs + nb_iargs - 1];
1686 arg_ct = &def->args_ct[0];
1687 ts = &s->temps[func_arg];
1688 func_addr = ts->val;
1690 if (ts->val_type == TEMP_VAL_MEM) {
1691 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1692 tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1694 } else if (ts->val_type == TEMP_VAL_REG) {
1696 if (!tcg_regset_test_reg(arg_ct->u.regs, reg)) {
1697 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1698 tcg_out_mov(s, reg, ts->reg);
1701 } else if (ts->val_type == TEMP_VAL_CONST) {
1702 if (tcg_target_const_match(func_addr, arg_ct)) {
1704 func_arg = func_addr;
1706 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1707 tcg_out_movi(s, ts->type, reg, func_addr);
1714 /* mark dead temporaries and free the associated registers */
1715 for(i = 0; i < nb_iargs; i++) {
1716 arg = args[nb_oargs + i];
1717 if (IS_DEAD_IARG(i)) {
1718 ts = &s->temps[arg];
1719 if (ts->val_type != TEMP_VAL_CONST && !ts->fixed_reg) {
1720 if (ts->val_type == TEMP_VAL_REG)
1721 s->reg_to_temp[ts->reg] = -1;
1722 ts->val_type = TEMP_VAL_DEAD;
1727 /* clobber call registers */
1728 for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
1729 if (tcg_regset_test_reg(tcg_target_call_clobber_regs, reg)) {
1730 tcg_reg_free(s, reg);
1734 /* store globals and free associated registers (we assume the call
1735 can modify any global. */
1738 tcg_out_op(s, opc, &func_arg, &const_func_arg);
1740 if (allocate_args) {
1741 tcg_out_addi(s, TCG_REG_CALL_STACK, STACK_DIR(call_stack_size));
1744 /* assign output registers and emit moves if needed */
1745 for(i = 0; i < nb_oargs; i++) {
1747 ts = &s->temps[arg];
1748 reg = tcg_target_call_oarg_regs[i];
1749 tcg_reg_free(s, reg);
1750 if (ts->fixed_reg) {
1751 if (ts->reg != reg) {
1752 tcg_out_mov(s, ts->reg, reg);
1755 if (ts->val_type == TEMP_VAL_REG)
1756 s->reg_to_temp[ts->reg] = -1;
1757 ts->val_type = TEMP_VAL_REG;
1759 ts->mem_coherent = 0;
1760 s->reg_to_temp[reg] = arg;
1764 return nb_iargs + nb_oargs + def->nb_cargs + 1;
1767 #ifdef CONFIG_PROFILER
1769 static int64_t dyngen_table_op_count[NB_OPS];
1771 void dump_op_count(void)
1775 f = fopen("/tmp/op1.log", "w");
1776 for(i = 0; i < INDEX_op_end; i++) {
1777 fprintf(f, "%s %" PRId64 "\n", tcg_op_defs[i].name, dyngen_table_op_count[i]);
1780 f = fopen("/tmp/op2.log", "w");
1781 for(i = INDEX_op_end; i < NB_OPS; i++) {
1782 fprintf(f, "%s %" PRId64 "\n", tcg_op_defs[i].name, dyngen_table_op_count[i]);
1789 static inline int tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf,
1792 int opc, op_index, macro_op_index;
1793 const TCGOpDef *def;
1794 unsigned int dead_iargs;
1798 if (unlikely(loglevel & CPU_LOG_TB_OP)) {
1799 fprintf(logfile, "OP:\n");
1800 tcg_dump_ops(s, logfile);
1801 fprintf(logfile, "\n");
1805 tcg_liveness_analysis(s);
1808 if (unlikely(loglevel & CPU_LOG_TB_OP_OPT)) {
1809 fprintf(logfile, "OP after la:\n");
1810 tcg_dump_ops(s, logfile);
1811 fprintf(logfile, "\n");
1815 tcg_reg_alloc_start(s);
1817 s->code_buf = gen_code_buf;
1818 s->code_ptr = gen_code_buf;
1820 macro_op_index = -1;
1821 args = gen_opparam_buf;
1825 opc = gen_opc_buf[op_index];
1826 #ifdef CONFIG_PROFILER
1827 dyngen_table_op_count[opc]++;
1829 def = &tcg_op_defs[opc];
1831 printf("%s: %d %d %d\n", def->name,
1832 def->nb_oargs, def->nb_iargs, def->nb_cargs);
1836 case INDEX_op_mov_i32:
1837 #if TCG_TARGET_REG_BITS == 64
1838 case INDEX_op_mov_i64:
1840 dead_iargs = s->op_dead_iargs[op_index];
1841 tcg_reg_alloc_mov(s, def, args, dead_iargs);
1851 case INDEX_op_discard:
1854 ts = &s->temps[args[0]];
1855 /* mark the temporary as dead */
1856 if (ts->val_type != TEMP_VAL_CONST && !ts->fixed_reg) {
1857 if (ts->val_type == TEMP_VAL_REG)
1858 s->reg_to_temp[ts->reg] = -1;
1859 ts->val_type = TEMP_VAL_DEAD;
1863 case INDEX_op_macro_goto:
1864 macro_op_index = op_index; /* only used for exceptions */
1865 op_index = args[0] - 1;
1866 args = gen_opparam_buf + args[1];
1868 case INDEX_op_macro_end:
1869 macro_op_index = -1; /* only used for exceptions */
1870 op_index = args[0] - 1;
1871 args = gen_opparam_buf + args[1];
1873 case INDEX_op_macro_start:
1874 /* must never happen here */
1876 case INDEX_op_set_label:
1877 tcg_reg_alloc_bb_end(s);
1878 tcg_out_label(s, args[0], (long)s->code_ptr);
1881 dead_iargs = s->op_dead_iargs[op_index];
1882 args += tcg_reg_alloc_call(s, def, opc, args, dead_iargs);
1887 #ifdef CONFIG_DYNGEN_OP
1888 case 0 ... INDEX_op_end - 1:
1889 /* legacy dyngen ops */
1890 #ifdef CONFIG_PROFILER
1892 extern int64_t dyngen_old_op_count;
1893 dyngen_old_op_count++;
1896 tcg_reg_alloc_bb_end(s);
1897 if (search_pc >= 0) {
1898 s->code_ptr += def->copy_size;
1899 args += def->nb_args;
1901 args = dyngen_op(s, opc, args);
1906 /* Note: in order to speed up the code, it would be much
1907 faster to have specialized register allocator functions for
1908 some common argument patterns */
1909 dead_iargs = s->op_dead_iargs[op_index];
1910 tcg_reg_alloc_op(s, def, opc, args, dead_iargs);
1913 args += def->nb_args;
1915 if (search_pc >= 0 && search_pc < s->code_ptr - gen_code_buf) {
1916 if (macro_op_index >= 0)
1917 return macro_op_index;
1930 int dyngen_code(TCGContext *s, uint8_t *gen_code_buf)
1932 #ifdef CONFIG_PROFILER
1934 extern int64_t dyngen_op_count;
1935 extern int dyngen_op_count_max;
1937 n = (gen_opc_ptr - gen_opc_buf);
1938 dyngen_op_count += n;
1939 if (n > dyngen_op_count_max)
1940 dyngen_op_count_max = n;
1944 tcg_gen_code_common(s, gen_code_buf, -1);
1946 /* flush instruction cache */
1947 flush_icache_range((unsigned long)gen_code_buf,
1948 (unsigned long)s->code_ptr);
1949 return s->code_ptr - gen_code_buf;
1952 /* Return the index of the micro operation such as the pc after is <
1953 offset bytes from the start of the TB. The contents of gen_code_buf must
1954 not be changed, though writing the same values is ok.
1955 Return -1 if not found. */
1956 int dyngen_code_search_pc(TCGContext *s, uint8_t *gen_code_buf, long offset)
1958 return tcg_gen_code_common(s, gen_code_buf, offset);