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