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