blob: 66529f577208336e9f7c59f35bf8171018db1e3a [file] [log] [blame]
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001/*
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
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080025/* define it to use liveness analysis (better code) */
26#define USE_LIVENESS_ANALYSIS
27
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070028#include "config.h"
29
David Turner6a9ef172010-09-09 22:54:36 +020030#if !defined(CONFIG_DEBUG_TCG) && !defined(NDEBUG)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070031/* define it to suppress various consistency checks (faster) */
32#define NDEBUG
33#endif
34
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080035#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
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070043#ifdef _AIX
44#include <alloca.h>
45#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080046
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080047#include "qemu-common.h"
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070048#include "cache-utils.h"
David 'Digit' Turnerb9317722010-05-10 18:53:56 -070049#include "host-utils.h"
David Turner6a9ef172010-09-09 22:54:36 +020050#include "qemu-timer.h"
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080051
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
David 'Digit' Turnerb9317722010-05-10 18:53:56 -070062#if defined(CONFIG_USE_GUEST_BASE) && !defined(TCG_TARGET_HAS_GUEST_BASE)
63#error GUEST_BASE not supported on this host.
64#endif
65
David 'Digit' Turnerf1d9bf12011-05-11 18:19:41 +020066static void tcg_target_init(TCGContext *s);
67static void tcg_target_qemu_prologue(TCGContext *s);
David 'Digit' Turnerb9317722010-05-10 18:53:56 -070068static void patch_reloc(uint8_t *code_ptr, int type,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080069 tcg_target_long value, tcg_target_long addend);
70
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070071static TCGOpDef tcg_op_defs[] = {
David 'Digit' Turnerf1d9bf12011-05-11 18:19:41 +020072#define DEF(s, oargs, iargs, cargs, flags) { #s, oargs, iargs, cargs, iargs + oargs + cargs, flags },
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080073#include "tcg-opc.h"
74#undef DEF
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080075};
76
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070077static TCGRegSet tcg_target_available_regs[2];
78static TCGRegSet tcg_target_call_clobber_regs;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080079
80/* XXX: move that inside the context */
81uint16_t *gen_opc_ptr;
82TCGArg *gen_opparam_ptr;
83
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -080084#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
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080094static inline void tcg_out8(TCGContext *s, uint8_t v)
95{
96 *s->code_ptr++ = v;
97}
98
99static inline void tcg_out16(TCGContext *s, uint16_t v)
100{
101 *(uint16_t *)s->code_ptr = v;
102 s->code_ptr += 2;
103}
104
105static 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
David 'Digit' Turnerf1d9bf12011-05-11 18:19:41 +0200113static void tcg_out_reloc(TCGContext *s, uint8_t *code_ptr, int type,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800114 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
David 'Digit' Turnerb9317722010-05-10 18:53:56 -0700122 modify instruction fields in place. The caller may not have
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800123 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
David 'Digit' Turnerb9317722010-05-10 18:53:56 -0700136static void tcg_out_label(TCGContext *s, int label_index,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800137 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
154int 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 */
172void *tcg_malloc_internal(TCGContext *s, int size)
173{
174 TCGPool *p;
175 int pool_size;
David 'Digit' Turnerb9317722010-05-10 18:53:56 -0700176
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800177 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;
David 'Digit' Turnerb9317722010-05-10 18:53:56 -0700199 if (s->pool_current)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800200 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
214void tcg_pool_reset(TCGContext *s)
215{
216 s->pool_cur = s->pool_end = NULL;
217 s->pool_current = NULL;
218}
219
220void 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;
David 'Digit' Turnerb9317722010-05-10 18:53:56 -0700230
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800231 /* 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 }
David 'Digit' Turnerb9317722010-05-10 18:53:56 -0700251
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800252 tcg_target_init(s);
David 'Digit' Turnerf1d9bf12011-05-11 18:19:41 +0200253}
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800254
David 'Digit' Turnerf1d9bf12011-05-11 18:19:41 +0200255void tcg_prologue_init(TCGContext *s)
256{
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800257 /* 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);
David 'Digit' Turnerb9317722010-05-10 18:53:56 -0700261 flush_icache_range((unsigned long)s->code_buf,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800262 (unsigned long)s->code_ptr);
263}
264
265void 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
273void 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
288static inline void tcg_temp_alloc(TCGContext *s, int n)
289{
290 if (n > TCG_MAX_TEMPS)
291 tcg_abort();
292}
293
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700294static inline int tcg_global_reg_new_internal(TCGType type, int reg,
295 const char *name)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800296{
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);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700317 return idx;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800318}
319
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700320TCGv_i32 tcg_global_reg_new_i32(int reg, const char *name)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800321{
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800322 int idx;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800323
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700324 idx = tcg_global_reg_new_internal(TCG_TYPE_I32, reg, name);
325 return MAKE_TCGV_I32(idx);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800326}
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800327
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700328TCGv_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
336static inline int tcg_global_mem_new_internal(TCGType type, int reg,
337 tcg_target_long offset,
338 const char *name)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800339{
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 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700394 return idx;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800395}
396
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700397TCGv_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
406TCGv_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
415static inline int tcg_temp_new_internal(TCGType type, int temp_local)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800416{
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 }
David 'Digit' Turnerf1d9bf12011-05-11 18:19:41 +0200463
464#if defined(CONFIG_DEBUG_TCG)
465 s->temps_in_use++;
466#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700467 return idx;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800468}
469
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700470TCGv_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
478TCGv_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
486static inline void tcg_temp_free_internal(int idx)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800487{
488 TCGContext *s = &tcg_ctx;
489 TCGTemp *ts;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800490 int k;
491
David 'Digit' Turnerf1d9bf12011-05-11 18:19:41 +0200492#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
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800499 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
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700510void tcg_temp_free_i32(TCGv_i32 arg)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800511{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700512 tcg_temp_free_internal(GET_TCGV_I32(arg));
513}
514
515void tcg_temp_free_i64(TCGv_i64 arg)
516{
517 tcg_temp_free_internal(GET_TCGV_I64(arg));
518}
519
520TCGv_i32 tcg_const_i32(int32_t val)
521{
522 TCGv_i32 t0;
523 t0 = tcg_temp_new_i32();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800524 tcg_gen_movi_i32(t0, val);
525 return t0;
526}
527
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700528TCGv_i64 tcg_const_i64(int64_t val)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800529{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700530 TCGv_i64 t0;
531 t0 = tcg_temp_new_i64();
532 tcg_gen_movi_i64(t0, val);
533 return t0;
534}
535
536TCGv_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
544TCGv_i64 tcg_const_local_i64(int64_t val)
545{
546 TCGv_i64 t0;
547 t0 = tcg_temp_local_new_i64();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800548 tcg_gen_movi_i64(t0, val);
549 return t0;
550}
551
David 'Digit' Turnerf1d9bf12011-05-11 18:19:41 +0200552#if defined(CONFIG_DEBUG_TCG)
553void tcg_clear_temp_count(void)
554{
555 TCGContext *s = &tcg_ctx;
556 s->temps_in_use = 0;
557}
558
559int 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
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800573void 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
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800592/* 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(). */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700595void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags,
596 int sizemask, TCGArg ret, int nargs, TCGArg *args)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800597{
David 'Digit' Turnerf1d9bf12011-05-11 18:19:41 +0200598#ifdef TCG_TARGET_I386
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700599 int call_type;
David 'Digit' Turnerf1d9bf12011-05-11 18:19:41 +0200600#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700601 int i;
602 int real_args;
603 int nb_rets;
604 TCGArg *nparam;
David 'Digit' Turnerf1d9bf12011-05-11 18:19:41 +0200605
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
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700623 *gen_opc_ptr++ = INDEX_op_call;
624 nparam = gen_opparam_ptr++;
David 'Digit' Turnerf1d9bf12011-05-11 18:19:41 +0200625#ifdef TCG_TARGET_I386
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800626 call_type = (flags & TCG_CALL_TYPE_MASK);
David 'Digit' Turnerf1d9bf12011-05-11 18:19:41 +0200627#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700628 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
David 'Digit' Turnerf1d9bf12011-05-11 18:19:41 +0200651 int is_64bit = sizemask & (1 << (i+1)*2);
652 if (is_64bit) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800653#ifdef TCG_TARGET_I386
654 /* REGPARM case: if the third parameter is 64 bit, it is
655 allocated on the stack */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700656 if (i == 2 && call_type == TCG_CALL_TYPE_REGPARM) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800657 call_type = TCG_CALL_TYPE_REGPARM_2;
658 flags = (flags & ~TCG_CALL_TYPE_MASK) | call_type;
659 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700660#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800661#ifdef TCG_TARGET_CALL_ALIGN_ARGS
662 /* some targets want aligned 64 bit args */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700663 if (real_args & 1) {
664 *gen_opparam_ptr++ = TCG_CALL_DUMMY_ARG;
665 real_args++;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800666 }
667#endif
David 'Digit' Turnerf1d9bf12011-05-11 18:19:41 +0200668 /* 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)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700679 *gen_opparam_ptr++ = args[i] + 1;
680 *gen_opparam_ptr++ = args[i];
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800681#else
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700682 *gen_opparam_ptr++ = args[i];
683 *gen_opparam_ptr++ = args[i] + 1;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800684#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700685 real_args += 2;
David 'Digit' Turnerf1d9bf12011-05-11 18:19:41 +0200686 continue;
687 }
688#endif /* TCG_TARGET_REG_BITS < 64 */
689
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700690 *gen_opparam_ptr++ = args[i];
691 real_args++;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800692 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700693 *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;
David 'Digit' Turnerf1d9bf12011-05-11 18:19:41 +0200701
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 */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800711}
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800712
713#if TCG_TARGET_REG_BITS == 32
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700714void tcg_gen_shifti_i64(TCGv_i64 ret, TCGv_i64 arg1,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800715 int c, int right, int arith)
716{
717 if (c == 0) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700718 tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg1));
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800719 tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1));
720 } else if (c >= 32) {
721 c -= 32;
722 if (right) {
723 if (arith) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700724 tcg_gen_sari_i32(TCGV_LOW(ret), TCGV_HIGH(arg1), c);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800725 tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), 31);
726 } else {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700727 tcg_gen_shri_i32(TCGV_LOW(ret), TCGV_HIGH(arg1), c);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800728 tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
729 }
730 } else {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700731 tcg_gen_shli_i32(TCGV_HIGH(ret), TCGV_LOW(arg1), c);
732 tcg_gen_movi_i32(TCGV_LOW(ret), 0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800733 }
734 } else {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700735 TCGv_i32 t0, t1;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800736
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700737 t0 = tcg_temp_new_i32();
738 t1 = tcg_temp_new_i32();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800739 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);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700743 else
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800744 tcg_gen_shri_i32(t1, TCGV_HIGH(arg1), c);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700745 tcg_gen_shri_i32(TCGV_LOW(ret), TCGV_LOW(arg1), c);
746 tcg_gen_or_i32(TCGV_LOW(ret), TCGV_LOW(ret), t0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800747 tcg_gen_mov_i32(TCGV_HIGH(ret), t1);
748 } else {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700749 tcg_gen_shri_i32(t0, TCGV_LOW(arg1), 32 - c);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800750 /* Note: ret can be the same as arg1, so we use t1 */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700751 tcg_gen_shli_i32(t1, TCGV_LOW(arg1), c);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800752 tcg_gen_shli_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), c);
753 tcg_gen_or_i32(TCGV_HIGH(ret), TCGV_HIGH(ret), t0);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700754 tcg_gen_mov_i32(TCGV_LOW(ret), t1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800755 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700756 tcg_temp_free_i32(t0);
757 tcg_temp_free_i32(t1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800758 }
759}
760#endif
761
David 'Digit' Turnerf1d9bf12011-05-11 18:19:41 +0200762
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800763static 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
786static 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 {
David 'Digit' Turnerb9317722010-05-10 18:53:56 -0700795 if (ts->temp_local)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800796 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
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700803char *tcg_get_arg_str_i32(TCGContext *s, char *buf, int buf_size, TCGv_i32 arg)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800804{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700805 return tcg_get_arg_str_idx(s, buf, buf_size, GET_TCGV_I32(arg));
806}
807
808char *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));
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800811}
812
813static 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) */
826static 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)) {
David 'Digit' Turnerb9317722010-05-10 18:53:56 -0700833 qsort(s->helpers, s->nb_helpers, sizeof(TCGHelperInfo),
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800834 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
856static 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
870void tcg_dump_ops(TCGContext *s, FILE *outfile)
871{
872 const uint16_t *opc_ptr;
873 const TCGArg *args;
874 TCGArg arg;
David 'Digit' Turnerf1d9bf12011-05-11 18:19:41 +0200875 TCGOpcode c;
876 int i, k, nb_oargs, nb_iargs, nb_cargs, first_insn;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800877 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
David 'Digit' Turnerb9317722010-05-10 18:53:56 -0700893 if (!first_insn)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800894 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 }
David 'Digit' Turnerb9317722010-05-10 18:53:56 -0700933 } else if (c == INDEX_op_movi_i32
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800934#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;
David 'Digit' Turnerb9317722010-05-10 18:53:56 -0700944 fprintf(outfile, " %s %s,$", def->name,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800945 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) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700949 fprintf(outfile, "%s", th->name);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800950 } 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 }
David 'Digit' Turnerb9317722010-05-10 18:53:56 -0700968
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800969 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 }
David 'Digit' Turnerb9317722010-05-10 18:53:56 -0700982 switch (c) {
983 case INDEX_op_brcond_i32:
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800984#if TCG_TARGET_REG_BITS == 32
David 'Digit' Turnerb9317722010-05-10 18:53:56 -0700985 case INDEX_op_brcond2_i32:
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800986#elif TCG_TARGET_REG_BITS == 64
David 'Digit' Turnerb9317722010-05-10 18:53:56 -0700987 case INDEX_op_brcond_i64:
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800988#endif
David 'Digit' Turnerb9317722010-05-10 18:53:56 -0700989 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
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800995 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;
David 'Digit' Turnerb9317722010-05-10 18:53:56 -07001000 break;
1001 default:
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001002 i = 0;
David 'Digit' Turnerb9317722010-05-10 18:53:56 -07001003 break;
1004 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001005 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 */
1018static 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 */
1040static 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
1061void tcg_add_target_add_op_defs(const TCGTargetOpDef *tdefs)
1062{
David 'Digit' Turnerf1d9bf12011-05-11 18:19:41 +02001063 TCGOpcode op;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001064 TCGOpDef *def;
1065 const char *ct_str;
1066 int i, nb_args;
1067
1068 for(;;) {
David 'Digit' Turnerf1d9bf12011-05-11 18:19:41 +02001069 if (tdefs->op == (TCGOpcode)-1)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001070 break;
1071 op = tdefs->op;
David 'Digit' Turnerf1d9bf12011-05-11 18:19:41 +02001072 assert((unsigned)op < NB_OPS);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001073 def = &tcg_op_defs[op];
David 'Digit' Turnerb9317722010-05-10 18:53:56 -07001074#if defined(CONFIG_DEBUG_TCG)
1075 /* Duplicate entry in op definitions? */
1076 assert(!def->used);
1077 def->used = 1;
1078#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001079 nb_args = def->nb_iargs + def->nb_oargs;
1080 for(i = 0; i < nb_args; i++) {
1081 ct_str = tdefs->args_ct_str[i];
David 'Digit' Turnerb9317722010-05-10 18:53:56 -07001082 /* Incomplete TCGTargetOpDef entry? */
1083 assert(ct_str != NULL);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001084 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
David 'Digit' Turnerb9317722010-05-10 18:53:56 -07001118 /* TCGTargetOpDef entry with too much information? */
1119 assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL);
1120
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001121 /* 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
David 'Digit' Turnerb9317722010-05-10 18:53:56 -07001138#if defined(CONFIG_DEBUG_TCG)
David 'Digit' Turnerf1d9bf12011-05-11 18:19:41 +02001139 i = 0;
David 'Digit' Turnerb9317722010-05-10 18:53:56 -07001140 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? */
David 'Digit' Turnerf1d9bf12011-05-11 18:19:41 +02001143 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 }
David 'Digit' Turnerb9317722010-05-10 18:53:56 -07001148 } else {
1149 /* Missing entry in op definitions? */
David 'Digit' Turnerf1d9bf12011-05-11 18:19:41 +02001150 if (!tcg_op_defs[op].used) {
1151 fprintf(stderr, "Missing op definition for %s\n",
1152 tcg_op_defs[op].name);
1153 i = 1;
David 'Digit' Turnerb9317722010-05-10 18:53:56 -07001154 }
David 'Digit' Turnerf1d9bf12011-05-11 18:19:41 +02001155 }
1156 }
1157 if (i == 1) {
1158 tcg_abort();
David 'Digit' Turnerb9317722010-05-10 18:53:56 -07001159 }
1160#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001161}
1162
1163#ifdef USE_LIVENESS_ANALYSIS
1164
1165/* set a nop for an operation using 'nb_args' */
David 'Digit' Turnerb9317722010-05-10 18:53:56 -07001166static inline void tcg_set_nop(TCGContext *s, uint16_t *opc_ptr,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001167 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. */
1182static 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. */
1190static 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. */
1209static void tcg_liveness_analysis(TCGContext *s)
1210{
David 'Digit' Turnerf1d9bf12011-05-11 18:19:41 +02001211 int i, op_index, nb_args, nb_iargs, nb_oargs, arg, nb_ops;
1212 TCGOpcode op;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001213 TCGArg *args;
1214 const TCGOpDef *def;
1215 uint8_t *dead_temps;
1216 unsigned int dead_iargs;
David 'Digit' Turnerddf49e52009-10-05 14:06:05 -07001217
David 'Digit' Turnerbcc6ae12009-10-06 11:18:29 -07001218 /* sanity check */
1219 if (gen_opc_ptr - gen_opc_buf > OPC_BUF_SIZE) {
1220 fprintf(stderr, "PANIC: too many opcodes generated (%d > %d)\n",
David 'Digit' Turnerd9b6cb92010-10-20 19:07:28 +02001221 (int)(gen_opc_ptr - gen_opc_buf), OPC_BUF_SIZE);
David 'Digit' Turnerbcc6ae12009-10-06 11:18:29 -07001222 tcg_abort();
David 'Digit' Turnerddf49e52009-10-05 14:06:05 -07001223 }
1224
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001225 gen_opc_ptr++; /* skip end */
1226
1227 nb_ops = gen_opc_ptr - gen_opc_buf;
1228
David 'Digit' Turnerb9317722010-05-10 18:53:56 -07001229 s->op_dead_iargs = tcg_malloc(nb_ops * sizeof(uint16_t));
1230
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001231 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 }
David 'Digit' Turnerb9317722010-05-10 18:53:56 -07001259 tcg_set_nop(s, gen_opc_buf + op_index,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001260 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 }
David 'Digit' Turnerb9317722010-05-10 18:53:56 -07001269
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001270 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
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001275 /* 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:
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001312 args -= def->nb_args;
1313 nb_iargs = def->nb_iargs;
1314 nb_oargs = def->nb_oargs;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001315
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001316 /* 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;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001324 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001325 tcg_set_nop(s, gen_opc_buf + op_index, args, def->nb_args);
1326#ifdef CONFIG_PROFILER
1327 s->del_op_count++;
1328#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001329 } else {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001330 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;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001356 }
1357 break;
1358 }
1359 op_index--;
1360 }
1361
1362 if (args != gen_opparam_buf)
1363 tcg_abort();
1364}
1365#else
1366/* dummy liveness analysis */
David 'Digit' Turnerf1d9bf12011-05-11 18:19:41 +02001367static void tcg_liveness_analysis(TCGContext *s)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001368{
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
1378static 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) {
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08001409 printf("%s: %s\n",
1410 tcg_target_reg_names[i],
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001411 tcg_get_arg_str_idx(s, buf, sizeof(buf), s->reg_to_temp[i]));
1412 }
1413 }
1414}
1415
1416static 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) {
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08001428 printf("Inconsistency for register %s:\n",
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001429 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) {
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08001439 printf("Inconsistency for temp %s:\n",
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001440 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
1450static 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 */
1464static 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) {
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08001474 if (!ts->mem_allocated)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001475 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 */
1484static 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. */
1512static 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:
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08001527 reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001528 allocated_regs);
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08001529 if (!ts->mem_allocated)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001530 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. */
1546static 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. */
1557static 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
1579static 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
1600static 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) {
David 'Digit' Turnerf1d9bf12011-05-11 18:19:41 +02001628 tcg_out_mov(s, ots->type, reg, ts->reg);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001629 }
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
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08001659static void tcg_reg_alloc_op(TCGContext *s,
David 'Digit' Turnerf1d9bf12011-05-11 18:19:41 +02001660 const TCGOpDef *def, TCGOpcode opc,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001661 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 */
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08001676 memcpy(new_args + nb_oargs + nb_iargs,
1677 args + nb_oargs + nb_iargs,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001678 sizeof(TCGArg) * def->nb_cargs);
1679
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08001680 /* satisfy input constraints */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001681 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 */
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08001721 if (!IS_DEAD_IARG(i - nb_oargs))
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001722 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:
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08001730 /* allocate a new register matching the constraint
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001731 and move the temporary register into it */
1732 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
David 'Digit' Turnerf1d9bf12011-05-11 18:19:41 +02001733 tcg_out_mov(s, ts->type, reg, ts->reg);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001734 }
1735 new_args[i] = reg;
1736 const_args[i] = 0;
1737 tcg_regset_set_reg(allocated_regs, reg);
1738 iarg_end: ;
1739 }
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08001740
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001741 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 }
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08001756
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001757 if (def->flags & TCG_OPF_CALL_CLOBBER) {
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08001758 /* XXX: permit generic clobber register list ? */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001759 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) */
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08001766
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001767 /* store globals and free associated registers (we assume the insn
1768 can modify any global. */
1769 save_globals(s, allocated_regs);
1770 }
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08001771
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001772 /* 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 */
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08001799 ts->mem_coherent = 0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001800 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);
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08001809
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001810 /* 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) {
David 'Digit' Turnerf1d9bf12011-05-11 18:19:41 +02001815 tcg_out_mov(s, ts->type, ts->reg, reg);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001816 }
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
1826static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def,
David 'Digit' Turnerf1d9bf12011-05-11 18:19:41 +02001827 TCGOpcode opc, const TCGArg *args,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001828 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);
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08001853 call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) &
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001854 ~(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) {
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08001871 reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001872 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) {
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08001877 reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001878 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 }
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08001890
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001891 /* 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) {
David 'Digit' Turnerf1d9bf12011-05-11 18:19:41 +02001901 tcg_out_mov(s, ts->type, reg, ts->reg);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001902 }
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 }
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08001914
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001915 /* 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);
David 'Digit' Turnerf1d9bf12011-05-11 18:19:41 +02001930 tcg_out_mov(s, ts->type, reg, ts->reg);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001931 }
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 }
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08001947
1948
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001949 /* 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 }
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08001961
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001962 /* 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 }
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08001968
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001969 /* store globals and free associated registers (we assume the call
1970 can modify any global. */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001971 if (!(flags & TCG_CALL_CONST)) {
1972 save_globals(s, allocated_regs);
1973 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001974
1975 tcg_out_op(s, opc, &func_arg, &const_func_arg);
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08001976
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001977 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) {
David 'Digit' Turnerf1d9bf12011-05-11 18:19:41 +02001989 tcg_out_mov(s, ts->type, ts->reg, reg);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001990 }
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;
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08001996 ts->mem_coherent = 0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001997 s->reg_to_temp[reg] = arg;
1998 }
1999 }
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08002000
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002001 return nb_iargs + nb_oargs + def->nb_cargs + 1;
2002}
2003
2004#ifdef CONFIG_PROFILER
2005
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002006static int64_t tcg_table_op_count[NB_OPS];
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002007
David 'Digit' Turnerf1d9bf12011-05-11 18:19:41 +02002008static void dump_op_count(void)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002009{
2010 int i;
2011 FILE *f;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002012 f = fopen("/tmp/op.log", "w");
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002013 for(i = INDEX_op_end; i < NB_OPS; i++) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002014 fprintf(f, "%s %" PRId64 "\n", tcg_op_defs[i].name, tcg_table_op_count[i]);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002015 }
2016 fclose(f);
2017}
2018#endif
2019
2020
2021static inline int tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf,
2022 long search_pc)
2023{
David 'Digit' Turnerf1d9bf12011-05-11 18:19:41 +02002024 TCGOpcode opc;
2025 int op_index;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002026 const TCGOpDef *def;
2027 unsigned int dead_iargs;
2028 const TCGArg *args;
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08002029#ifdef CONFIG_MEMCHECK
2030 unsigned int tpc2gpc_index = 0;
2031#endif // CONFIG_MEMCHECK
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002032
Andrew Hsieh0b397972012-06-11 17:03:18 +08002033#if !SUPPORT_GLOBAL_REGISTER_VARIABLE
2034 printf("ERROR: This emulator is built by compiler without global register variable\n"
2035 "support! Emulator reserves a register to point to target architecture state\n"
2036 "for better code generation. LLVM-based compilers such as clang and llvm-gcc\n"
2037 "currently don't support global register variable. Please see\n"
2038 "http://source.android.com/source/initializing.html for detail.\n\n");
2039 tcg_abort();
2040#endif
2041
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002042#ifdef DEBUG_DISAS
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002043 if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP))) {
2044 qemu_log("OP:\n");
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002045 tcg_dump_ops(s, logfile);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002046 qemu_log("\n");
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002047 }
2048#endif
2049
2050#ifdef CONFIG_PROFILER
2051 s->la_time -= profile_getclock();
2052#endif
2053 tcg_liveness_analysis(s);
2054#ifdef CONFIG_PROFILER
2055 s->la_time += profile_getclock();
2056#endif
2057
2058#ifdef DEBUG_DISAS
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002059 if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT))) {
David 'Digit' Turnerb9317722010-05-10 18:53:56 -07002060 qemu_log("OP after liveness analysis:\n");
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002061 tcg_dump_ops(s, logfile);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002062 qemu_log("\n");
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002063 }
2064#endif
2065
2066 tcg_reg_alloc_start(s);
2067
2068 s->code_buf = gen_code_buf;
2069 s->code_ptr = gen_code_buf;
2070
2071 args = gen_opparam_buf;
2072 op_index = 0;
2073
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08002074#ifdef CONFIG_MEMCHECK
2075 gen_opc_tpc2gpc_pairs = 0;
2076#endif // CONFIG_MEMCHECK
2077
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002078 for(;;) {
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08002079#ifdef CONFIG_MEMCHECK
2080 /* On condition that memcheck is enabled, and operation index reached
2081 * new operation in the guest code, save (pc_tb, pc_guest) pair into
2082 * gen_opc_tpc2gpc array. Note that we do that only on condition that
2083 * search_pc is < 0. This way we make sure that this is "normal"
2084 * translation, called from tcg_gen_code, and not from
2085 * tcg_gen_code_search_pc. */
2086 if (memcheck_enabled && search_pc < 0 &&
2087 gen_opc_instr_start[op_index]) {
David 'Digit' Turnerd9b6cb92010-10-20 19:07:28 +02002088 gen_opc_tpc2gpc_ptr[tpc2gpc_index] = s->code_ptr;
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08002089 tpc2gpc_index++;
David 'Digit' Turnerd9b6cb92010-10-20 19:07:28 +02002090 gen_opc_tpc2gpc_ptr[tpc2gpc_index] = (void*)(ptrdiff_t)gen_opc_pc[op_index];
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08002091 tpc2gpc_index++;
2092 gen_opc_tpc2gpc_pairs++;
2093 }
2094#endif // CONFIG_MEMCHECK
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002095 opc = gen_opc_buf[op_index];
2096#ifdef CONFIG_PROFILER
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002097 tcg_table_op_count[opc]++;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002098#endif
2099 def = &tcg_op_defs[opc];
2100#if 0
2101 printf("%s: %d %d %d\n", def->name,
2102 def->nb_oargs, def->nb_iargs, def->nb_cargs);
2103 // dump_regs(s);
2104#endif
2105 switch(opc) {
2106 case INDEX_op_mov_i32:
2107#if TCG_TARGET_REG_BITS == 64
2108 case INDEX_op_mov_i64:
2109#endif
2110 dead_iargs = s->op_dead_iargs[op_index];
2111 tcg_reg_alloc_mov(s, def, args, dead_iargs);
2112 break;
2113 case INDEX_op_movi_i32:
2114#if TCG_TARGET_REG_BITS == 64
2115 case INDEX_op_movi_i64:
2116#endif
2117 tcg_reg_alloc_movi(s, args);
2118 break;
2119 case INDEX_op_debug_insn_start:
2120 /* debug instruction */
2121 break;
2122 case INDEX_op_nop:
2123 case INDEX_op_nop1:
2124 case INDEX_op_nop2:
2125 case INDEX_op_nop3:
2126 break;
2127 case INDEX_op_nopn:
2128 args += args[0];
2129 goto next;
2130 case INDEX_op_discard:
2131 {
2132 TCGTemp *ts;
2133 ts = &s->temps[args[0]];
2134 /* mark the temporary as dead */
2135 if (!ts->fixed_reg) {
2136 if (ts->val_type == TEMP_VAL_REG)
2137 s->reg_to_temp[ts->reg] = -1;
2138 ts->val_type = TEMP_VAL_DEAD;
2139 }
2140 }
2141 break;
2142 case INDEX_op_set_label:
2143 tcg_reg_alloc_bb_end(s, s->reserved_regs);
2144 tcg_out_label(s, args[0], (long)s->code_ptr);
2145 break;
2146 case INDEX_op_call:
2147 dead_iargs = s->op_dead_iargs[op_index];
2148 args += tcg_reg_alloc_call(s, def, opc, args, dead_iargs);
2149 goto next;
2150 case INDEX_op_end:
2151 goto the_end;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002152 default:
2153 /* Note: in order to speed up the code, it would be much
2154 faster to have specialized register allocator functions for
2155 some common argument patterns */
2156 dead_iargs = s->op_dead_iargs[op_index];
2157 tcg_reg_alloc_op(s, def, opc, args, dead_iargs);
2158 break;
2159 }
2160 args += def->nb_args;
2161 next:
2162 if (search_pc >= 0 && search_pc < s->code_ptr - gen_code_buf) {
2163 return op_index;
2164 }
2165 op_index++;
2166#ifndef NDEBUG
2167 check_regs(s);
2168#endif
2169 }
2170 the_end:
2171 return -1;
2172}
2173
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002174int tcg_gen_code(TCGContext *s, uint8_t *gen_code_buf)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002175{
2176#ifdef CONFIG_PROFILER
2177 {
2178 int n;
2179 n = (gen_opc_ptr - gen_opc_buf);
2180 s->op_count += n;
2181 if (n > s->op_count_max)
2182 s->op_count_max = n;
2183
2184 s->temp_count += s->nb_temps;
2185 if (s->nb_temps > s->temp_count_max)
2186 s->temp_count_max = s->nb_temps;
2187 }
2188#endif
2189
David 'Digit' Turnerbcc6ae12009-10-06 11:18:29 -07002190 /* sanity check */
2191 if (gen_opc_ptr - gen_opc_buf > OPC_BUF_SIZE) {
2192 fprintf(stderr, "PANIC: too many opcodes generated (%d > %d)\n",
David 'Digit' Turnerd9b6cb92010-10-20 19:07:28 +02002193 (int)(gen_opc_ptr - gen_opc_buf), OPC_BUF_SIZE);
David 'Digit' Turnerbcc6ae12009-10-06 11:18:29 -07002194 tcg_abort();
2195 }
2196
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002197 tcg_gen_code_common(s, gen_code_buf, -1);
2198
2199 /* flush instruction cache */
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08002200 flush_icache_range((unsigned long)gen_code_buf,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002201 (unsigned long)s->code_ptr);
2202 return s->code_ptr - gen_code_buf;
2203}
2204
2205/* Return the index of the micro operation such as the pc after is <
2206 offset bytes from the start of the TB. The contents of gen_code_buf must
2207 not be changed, though writing the same values is ok.
2208 Return -1 if not found. */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002209int tcg_gen_code_search_pc(TCGContext *s, uint8_t *gen_code_buf, long offset)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002210{
2211 return tcg_gen_code_common(s, gen_code_buf, offset);
2212}
2213
2214#ifdef CONFIG_PROFILER
David 'Digit' Turnerf1d9bf12011-05-11 18:19:41 +02002215void tcg_dump_info(FILE *f, fprintf_function cpu_fprintf)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002216{
2217 TCGContext *s = &tcg_ctx;
2218 int64_t tot;
2219
2220 tot = s->interm_time + s->code_time;
2221 cpu_fprintf(f, "JIT cycles %" PRId64 " (%0.3f s at 2.4 GHz)\n",
2222 tot, tot / 2.4e9);
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08002223 cpu_fprintf(f, "translated TBs %" PRId64 " (aborted=%" PRId64 " %0.1f%%)\n",
2224 s->tb_count,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002225 s->tb_count1 - s->tb_count,
2226 s->tb_count1 ? (double)(s->tb_count1 - s->tb_count) / s->tb_count1 * 100.0 : 0);
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08002227 cpu_fprintf(f, "avg ops/TB %0.1f max=%d\n",
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002228 s->tb_count ? (double)s->op_count / s->tb_count : 0, s->op_count_max);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002229 cpu_fprintf(f, "deleted ops/TB %0.2f\n",
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08002230 s->tb_count ?
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002231 (double)s->del_op_count / s->tb_count : 0);
2232 cpu_fprintf(f, "avg temps/TB %0.2f max=%d\n",
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08002233 s->tb_count ?
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002234 (double)s->temp_count / s->tb_count : 0,
2235 s->temp_count_max);
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08002236
2237 cpu_fprintf(f, "cycles/op %0.1f\n",
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002238 s->op_count ? (double)tot / s->op_count : 0);
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08002239 cpu_fprintf(f, "cycles/in byte %0.1f\n",
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002240 s->code_in_len ? (double)tot / s->code_in_len : 0);
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08002241 cpu_fprintf(f, "cycles/out byte %0.1f\n",
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002242 s->code_out_len ? (double)tot / s->code_out_len : 0);
2243 if (tot == 0)
2244 tot = 1;
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08002245 cpu_fprintf(f, " gen_interm time %0.1f%%\n",
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002246 (double)s->interm_time / tot * 100.0);
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08002247 cpu_fprintf(f, " gen_code time %0.1f%%\n",
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002248 (double)s->code_time / tot * 100.0);
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08002249 cpu_fprintf(f, "liveness/code time %0.1f%%\n",
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002250 (double)s->la_time / (s->code_time ? s->code_time : 1) * 100.0);
2251 cpu_fprintf(f, "cpu_restore count %" PRId64 "\n",
2252 s->restore_count);
2253 cpu_fprintf(f, " avg cycles %0.1f\n",
2254 s->restore_count ? (double)s->restore_time / s->restore_count : 0);
David 'Digit' Turnerb9317722010-05-10 18:53:56 -07002255
2256 dump_op_count();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002257}
2258#else
David 'Digit' Turnerf1d9bf12011-05-11 18:19:41 +02002259void tcg_dump_info(FILE *f, fprintf_function cpu_fprintf)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002260{
2261 cpu_fprintf(f, "[TCG profiler not compiled]\n");
2262}
2263#endif