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