1c896fe29Sbellard /* 2c896fe29Sbellard * Tiny Code Generator for QEMU 3c896fe29Sbellard * 4c896fe29Sbellard * Copyright (c) 2008 Fabrice Bellard 5c896fe29Sbellard * 6c896fe29Sbellard * Permission is hereby granted, free of charge, to any person obtaining a copy 7c896fe29Sbellard * of this software and associated documentation files (the "Software"), to deal 8c896fe29Sbellard * in the Software without restriction, including without limitation the rights 9c896fe29Sbellard * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10c896fe29Sbellard * copies of the Software, and to permit persons to whom the Software is 11c896fe29Sbellard * furnished to do so, subject to the following conditions: 12c896fe29Sbellard * 13c896fe29Sbellard * The above copyright notice and this permission notice shall be included in 14c896fe29Sbellard * all copies or substantial portions of the Software. 15c896fe29Sbellard * 16c896fe29Sbellard * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17c896fe29Sbellard * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18c896fe29Sbellard * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19c896fe29Sbellard * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20c896fe29Sbellard * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21c896fe29Sbellard * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22c896fe29Sbellard * THE SOFTWARE. 23c896fe29Sbellard */ 24c896fe29Sbellard 25c896fe29Sbellard /* define it to use liveness analysis (better code) */ 26c896fe29Sbellard #define USE_LIVENESS_ANALYSIS 278f2e8c07SKirill Batuzov #define USE_TCG_OPTIMIZATIONS 28c896fe29Sbellard 29cca82982Saurel32 #include "config.h" 30cca82982Saurel32 31813da627SRichard Henderson /* Define to jump the ELF file used to communicate with GDB. */ 32813da627SRichard Henderson #undef DEBUG_JIT 33813da627SRichard Henderson 34a6c6f76cSBlue Swirl #if !defined(CONFIG_DEBUG_TCG) && !defined(NDEBUG) 35cca82982Saurel32 /* define it to suppress various consistency checks (faster) */ 36cca82982Saurel32 #define NDEBUG 37cca82982Saurel32 #endif 38cca82982Saurel32 39ca10f867Saurel32 #include "qemu-common.h" 40902b3d5cSmalc #include "cache-utils.h" 41379f6698SPaul Brook #include "host-utils.h" 422d8ebcf9SRichard Henderson #include "qemu-timer.h" 43c896fe29Sbellard 44c896fe29Sbellard /* Note: the long term plan is to reduce the dependancies on the QEMU 45c896fe29Sbellard CPU definitions. Currently they are used for qemu_ld/st 46c896fe29Sbellard instructions */ 47c896fe29Sbellard #define NO_CPU_IO_DEFS 48c896fe29Sbellard #include "cpu.h" 49c896fe29Sbellard 50c896fe29Sbellard #include "tcg-op.h" 51813da627SRichard Henderson 52813da627SRichard Henderson #if TCG_TARGET_REG_BITS == 64 53813da627SRichard Henderson # define ELF_CLASS ELFCLASS64 54813da627SRichard Henderson #else 55813da627SRichard Henderson # define ELF_CLASS ELFCLASS32 56813da627SRichard Henderson #endif 57813da627SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN 58813da627SRichard Henderson # define ELF_DATA ELFDATA2MSB 59813da627SRichard Henderson #else 60813da627SRichard Henderson # define ELF_DATA ELFDATA2LSB 61813da627SRichard Henderson #endif 62813da627SRichard Henderson 63c896fe29Sbellard #include "elf.h" 64c896fe29Sbellard 65c0ad3001SStefan Weil /* Forward declarations for functions declared in tcg-target.c and used here. */ 66e4d58b41SRichard Henderson static void tcg_target_init(TCGContext *s); 67e4d58b41SRichard Henderson static void tcg_target_qemu_prologue(TCGContext *s); 68c896fe29Sbellard static void patch_reloc(uint8_t *code_ptr, int type, 69f54b3f92Saurel32 tcg_target_long value, tcg_target_long addend); 70c896fe29Sbellard 71813da627SRichard Henderson static void tcg_register_jit_int(void *buf, size_t size, 72813da627SRichard Henderson void *debug_frame, size_t debug_frame_size) 73813da627SRichard Henderson __attribute__((unused)); 74813da627SRichard Henderson 75c0ad3001SStefan Weil /* Forward declarations for functions declared and used in tcg-target.c. */ 76c0ad3001SStefan Weil static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str); 772a534affSRichard Henderson static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1, 78c0ad3001SStefan Weil tcg_target_long arg2); 792a534affSRichard Henderson static void tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg); 80c0ad3001SStefan Weil static void tcg_out_movi(TCGContext *s, TCGType type, 812a534affSRichard Henderson TCGReg ret, tcg_target_long arg); 82c0ad3001SStefan Weil static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, 83c0ad3001SStefan Weil const int *const_args); 842a534affSRichard Henderson static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1, 85c0ad3001SStefan Weil tcg_target_long arg2); 86c0ad3001SStefan Weil static int tcg_target_const_match(tcg_target_long val, 87c0ad3001SStefan Weil const TCGArgConstraint *arg_ct); 88c0ad3001SStefan Weil 898399ad59SRichard Henderson TCGOpDef tcg_op_defs[] = { 900e2029a0SAurelien Jarno #define DEF(s, oargs, iargs, cargs, flags) { #s, oargs, iargs, cargs, iargs + oargs + cargs, flags }, 91c896fe29Sbellard #include "tcg-opc.h" 92c896fe29Sbellard #undef DEF 93c896fe29Sbellard }; 942a24374aSStefan Weil const size_t tcg_op_defs_max = ARRAY_SIZE(tcg_op_defs); 95c896fe29Sbellard 96b1d8e52eSblueswir1 static TCGRegSet tcg_target_available_regs[2]; 97b1d8e52eSblueswir1 static TCGRegSet tcg_target_call_clobber_regs; 98c896fe29Sbellard 99c896fe29Sbellard /* XXX: move that inside the context */ 100c896fe29Sbellard uint16_t *gen_opc_ptr; 101c896fe29Sbellard TCGArg *gen_opparam_ptr; 102c896fe29Sbellard 103c896fe29Sbellard static inline void tcg_out8(TCGContext *s, uint8_t v) 104c896fe29Sbellard { 105c896fe29Sbellard *s->code_ptr++ = v; 106c896fe29Sbellard } 107c896fe29Sbellard 108c896fe29Sbellard static inline void tcg_out16(TCGContext *s, uint16_t v) 109c896fe29Sbellard { 110c896fe29Sbellard *(uint16_t *)s->code_ptr = v; 111c896fe29Sbellard s->code_ptr += 2; 112c896fe29Sbellard } 113c896fe29Sbellard 114c896fe29Sbellard static inline void tcg_out32(TCGContext *s, uint32_t v) 115c896fe29Sbellard { 116c896fe29Sbellard *(uint32_t *)s->code_ptr = v; 117c896fe29Sbellard s->code_ptr += 4; 118c896fe29Sbellard } 119c896fe29Sbellard 120c896fe29Sbellard /* label relocation processing */ 121c896fe29Sbellard 122a5ad5916SStefan Weil static void tcg_out_reloc(TCGContext *s, uint8_t *code_ptr, int type, 123c896fe29Sbellard int label_index, long addend) 124c896fe29Sbellard { 125c896fe29Sbellard TCGLabel *l; 126c896fe29Sbellard TCGRelocation *r; 127c896fe29Sbellard 128c896fe29Sbellard l = &s->labels[label_index]; 129c896fe29Sbellard if (l->has_value) { 130623e265cSpbrook /* FIXME: This may break relocations on RISC targets that 131623e265cSpbrook modify instruction fields in place. The caller may not have 132623e265cSpbrook written the initial value. */ 133f54b3f92Saurel32 patch_reloc(code_ptr, type, l->u.value, addend); 134c896fe29Sbellard } else { 135c896fe29Sbellard /* add a new relocation entry */ 136c896fe29Sbellard r = tcg_malloc(sizeof(TCGRelocation)); 137c896fe29Sbellard r->type = type; 138c896fe29Sbellard r->ptr = code_ptr; 139c896fe29Sbellard r->addend = addend; 140c896fe29Sbellard r->next = l->u.first_reloc; 141c896fe29Sbellard l->u.first_reloc = r; 142c896fe29Sbellard } 143c896fe29Sbellard } 144c896fe29Sbellard 1459d6fca70SStefan Weil static void tcg_out_label(TCGContext *s, int label_index, void *ptr) 146c896fe29Sbellard { 147c896fe29Sbellard TCGLabel *l; 148c896fe29Sbellard TCGRelocation *r; 1499d6fca70SStefan Weil tcg_target_long value = (tcg_target_long)ptr; 150c896fe29Sbellard 151c896fe29Sbellard l = &s->labels[label_index]; 152c896fe29Sbellard if (l->has_value) 153c896fe29Sbellard tcg_abort(); 154c896fe29Sbellard r = l->u.first_reloc; 155c896fe29Sbellard while (r != NULL) { 156f54b3f92Saurel32 patch_reloc(r->ptr, r->type, value, r->addend); 157c896fe29Sbellard r = r->next; 158c896fe29Sbellard } 159c896fe29Sbellard l->has_value = 1; 160c896fe29Sbellard l->u.value = value; 161c896fe29Sbellard } 162c896fe29Sbellard 163c896fe29Sbellard int gen_new_label(void) 164c896fe29Sbellard { 165c896fe29Sbellard TCGContext *s = &tcg_ctx; 166c896fe29Sbellard int idx; 167c896fe29Sbellard TCGLabel *l; 168c896fe29Sbellard 169c896fe29Sbellard if (s->nb_labels >= TCG_MAX_LABELS) 170c896fe29Sbellard tcg_abort(); 171c896fe29Sbellard idx = s->nb_labels++; 172c896fe29Sbellard l = &s->labels[idx]; 173c896fe29Sbellard l->has_value = 0; 174c896fe29Sbellard l->u.first_reloc = NULL; 175c896fe29Sbellard return idx; 176c896fe29Sbellard } 177c896fe29Sbellard 178c896fe29Sbellard #include "tcg-target.c" 179c896fe29Sbellard 180c896fe29Sbellard /* pool based memory allocation */ 181c896fe29Sbellard void *tcg_malloc_internal(TCGContext *s, int size) 182c896fe29Sbellard { 183c896fe29Sbellard TCGPool *p; 184c896fe29Sbellard int pool_size; 185c896fe29Sbellard 186c896fe29Sbellard if (size > TCG_POOL_CHUNK_SIZE) { 187c896fe29Sbellard /* big malloc: insert a new pool (XXX: could optimize) */ 1887267c094SAnthony Liguori p = g_malloc(sizeof(TCGPool) + size); 189c896fe29Sbellard p->size = size; 1904055299eSKirill Batuzov p->next = s->pool_first_large; 1914055299eSKirill Batuzov s->pool_first_large = p; 1924055299eSKirill Batuzov return p->data; 193c896fe29Sbellard } else { 194c896fe29Sbellard p = s->pool_current; 195c896fe29Sbellard if (!p) { 196c896fe29Sbellard p = s->pool_first; 197c896fe29Sbellard if (!p) 198c896fe29Sbellard goto new_pool; 199c896fe29Sbellard } else { 200c896fe29Sbellard if (!p->next) { 201c896fe29Sbellard new_pool: 202c896fe29Sbellard pool_size = TCG_POOL_CHUNK_SIZE; 2037267c094SAnthony Liguori p = g_malloc(sizeof(TCGPool) + pool_size); 204c896fe29Sbellard p->size = pool_size; 205c896fe29Sbellard p->next = NULL; 206c896fe29Sbellard if (s->pool_current) 207c896fe29Sbellard s->pool_current->next = p; 208c896fe29Sbellard else 209c896fe29Sbellard s->pool_first = p; 210c896fe29Sbellard } else { 211c896fe29Sbellard p = p->next; 212c896fe29Sbellard } 213c896fe29Sbellard } 214c896fe29Sbellard } 215c896fe29Sbellard s->pool_current = p; 216c896fe29Sbellard s->pool_cur = p->data + size; 217c896fe29Sbellard s->pool_end = p->data + p->size; 218c896fe29Sbellard return p->data; 219c896fe29Sbellard } 220c896fe29Sbellard 221c896fe29Sbellard void tcg_pool_reset(TCGContext *s) 222c896fe29Sbellard { 2234055299eSKirill Batuzov TCGPool *p, *t; 2244055299eSKirill Batuzov for (p = s->pool_first_large; p; p = t) { 2254055299eSKirill Batuzov t = p->next; 2264055299eSKirill Batuzov g_free(p); 2274055299eSKirill Batuzov } 2284055299eSKirill Batuzov s->pool_first_large = NULL; 229c896fe29Sbellard s->pool_cur = s->pool_end = NULL; 230c896fe29Sbellard s->pool_current = NULL; 231c896fe29Sbellard } 232c896fe29Sbellard 233c896fe29Sbellard void tcg_context_init(TCGContext *s) 234c896fe29Sbellard { 235c896fe29Sbellard int op, total_args, n; 236c896fe29Sbellard TCGOpDef *def; 237c896fe29Sbellard TCGArgConstraint *args_ct; 238c896fe29Sbellard int *sorted_args; 239c896fe29Sbellard 240c896fe29Sbellard memset(s, 0, sizeof(*s)); 241c896fe29Sbellard s->nb_globals = 0; 242c896fe29Sbellard 243c896fe29Sbellard /* Count total number of arguments and allocate the corresponding 244c896fe29Sbellard space */ 245c896fe29Sbellard total_args = 0; 246c896fe29Sbellard for(op = 0; op < NB_OPS; op++) { 247c896fe29Sbellard def = &tcg_op_defs[op]; 248c896fe29Sbellard n = def->nb_iargs + def->nb_oargs; 249c896fe29Sbellard total_args += n; 250c896fe29Sbellard } 251c896fe29Sbellard 2527267c094SAnthony Liguori args_ct = g_malloc(sizeof(TCGArgConstraint) * total_args); 2537267c094SAnthony Liguori sorted_args = g_malloc(sizeof(int) * total_args); 254c896fe29Sbellard 255c896fe29Sbellard for(op = 0; op < NB_OPS; op++) { 256c896fe29Sbellard def = &tcg_op_defs[op]; 257c896fe29Sbellard def->args_ct = args_ct; 258c896fe29Sbellard def->sorted_args = sorted_args; 259c896fe29Sbellard n = def->nb_iargs + def->nb_oargs; 260c896fe29Sbellard sorted_args += n; 261c896fe29Sbellard args_ct += n; 262c896fe29Sbellard } 263c896fe29Sbellard 264c896fe29Sbellard tcg_target_init(s); 2659002ec79SRichard Henderson } 266b03cce8eSbellard 2679002ec79SRichard Henderson void tcg_prologue_init(TCGContext *s) 2689002ec79SRichard Henderson { 269b03cce8eSbellard /* init global prologue and epilogue */ 270b03cce8eSbellard s->code_buf = code_gen_prologue; 271b03cce8eSbellard s->code_ptr = s->code_buf; 272b03cce8eSbellard tcg_target_qemu_prologue(s); 2732aeabc08SStefan Weil flush_icache_range((tcg_target_ulong)s->code_buf, 2742aeabc08SStefan Weil (tcg_target_ulong)s->code_ptr); 275c896fe29Sbellard } 276c896fe29Sbellard 277c896fe29Sbellard void tcg_set_frame(TCGContext *s, int reg, 278c896fe29Sbellard tcg_target_long start, tcg_target_long size) 279c896fe29Sbellard { 280c896fe29Sbellard s->frame_start = start; 281c896fe29Sbellard s->frame_end = start + size; 282c896fe29Sbellard s->frame_reg = reg; 283c896fe29Sbellard } 284c896fe29Sbellard 285c896fe29Sbellard void tcg_func_start(TCGContext *s) 286c896fe29Sbellard { 287e8996ee0Sbellard int i; 288c896fe29Sbellard tcg_pool_reset(s); 289c896fe29Sbellard s->nb_temps = s->nb_globals; 290641d5fbeSbellard for(i = 0; i < (TCG_TYPE_COUNT * 2); i++) 291e8996ee0Sbellard s->first_free_temp[i] = -1; 292c896fe29Sbellard s->labels = tcg_malloc(sizeof(TCGLabel) * TCG_MAX_LABELS); 293c896fe29Sbellard s->nb_labels = 0; 294c896fe29Sbellard s->current_frame_offset = s->frame_start; 295c896fe29Sbellard 2960a209d4bSRichard Henderson #ifdef CONFIG_DEBUG_TCG 2970a209d4bSRichard Henderson s->goto_tb_issue_mask = 0; 2980a209d4bSRichard Henderson #endif 2990a209d4bSRichard Henderson 300*92414b31SEvgeny Voevodin s->gen_opc_ptr = s->gen_opc_buf; 301c4afe5c4SEvgeny Voevodin s->gen_opparam_ptr = gen_opparam_buf; 302b76f0d8cSYeongkyoon Lee 303b76f0d8cSYeongkyoon Lee #if defined(CONFIG_QEMU_LDST_OPTIMIZATION) && defined(CONFIG_SOFTMMU) 304b76f0d8cSYeongkyoon Lee /* Initialize qemu_ld/st labels to assist code generation at the end of TB 305b76f0d8cSYeongkyoon Lee for TLB miss cases at the end of TB */ 306b76f0d8cSYeongkyoon Lee s->qemu_ldst_labels = tcg_malloc(sizeof(TCGLabelQemuLdst) * 307b76f0d8cSYeongkyoon Lee TCG_MAX_QEMU_LDST); 308b76f0d8cSYeongkyoon Lee s->nb_qemu_ldst_labels = 0; 309b76f0d8cSYeongkyoon Lee #endif 310c896fe29Sbellard } 311c896fe29Sbellard 312c896fe29Sbellard static inline void tcg_temp_alloc(TCGContext *s, int n) 313c896fe29Sbellard { 314c896fe29Sbellard if (n > TCG_MAX_TEMPS) 315c896fe29Sbellard tcg_abort(); 316c896fe29Sbellard } 317c896fe29Sbellard 318a7812ae4Spbrook static inline int tcg_global_reg_new_internal(TCGType type, int reg, 319a7812ae4Spbrook const char *name) 320c896fe29Sbellard { 321c896fe29Sbellard TCGContext *s = &tcg_ctx; 322c896fe29Sbellard TCGTemp *ts; 323c896fe29Sbellard int idx; 324c896fe29Sbellard 325c896fe29Sbellard #if TCG_TARGET_REG_BITS == 32 326c896fe29Sbellard if (type != TCG_TYPE_I32) 327c896fe29Sbellard tcg_abort(); 328c896fe29Sbellard #endif 329c896fe29Sbellard if (tcg_regset_test_reg(s->reserved_regs, reg)) 330c896fe29Sbellard tcg_abort(); 331c896fe29Sbellard idx = s->nb_globals; 332c896fe29Sbellard tcg_temp_alloc(s, s->nb_globals + 1); 333c896fe29Sbellard ts = &s->temps[s->nb_globals]; 334c896fe29Sbellard ts->base_type = type; 335c896fe29Sbellard ts->type = type; 336c896fe29Sbellard ts->fixed_reg = 1; 337c896fe29Sbellard ts->reg = reg; 338c896fe29Sbellard ts->name = name; 339c896fe29Sbellard s->nb_globals++; 340c896fe29Sbellard tcg_regset_set_reg(s->reserved_regs, reg); 341a7812ae4Spbrook return idx; 342a7812ae4Spbrook } 343a7812ae4Spbrook 344a7812ae4Spbrook TCGv_i32 tcg_global_reg_new_i32(int reg, const char *name) 345a7812ae4Spbrook { 346a7812ae4Spbrook int idx; 347a7812ae4Spbrook 348a7812ae4Spbrook idx = tcg_global_reg_new_internal(TCG_TYPE_I32, reg, name); 349a7812ae4Spbrook return MAKE_TCGV_I32(idx); 350a7812ae4Spbrook } 351a7812ae4Spbrook 352a7812ae4Spbrook TCGv_i64 tcg_global_reg_new_i64(int reg, const char *name) 353a7812ae4Spbrook { 354a7812ae4Spbrook int idx; 355a7812ae4Spbrook 356a7812ae4Spbrook idx = tcg_global_reg_new_internal(TCG_TYPE_I64, reg, name); 357a7812ae4Spbrook return MAKE_TCGV_I64(idx); 358c896fe29Sbellard } 359c896fe29Sbellard 360a7812ae4Spbrook static inline int tcg_global_mem_new_internal(TCGType type, int reg, 361a7812ae4Spbrook tcg_target_long offset, 362c896fe29Sbellard const char *name) 363c896fe29Sbellard { 364c896fe29Sbellard TCGContext *s = &tcg_ctx; 365c896fe29Sbellard TCGTemp *ts; 366c896fe29Sbellard int idx; 367c896fe29Sbellard 368c896fe29Sbellard idx = s->nb_globals; 369c896fe29Sbellard #if TCG_TARGET_REG_BITS == 32 370c896fe29Sbellard if (type == TCG_TYPE_I64) { 371c896fe29Sbellard char buf[64]; 372c588979bSths tcg_temp_alloc(s, s->nb_globals + 2); 373c896fe29Sbellard ts = &s->temps[s->nb_globals]; 374c896fe29Sbellard ts->base_type = type; 375c896fe29Sbellard ts->type = TCG_TYPE_I32; 376c896fe29Sbellard ts->fixed_reg = 0; 377c896fe29Sbellard ts->mem_allocated = 1; 378c896fe29Sbellard ts->mem_reg = reg; 379c896fe29Sbellard #ifdef TCG_TARGET_WORDS_BIGENDIAN 380c896fe29Sbellard ts->mem_offset = offset + 4; 381c896fe29Sbellard #else 382c896fe29Sbellard ts->mem_offset = offset; 383c896fe29Sbellard #endif 384c896fe29Sbellard pstrcpy(buf, sizeof(buf), name); 385c896fe29Sbellard pstrcat(buf, sizeof(buf), "_0"); 386c896fe29Sbellard ts->name = strdup(buf); 387c896fe29Sbellard ts++; 388c896fe29Sbellard 389c896fe29Sbellard ts->base_type = type; 390c896fe29Sbellard ts->type = TCG_TYPE_I32; 391c896fe29Sbellard ts->fixed_reg = 0; 392c896fe29Sbellard ts->mem_allocated = 1; 393c896fe29Sbellard ts->mem_reg = reg; 394c896fe29Sbellard #ifdef TCG_TARGET_WORDS_BIGENDIAN 395c896fe29Sbellard ts->mem_offset = offset; 396c896fe29Sbellard #else 397c896fe29Sbellard ts->mem_offset = offset + 4; 398c896fe29Sbellard #endif 399c896fe29Sbellard pstrcpy(buf, sizeof(buf), name); 400c896fe29Sbellard pstrcat(buf, sizeof(buf), "_1"); 401c896fe29Sbellard ts->name = strdup(buf); 402c896fe29Sbellard 403c896fe29Sbellard s->nb_globals += 2; 404c896fe29Sbellard } else 405c896fe29Sbellard #endif 406c896fe29Sbellard { 407c896fe29Sbellard tcg_temp_alloc(s, s->nb_globals + 1); 408c896fe29Sbellard ts = &s->temps[s->nb_globals]; 409c896fe29Sbellard ts->base_type = type; 410c896fe29Sbellard ts->type = type; 411c896fe29Sbellard ts->fixed_reg = 0; 412c896fe29Sbellard ts->mem_allocated = 1; 413c896fe29Sbellard ts->mem_reg = reg; 414c896fe29Sbellard ts->mem_offset = offset; 415c896fe29Sbellard ts->name = name; 416c896fe29Sbellard s->nb_globals++; 417c896fe29Sbellard } 418a7812ae4Spbrook return idx; 419c896fe29Sbellard } 420c896fe29Sbellard 421a7812ae4Spbrook TCGv_i32 tcg_global_mem_new_i32(int reg, tcg_target_long offset, 422a7812ae4Spbrook const char *name) 423a7812ae4Spbrook { 424a7812ae4Spbrook int idx; 425a7812ae4Spbrook 426a7812ae4Spbrook idx = tcg_global_mem_new_internal(TCG_TYPE_I32, reg, offset, name); 427a7812ae4Spbrook return MAKE_TCGV_I32(idx); 428a7812ae4Spbrook } 429a7812ae4Spbrook 430a7812ae4Spbrook TCGv_i64 tcg_global_mem_new_i64(int reg, tcg_target_long offset, 431a7812ae4Spbrook const char *name) 432a7812ae4Spbrook { 433a7812ae4Spbrook int idx; 434a7812ae4Spbrook 435a7812ae4Spbrook idx = tcg_global_mem_new_internal(TCG_TYPE_I64, reg, offset, name); 436a7812ae4Spbrook return MAKE_TCGV_I64(idx); 437a7812ae4Spbrook } 438a7812ae4Spbrook 439a7812ae4Spbrook static inline int tcg_temp_new_internal(TCGType type, int temp_local) 440c896fe29Sbellard { 441c896fe29Sbellard TCGContext *s = &tcg_ctx; 442c896fe29Sbellard TCGTemp *ts; 443641d5fbeSbellard int idx, k; 444c896fe29Sbellard 445641d5fbeSbellard k = type; 446641d5fbeSbellard if (temp_local) 447641d5fbeSbellard k += TCG_TYPE_COUNT; 448641d5fbeSbellard idx = s->first_free_temp[k]; 449e8996ee0Sbellard if (idx != -1) { 450e8996ee0Sbellard /* There is already an available temp with the 451e8996ee0Sbellard right type */ 452e8996ee0Sbellard ts = &s->temps[idx]; 453641d5fbeSbellard s->first_free_temp[k] = ts->next_free_temp; 454e8996ee0Sbellard ts->temp_allocated = 1; 455641d5fbeSbellard assert(ts->temp_local == temp_local); 456e8996ee0Sbellard } else { 457c896fe29Sbellard idx = s->nb_temps; 458c896fe29Sbellard #if TCG_TARGET_REG_BITS == 32 459c896fe29Sbellard if (type == TCG_TYPE_I64) { 4608df1ca4bSths tcg_temp_alloc(s, s->nb_temps + 2); 461c896fe29Sbellard ts = &s->temps[s->nb_temps]; 462c896fe29Sbellard ts->base_type = type; 463c896fe29Sbellard ts->type = TCG_TYPE_I32; 464e8996ee0Sbellard ts->temp_allocated = 1; 465641d5fbeSbellard ts->temp_local = temp_local; 466c896fe29Sbellard ts->name = NULL; 467c896fe29Sbellard ts++; 468c896fe29Sbellard ts->base_type = TCG_TYPE_I32; 469c896fe29Sbellard ts->type = TCG_TYPE_I32; 470e8996ee0Sbellard ts->temp_allocated = 1; 471641d5fbeSbellard ts->temp_local = temp_local; 472c896fe29Sbellard ts->name = NULL; 473c896fe29Sbellard s->nb_temps += 2; 474c896fe29Sbellard } else 475c896fe29Sbellard #endif 476c896fe29Sbellard { 477c896fe29Sbellard tcg_temp_alloc(s, s->nb_temps + 1); 478c896fe29Sbellard ts = &s->temps[s->nb_temps]; 479c896fe29Sbellard ts->base_type = type; 480c896fe29Sbellard ts->type = type; 481e8996ee0Sbellard ts->temp_allocated = 1; 482641d5fbeSbellard ts->temp_local = temp_local; 483c896fe29Sbellard ts->name = NULL; 484c896fe29Sbellard s->nb_temps++; 485c896fe29Sbellard } 486e8996ee0Sbellard } 48727bfd83cSPeter Maydell 48827bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG) 48927bfd83cSPeter Maydell s->temps_in_use++; 49027bfd83cSPeter Maydell #endif 491a7812ae4Spbrook return idx; 492c896fe29Sbellard } 493c896fe29Sbellard 494a7812ae4Spbrook TCGv_i32 tcg_temp_new_internal_i32(int temp_local) 495a7812ae4Spbrook { 496a7812ae4Spbrook int idx; 497a7812ae4Spbrook 498a7812ae4Spbrook idx = tcg_temp_new_internal(TCG_TYPE_I32, temp_local); 499a7812ae4Spbrook return MAKE_TCGV_I32(idx); 500a7812ae4Spbrook } 501a7812ae4Spbrook 502a7812ae4Spbrook TCGv_i64 tcg_temp_new_internal_i64(int temp_local) 503a7812ae4Spbrook { 504a7812ae4Spbrook int idx; 505a7812ae4Spbrook 506a7812ae4Spbrook idx = tcg_temp_new_internal(TCG_TYPE_I64, temp_local); 507a7812ae4Spbrook return MAKE_TCGV_I64(idx); 508a7812ae4Spbrook } 509a7812ae4Spbrook 510a7812ae4Spbrook static inline void tcg_temp_free_internal(int idx) 511c896fe29Sbellard { 512c896fe29Sbellard TCGContext *s = &tcg_ctx; 513c896fe29Sbellard TCGTemp *ts; 514641d5fbeSbellard int k; 515c896fe29Sbellard 51627bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG) 51727bfd83cSPeter Maydell s->temps_in_use--; 51827bfd83cSPeter Maydell if (s->temps_in_use < 0) { 51927bfd83cSPeter Maydell fprintf(stderr, "More temporaries freed than allocated!\n"); 52027bfd83cSPeter Maydell } 52127bfd83cSPeter Maydell #endif 52227bfd83cSPeter Maydell 523e8996ee0Sbellard assert(idx >= s->nb_globals && idx < s->nb_temps); 524c896fe29Sbellard ts = &s->temps[idx]; 525e8996ee0Sbellard assert(ts->temp_allocated != 0); 526e8996ee0Sbellard ts->temp_allocated = 0; 527641d5fbeSbellard k = ts->base_type; 528641d5fbeSbellard if (ts->temp_local) 529641d5fbeSbellard k += TCG_TYPE_COUNT; 530641d5fbeSbellard ts->next_free_temp = s->first_free_temp[k]; 531641d5fbeSbellard s->first_free_temp[k] = idx; 532e8996ee0Sbellard } 533e8996ee0Sbellard 534a7812ae4Spbrook void tcg_temp_free_i32(TCGv_i32 arg) 535e8996ee0Sbellard { 536a7812ae4Spbrook tcg_temp_free_internal(GET_TCGV_I32(arg)); 537a7812ae4Spbrook } 538a7812ae4Spbrook 539a7812ae4Spbrook void tcg_temp_free_i64(TCGv_i64 arg) 540a7812ae4Spbrook { 541a7812ae4Spbrook tcg_temp_free_internal(GET_TCGV_I64(arg)); 542a7812ae4Spbrook } 543a7812ae4Spbrook 544a7812ae4Spbrook TCGv_i32 tcg_const_i32(int32_t val) 545a7812ae4Spbrook { 546a7812ae4Spbrook TCGv_i32 t0; 547a7812ae4Spbrook t0 = tcg_temp_new_i32(); 548e8996ee0Sbellard tcg_gen_movi_i32(t0, val); 549e8996ee0Sbellard return t0; 550c896fe29Sbellard } 551c896fe29Sbellard 552a7812ae4Spbrook TCGv_i64 tcg_const_i64(int64_t val) 553c896fe29Sbellard { 554a7812ae4Spbrook TCGv_i64 t0; 555a7812ae4Spbrook t0 = tcg_temp_new_i64(); 556e8996ee0Sbellard tcg_gen_movi_i64(t0, val); 557e8996ee0Sbellard return t0; 558c896fe29Sbellard } 559c896fe29Sbellard 560a7812ae4Spbrook TCGv_i32 tcg_const_local_i32(int32_t val) 561bdffd4a9Saurel32 { 562a7812ae4Spbrook TCGv_i32 t0; 563a7812ae4Spbrook t0 = tcg_temp_local_new_i32(); 564bdffd4a9Saurel32 tcg_gen_movi_i32(t0, val); 565bdffd4a9Saurel32 return t0; 566bdffd4a9Saurel32 } 567bdffd4a9Saurel32 568a7812ae4Spbrook TCGv_i64 tcg_const_local_i64(int64_t val) 569bdffd4a9Saurel32 { 570a7812ae4Spbrook TCGv_i64 t0; 571a7812ae4Spbrook t0 = tcg_temp_local_new_i64(); 572bdffd4a9Saurel32 tcg_gen_movi_i64(t0, val); 573bdffd4a9Saurel32 return t0; 574bdffd4a9Saurel32 } 575bdffd4a9Saurel32 57627bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG) 57727bfd83cSPeter Maydell void tcg_clear_temp_count(void) 57827bfd83cSPeter Maydell { 57927bfd83cSPeter Maydell TCGContext *s = &tcg_ctx; 58027bfd83cSPeter Maydell s->temps_in_use = 0; 58127bfd83cSPeter Maydell } 58227bfd83cSPeter Maydell 58327bfd83cSPeter Maydell int tcg_check_temp_count(void) 58427bfd83cSPeter Maydell { 58527bfd83cSPeter Maydell TCGContext *s = &tcg_ctx; 58627bfd83cSPeter Maydell if (s->temps_in_use) { 58727bfd83cSPeter Maydell /* Clear the count so that we don't give another 58827bfd83cSPeter Maydell * warning immediately next time around. 58927bfd83cSPeter Maydell */ 59027bfd83cSPeter Maydell s->temps_in_use = 0; 59127bfd83cSPeter Maydell return 1; 59227bfd83cSPeter Maydell } 59327bfd83cSPeter Maydell return 0; 59427bfd83cSPeter Maydell } 59527bfd83cSPeter Maydell #endif 59627bfd83cSPeter Maydell 597c896fe29Sbellard void tcg_register_helper(void *func, const char *name) 598c896fe29Sbellard { 599c896fe29Sbellard TCGContext *s = &tcg_ctx; 600c896fe29Sbellard int n; 601c896fe29Sbellard if ((s->nb_helpers + 1) > s->allocated_helpers) { 602c896fe29Sbellard n = s->allocated_helpers; 603c896fe29Sbellard if (n == 0) { 604c896fe29Sbellard n = 4; 605c896fe29Sbellard } else { 606c896fe29Sbellard n *= 2; 607c896fe29Sbellard } 608c896fe29Sbellard s->helpers = realloc(s->helpers, n * sizeof(TCGHelperInfo)); 609c896fe29Sbellard s->allocated_helpers = n; 610c896fe29Sbellard } 6114dc81f28Sbellard s->helpers[s->nb_helpers].func = (tcg_target_ulong)func; 612c896fe29Sbellard s->helpers[s->nb_helpers].name = name; 613c896fe29Sbellard s->nb_helpers++; 614c896fe29Sbellard } 615c896fe29Sbellard 61639cf05d3Sbellard /* Note: we convert the 64 bit args to 32 bit and do some alignment 61739cf05d3Sbellard and endian swap. Maybe it would be better to do the alignment 61839cf05d3Sbellard and endian swap in tcg_reg_alloc_call(). */ 619a7812ae4Spbrook void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags, 620a7812ae4Spbrook int sizemask, TCGArg ret, int nargs, TCGArg *args) 621c896fe29Sbellard { 622a7812ae4Spbrook int i; 623a7812ae4Spbrook int real_args; 624a7812ae4Spbrook int nb_rets; 625a7812ae4Spbrook TCGArg *nparam; 6262bece2c8SRichard Henderson 6272bece2c8SRichard Henderson #if defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64 6282bece2c8SRichard Henderson for (i = 0; i < nargs; ++i) { 6292bece2c8SRichard Henderson int is_64bit = sizemask & (1 << (i+1)*2); 6302bece2c8SRichard Henderson int is_signed = sizemask & (2 << (i+1)*2); 6312bece2c8SRichard Henderson if (!is_64bit) { 6322bece2c8SRichard Henderson TCGv_i64 temp = tcg_temp_new_i64(); 6332bece2c8SRichard Henderson TCGv_i64 orig = MAKE_TCGV_I64(args[i]); 6342bece2c8SRichard Henderson if (is_signed) { 6352bece2c8SRichard Henderson tcg_gen_ext32s_i64(temp, orig); 6362bece2c8SRichard Henderson } else { 6372bece2c8SRichard Henderson tcg_gen_ext32u_i64(temp, orig); 6382bece2c8SRichard Henderson } 6392bece2c8SRichard Henderson args[i] = GET_TCGV_I64(temp); 6402bece2c8SRichard Henderson } 6412bece2c8SRichard Henderson } 6422bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */ 6432bece2c8SRichard Henderson 644efd7f486SEvgeny Voevodin *s->gen_opc_ptr++ = INDEX_op_call; 645c4afe5c4SEvgeny Voevodin nparam = s->gen_opparam_ptr++; 646a7812ae4Spbrook if (ret != TCG_CALL_DUMMY_ARG) { 647a7812ae4Spbrook #if TCG_TARGET_REG_BITS < 64 648a7812ae4Spbrook if (sizemask & 1) { 649a7812ae4Spbrook #ifdef TCG_TARGET_WORDS_BIGENDIAN 650c4afe5c4SEvgeny Voevodin *s->gen_opparam_ptr++ = ret + 1; 651c4afe5c4SEvgeny Voevodin *s->gen_opparam_ptr++ = ret; 652a7812ae4Spbrook #else 653c4afe5c4SEvgeny Voevodin *s->gen_opparam_ptr++ = ret; 654c4afe5c4SEvgeny Voevodin *s->gen_opparam_ptr++ = ret + 1; 655a7812ae4Spbrook #endif 656a7812ae4Spbrook nb_rets = 2; 657a7812ae4Spbrook } else 658a7812ae4Spbrook #endif 659a7812ae4Spbrook { 660c4afe5c4SEvgeny Voevodin *s->gen_opparam_ptr++ = ret; 661a7812ae4Spbrook nb_rets = 1; 662a7812ae4Spbrook } 663a7812ae4Spbrook } else { 664a7812ae4Spbrook nb_rets = 0; 665a7812ae4Spbrook } 666a7812ae4Spbrook real_args = 0; 667a7812ae4Spbrook for (i = 0; i < nargs; i++) { 668a7812ae4Spbrook #if TCG_TARGET_REG_BITS < 64 6692bece2c8SRichard Henderson int is_64bit = sizemask & (1 << (i+1)*2); 6702bece2c8SRichard Henderson if (is_64bit) { 67139cf05d3Sbellard #ifdef TCG_TARGET_CALL_ALIGN_ARGS 67239cf05d3Sbellard /* some targets want aligned 64 bit args */ 673ebd486d5Smalc if (real_args & 1) { 674c4afe5c4SEvgeny Voevodin *s->gen_opparam_ptr++ = TCG_CALL_DUMMY_ARG; 675ebd486d5Smalc real_args++; 67639cf05d3Sbellard } 67739cf05d3Sbellard #endif 6783f90f252SRichard Henderson /* If stack grows up, then we will be placing successive 6793f90f252SRichard Henderson arguments at lower addresses, which means we need to 6803f90f252SRichard Henderson reverse the order compared to how we would normally 6813f90f252SRichard Henderson treat either big or little-endian. For those arguments 6823f90f252SRichard Henderson that will wind up in registers, this still works for 6833f90f252SRichard Henderson HPPA (the only current STACK_GROWSUP target) since the 6843f90f252SRichard Henderson argument registers are *also* allocated in decreasing 6853f90f252SRichard Henderson order. If another such target is added, this logic may 6863f90f252SRichard Henderson have to get more complicated to differentiate between 6873f90f252SRichard Henderson stack arguments and register arguments. */ 6883f90f252SRichard Henderson #if defined(TCG_TARGET_WORDS_BIGENDIAN) != defined(TCG_TARGET_STACK_GROWSUP) 689c4afe5c4SEvgeny Voevodin *s->gen_opparam_ptr++ = args[i] + 1; 690c4afe5c4SEvgeny Voevodin *s->gen_opparam_ptr++ = args[i]; 691c896fe29Sbellard #else 692c4afe5c4SEvgeny Voevodin *s->gen_opparam_ptr++ = args[i]; 693c4afe5c4SEvgeny Voevodin *s->gen_opparam_ptr++ = args[i] + 1; 694c896fe29Sbellard #endif 695a7812ae4Spbrook real_args += 2; 6962bece2c8SRichard Henderson continue; 6972bece2c8SRichard Henderson } 6982bece2c8SRichard Henderson #endif /* TCG_TARGET_REG_BITS < 64 */ 6992bece2c8SRichard Henderson 700c4afe5c4SEvgeny Voevodin *s->gen_opparam_ptr++ = args[i]; 701a7812ae4Spbrook real_args++; 702c896fe29Sbellard } 703c4afe5c4SEvgeny Voevodin *s->gen_opparam_ptr++ = GET_TCGV_PTR(func); 704a7812ae4Spbrook 705c4afe5c4SEvgeny Voevodin *s->gen_opparam_ptr++ = flags; 706a7812ae4Spbrook 707a7812ae4Spbrook *nparam = (nb_rets << 16) | (real_args + 1); 708a7812ae4Spbrook 709a7812ae4Spbrook /* total parameters, needed to go backward in the instruction stream */ 710c4afe5c4SEvgeny Voevodin *s->gen_opparam_ptr++ = 1 + nb_rets + real_args + 3; 7112bece2c8SRichard Henderson 7122bece2c8SRichard Henderson #if defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64 7132bece2c8SRichard Henderson for (i = 0; i < nargs; ++i) { 7142bece2c8SRichard Henderson int is_64bit = sizemask & (1 << (i+1)*2); 7152bece2c8SRichard Henderson if (!is_64bit) { 7162bece2c8SRichard Henderson TCGv_i64 temp = MAKE_TCGV_I64(args[i]); 7172bece2c8SRichard Henderson tcg_temp_free_i64(temp); 7182bece2c8SRichard Henderson } 7192bece2c8SRichard Henderson } 7202bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */ 721a7812ae4Spbrook } 722c896fe29Sbellard 723ac56dd48Spbrook #if TCG_TARGET_REG_BITS == 32 724a7812ae4Spbrook void tcg_gen_shifti_i64(TCGv_i64 ret, TCGv_i64 arg1, 725c896fe29Sbellard int c, int right, int arith) 726c896fe29Sbellard { 727cf60bce4Sbellard if (c == 0) { 728a7812ae4Spbrook tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg1)); 729cf60bce4Sbellard tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1)); 730cf60bce4Sbellard } else if (c >= 32) { 731c896fe29Sbellard c -= 32; 732c896fe29Sbellard if (right) { 733c896fe29Sbellard if (arith) { 734a7812ae4Spbrook tcg_gen_sari_i32(TCGV_LOW(ret), TCGV_HIGH(arg1), c); 735ac56dd48Spbrook tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), 31); 736c896fe29Sbellard } else { 737a7812ae4Spbrook tcg_gen_shri_i32(TCGV_LOW(ret), TCGV_HIGH(arg1), c); 738ac56dd48Spbrook tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 739c896fe29Sbellard } 740c896fe29Sbellard } else { 741a7812ae4Spbrook tcg_gen_shli_i32(TCGV_HIGH(ret), TCGV_LOW(arg1), c); 742a7812ae4Spbrook tcg_gen_movi_i32(TCGV_LOW(ret), 0); 743c896fe29Sbellard } 744c896fe29Sbellard } else { 745a7812ae4Spbrook TCGv_i32 t0, t1; 746c896fe29Sbellard 747a7812ae4Spbrook t0 = tcg_temp_new_i32(); 748a7812ae4Spbrook t1 = tcg_temp_new_i32(); 749c896fe29Sbellard if (right) { 750ac56dd48Spbrook tcg_gen_shli_i32(t0, TCGV_HIGH(arg1), 32 - c); 751c896fe29Sbellard if (arith) 752ac56dd48Spbrook tcg_gen_sari_i32(t1, TCGV_HIGH(arg1), c); 753c896fe29Sbellard else 754ac56dd48Spbrook tcg_gen_shri_i32(t1, TCGV_HIGH(arg1), c); 755a7812ae4Spbrook tcg_gen_shri_i32(TCGV_LOW(ret), TCGV_LOW(arg1), c); 756a7812ae4Spbrook tcg_gen_or_i32(TCGV_LOW(ret), TCGV_LOW(ret), t0); 757ac56dd48Spbrook tcg_gen_mov_i32(TCGV_HIGH(ret), t1); 758c896fe29Sbellard } else { 759a7812ae4Spbrook tcg_gen_shri_i32(t0, TCGV_LOW(arg1), 32 - c); 760c896fe29Sbellard /* Note: ret can be the same as arg1, so we use t1 */ 761a7812ae4Spbrook tcg_gen_shli_i32(t1, TCGV_LOW(arg1), c); 762ac56dd48Spbrook tcg_gen_shli_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), c); 763ac56dd48Spbrook tcg_gen_or_i32(TCGV_HIGH(ret), TCGV_HIGH(ret), t0); 764a7812ae4Spbrook tcg_gen_mov_i32(TCGV_LOW(ret), t1); 765c896fe29Sbellard } 766a7812ae4Spbrook tcg_temp_free_i32(t0); 767a7812ae4Spbrook tcg_temp_free_i32(t1); 768c896fe29Sbellard } 769c896fe29Sbellard } 770ac56dd48Spbrook #endif 771c896fe29Sbellard 772be210acbSRichard Henderson 7738fcd3692Sblueswir1 static void tcg_reg_alloc_start(TCGContext *s) 774c896fe29Sbellard { 775c896fe29Sbellard int i; 776c896fe29Sbellard TCGTemp *ts; 777c896fe29Sbellard for(i = 0; i < s->nb_globals; i++) { 778c896fe29Sbellard ts = &s->temps[i]; 779c896fe29Sbellard if (ts->fixed_reg) { 780c896fe29Sbellard ts->val_type = TEMP_VAL_REG; 781c896fe29Sbellard } else { 782c896fe29Sbellard ts->val_type = TEMP_VAL_MEM; 783c896fe29Sbellard } 784c896fe29Sbellard } 785e8996ee0Sbellard for(i = s->nb_globals; i < s->nb_temps; i++) { 786e8996ee0Sbellard ts = &s->temps[i]; 7877dfd8c6aSAurelien Jarno if (ts->temp_local) { 7887dfd8c6aSAurelien Jarno ts->val_type = TEMP_VAL_MEM; 7897dfd8c6aSAurelien Jarno } else { 790e8996ee0Sbellard ts->val_type = TEMP_VAL_DEAD; 7917dfd8c6aSAurelien Jarno } 792e8996ee0Sbellard ts->mem_allocated = 0; 793e8996ee0Sbellard ts->fixed_reg = 0; 794e8996ee0Sbellard } 795c896fe29Sbellard for(i = 0; i < TCG_TARGET_NB_REGS; i++) { 796c896fe29Sbellard s->reg_to_temp[i] = -1; 797c896fe29Sbellard } 798c896fe29Sbellard } 799c896fe29Sbellard 800ac56dd48Spbrook static char *tcg_get_arg_str_idx(TCGContext *s, char *buf, int buf_size, 801ac56dd48Spbrook int idx) 802c896fe29Sbellard { 803c896fe29Sbellard TCGTemp *ts; 804ac56dd48Spbrook 8057f6f0ae5SStefan Weil assert(idx >= 0 && idx < s->nb_temps); 806ac56dd48Spbrook ts = &s->temps[idx]; 8077f6f0ae5SStefan Weil assert(ts); 808ac56dd48Spbrook if (idx < s->nb_globals) { 809ac56dd48Spbrook pstrcpy(buf, buf_size, ts->name); 810c896fe29Sbellard } else { 811641d5fbeSbellard if (ts->temp_local) 812641d5fbeSbellard snprintf(buf, buf_size, "loc%d", idx - s->nb_globals); 813641d5fbeSbellard else 814ac56dd48Spbrook snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals); 815c896fe29Sbellard } 816c896fe29Sbellard return buf; 817c896fe29Sbellard } 818c896fe29Sbellard 819a7812ae4Spbrook char *tcg_get_arg_str_i32(TCGContext *s, char *buf, int buf_size, TCGv_i32 arg) 820ac56dd48Spbrook { 821a7812ae4Spbrook return tcg_get_arg_str_idx(s, buf, buf_size, GET_TCGV_I32(arg)); 822a7812ae4Spbrook } 823a7812ae4Spbrook 824a7812ae4Spbrook char *tcg_get_arg_str_i64(TCGContext *s, char *buf, int buf_size, TCGv_i64 arg) 825a7812ae4Spbrook { 826a810a2deSblueswir1 return tcg_get_arg_str_idx(s, buf, buf_size, GET_TCGV_I64(arg)); 827ac56dd48Spbrook } 828ac56dd48Spbrook 829e8996ee0Sbellard static int helper_cmp(const void *p1, const void *p2) 830e8996ee0Sbellard { 831e8996ee0Sbellard const TCGHelperInfo *th1 = p1; 832e8996ee0Sbellard const TCGHelperInfo *th2 = p2; 833e8996ee0Sbellard if (th1->func < th2->func) 834e8996ee0Sbellard return -1; 835e8996ee0Sbellard else if (th1->func == th2->func) 836e8996ee0Sbellard return 0; 837e8996ee0Sbellard else 838e8996ee0Sbellard return 1; 839e8996ee0Sbellard } 840e8996ee0Sbellard 841e8996ee0Sbellard /* find helper definition (Note: A hash table would be better) */ 8424dc81f28Sbellard static TCGHelperInfo *tcg_find_helper(TCGContext *s, tcg_target_ulong val) 8434dc81f28Sbellard { 844e8996ee0Sbellard int m, m_min, m_max; 845e8996ee0Sbellard TCGHelperInfo *th; 846e8996ee0Sbellard tcg_target_ulong v; 847e8996ee0Sbellard 848e8996ee0Sbellard if (unlikely(!s->helpers_sorted)) { 849e8996ee0Sbellard qsort(s->helpers, s->nb_helpers, sizeof(TCGHelperInfo), 850e8996ee0Sbellard helper_cmp); 851e8996ee0Sbellard s->helpers_sorted = 1; 852e8996ee0Sbellard } 853e8996ee0Sbellard 854e8996ee0Sbellard /* binary search */ 855e8996ee0Sbellard m_min = 0; 856e8996ee0Sbellard m_max = s->nb_helpers - 1; 857e8996ee0Sbellard while (m_min <= m_max) { 858e8996ee0Sbellard m = (m_min + m_max) >> 1; 859e8996ee0Sbellard th = &s->helpers[m]; 860e8996ee0Sbellard v = th->func; 861e8996ee0Sbellard if (v == val) 862e8996ee0Sbellard return th; 863e8996ee0Sbellard else if (val < v) { 864e8996ee0Sbellard m_max = m - 1; 865e8996ee0Sbellard } else { 866e8996ee0Sbellard m_min = m + 1; 867e8996ee0Sbellard } 8684dc81f28Sbellard } 8694dc81f28Sbellard return NULL; 8704dc81f28Sbellard } 8714dc81f28Sbellard 872f48f3edeSblueswir1 static const char * const cond_name[] = 873f48f3edeSblueswir1 { 8740aed257fSRichard Henderson [TCG_COND_NEVER] = "never", 8750aed257fSRichard Henderson [TCG_COND_ALWAYS] = "always", 876f48f3edeSblueswir1 [TCG_COND_EQ] = "eq", 877f48f3edeSblueswir1 [TCG_COND_NE] = "ne", 878f48f3edeSblueswir1 [TCG_COND_LT] = "lt", 879f48f3edeSblueswir1 [TCG_COND_GE] = "ge", 880f48f3edeSblueswir1 [TCG_COND_LE] = "le", 881f48f3edeSblueswir1 [TCG_COND_GT] = "gt", 882f48f3edeSblueswir1 [TCG_COND_LTU] = "ltu", 883f48f3edeSblueswir1 [TCG_COND_GEU] = "geu", 884f48f3edeSblueswir1 [TCG_COND_LEU] = "leu", 885f48f3edeSblueswir1 [TCG_COND_GTU] = "gtu" 886f48f3edeSblueswir1 }; 887f48f3edeSblueswir1 888eeacee4dSBlue Swirl void tcg_dump_ops(TCGContext *s) 889c896fe29Sbellard { 890c896fe29Sbellard const uint16_t *opc_ptr; 891c896fe29Sbellard const TCGArg *args; 892c896fe29Sbellard TCGArg arg; 893a9751609SRichard Henderson TCGOpcode c; 894a9751609SRichard Henderson int i, k, nb_oargs, nb_iargs, nb_cargs, first_insn; 895c896fe29Sbellard const TCGOpDef *def; 896c896fe29Sbellard char buf[128]; 897c896fe29Sbellard 8987e4597d7Sbellard first_insn = 1; 899*92414b31SEvgeny Voevodin opc_ptr = s->gen_opc_buf; 900c896fe29Sbellard args = gen_opparam_buf; 901efd7f486SEvgeny Voevodin while (opc_ptr < s->gen_opc_ptr) { 902c896fe29Sbellard c = *opc_ptr++; 903c896fe29Sbellard def = &tcg_op_defs[c]; 9047e4597d7Sbellard if (c == INDEX_op_debug_insn_start) { 9057e4597d7Sbellard uint64_t pc; 9067e4597d7Sbellard #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS 9077e4597d7Sbellard pc = ((uint64_t)args[1] << 32) | args[0]; 9087e4597d7Sbellard #else 9097e4597d7Sbellard pc = args[0]; 9107e4597d7Sbellard #endif 911eeacee4dSBlue Swirl if (!first_insn) { 912eeacee4dSBlue Swirl qemu_log("\n"); 913eeacee4dSBlue Swirl } 914eeacee4dSBlue Swirl qemu_log(" ---- 0x%" PRIx64, pc); 9157e4597d7Sbellard first_insn = 0; 9167e4597d7Sbellard nb_oargs = def->nb_oargs; 9177e4597d7Sbellard nb_iargs = def->nb_iargs; 9187e4597d7Sbellard nb_cargs = def->nb_cargs; 9197e4597d7Sbellard } else if (c == INDEX_op_call) { 920c896fe29Sbellard TCGArg arg; 9214dc81f28Sbellard 922c896fe29Sbellard /* variable number of arguments */ 923c896fe29Sbellard arg = *args++; 924c896fe29Sbellard nb_oargs = arg >> 16; 925c896fe29Sbellard nb_iargs = arg & 0xffff; 926c896fe29Sbellard nb_cargs = def->nb_cargs; 927b03cce8eSbellard 928eeacee4dSBlue Swirl qemu_log(" %s ", def->name); 9297e4597d7Sbellard 930b03cce8eSbellard /* function name */ 931eeacee4dSBlue Swirl qemu_log("%s", 932eeacee4dSBlue Swirl tcg_get_arg_str_idx(s, buf, sizeof(buf), 933eeacee4dSBlue Swirl args[nb_oargs + nb_iargs - 1])); 934b03cce8eSbellard /* flags */ 935eeacee4dSBlue Swirl qemu_log(",$0x%" TCG_PRIlx, args[nb_oargs + nb_iargs]); 936b03cce8eSbellard /* nb out args */ 937eeacee4dSBlue Swirl qemu_log(",$%d", nb_oargs); 938b03cce8eSbellard for(i = 0; i < nb_oargs; i++) { 939eeacee4dSBlue Swirl qemu_log(","); 940eeacee4dSBlue Swirl qemu_log("%s", tcg_get_arg_str_idx(s, buf, sizeof(buf), 941eeacee4dSBlue Swirl args[i])); 942b03cce8eSbellard } 943b03cce8eSbellard for(i = 0; i < (nb_iargs - 1); i++) { 944eeacee4dSBlue Swirl qemu_log(","); 94539cf05d3Sbellard if (args[nb_oargs + i] == TCG_CALL_DUMMY_ARG) { 946eeacee4dSBlue Swirl qemu_log("<dummy>"); 94739cf05d3Sbellard } else { 948eeacee4dSBlue Swirl qemu_log("%s", tcg_get_arg_str_idx(s, buf, sizeof(buf), 949eeacee4dSBlue Swirl args[nb_oargs + i])); 950b03cce8eSbellard } 95139cf05d3Sbellard } 952fba3161fSAurelien Jarno } else if (c == INDEX_op_movi_i32 || c == INDEX_op_movi_i64) { 953e8996ee0Sbellard tcg_target_ulong val; 954e8996ee0Sbellard TCGHelperInfo *th; 955e8996ee0Sbellard 956e8996ee0Sbellard nb_oargs = def->nb_oargs; 957e8996ee0Sbellard nb_iargs = def->nb_iargs; 958e8996ee0Sbellard nb_cargs = def->nb_cargs; 959eeacee4dSBlue Swirl qemu_log(" %s %s,$", def->name, 960e8996ee0Sbellard tcg_get_arg_str_idx(s, buf, sizeof(buf), args[0])); 961e8996ee0Sbellard val = args[1]; 962e8996ee0Sbellard th = tcg_find_helper(s, val); 963e8996ee0Sbellard if (th) { 964eeacee4dSBlue Swirl qemu_log("%s", th->name); 965e8996ee0Sbellard } else { 966eeacee4dSBlue Swirl if (c == INDEX_op_movi_i32) { 967eeacee4dSBlue Swirl qemu_log("0x%x", (uint32_t)val); 968eeacee4dSBlue Swirl } else { 969eeacee4dSBlue Swirl qemu_log("0x%" PRIx64 , (uint64_t)val); 970eeacee4dSBlue Swirl } 971e8996ee0Sbellard } 972b03cce8eSbellard } else { 973eeacee4dSBlue Swirl qemu_log(" %s ", def->name); 974b03cce8eSbellard if (c == INDEX_op_nopn) { 975c896fe29Sbellard /* variable number of arguments */ 976c896fe29Sbellard nb_cargs = *args; 977c896fe29Sbellard nb_oargs = 0; 978c896fe29Sbellard nb_iargs = 0; 979c896fe29Sbellard } else { 980c896fe29Sbellard nb_oargs = def->nb_oargs; 981c896fe29Sbellard nb_iargs = def->nb_iargs; 982c896fe29Sbellard nb_cargs = def->nb_cargs; 983c896fe29Sbellard } 984c896fe29Sbellard 985c896fe29Sbellard k = 0; 986c896fe29Sbellard for(i = 0; i < nb_oargs; i++) { 987eeacee4dSBlue Swirl if (k != 0) { 988eeacee4dSBlue Swirl qemu_log(","); 989eeacee4dSBlue Swirl } 990eeacee4dSBlue Swirl qemu_log("%s", tcg_get_arg_str_idx(s, buf, sizeof(buf), 991eeacee4dSBlue Swirl args[k++])); 992c896fe29Sbellard } 993c896fe29Sbellard for(i = 0; i < nb_iargs; i++) { 994eeacee4dSBlue Swirl if (k != 0) { 995eeacee4dSBlue Swirl qemu_log(","); 996eeacee4dSBlue Swirl } 997eeacee4dSBlue Swirl qemu_log("%s", tcg_get_arg_str_idx(s, buf, sizeof(buf), 998eeacee4dSBlue Swirl args[k++])); 999c896fe29Sbellard } 1000be210acbSRichard Henderson switch (c) { 1001be210acbSRichard Henderson case INDEX_op_brcond_i32: 1002ffc5ea09SRichard Henderson case INDEX_op_setcond_i32: 1003ffc5ea09SRichard Henderson case INDEX_op_movcond_i32: 1004be210acbSRichard Henderson case INDEX_op_brcond2_i32: 1005be210acbSRichard Henderson case INDEX_op_setcond2_i32: 1006ffc5ea09SRichard Henderson case INDEX_op_brcond_i64: 1007be210acbSRichard Henderson case INDEX_op_setcond_i64: 1008ffc5ea09SRichard Henderson case INDEX_op_movcond_i64: 1009eeacee4dSBlue Swirl if (args[k] < ARRAY_SIZE(cond_name) && cond_name[args[k]]) { 1010eeacee4dSBlue Swirl qemu_log(",%s", cond_name[args[k++]]); 1011eeacee4dSBlue Swirl } else { 1012eeacee4dSBlue Swirl qemu_log(",$0x%" TCG_PRIlx, args[k++]); 1013eeacee4dSBlue Swirl } 1014f48f3edeSblueswir1 i = 1; 1015be210acbSRichard Henderson break; 1016be210acbSRichard Henderson default: 1017f48f3edeSblueswir1 i = 0; 1018be210acbSRichard Henderson break; 1019be210acbSRichard Henderson } 1020f48f3edeSblueswir1 for(; i < nb_cargs; i++) { 1021eeacee4dSBlue Swirl if (k != 0) { 1022eeacee4dSBlue Swirl qemu_log(","); 1023eeacee4dSBlue Swirl } 1024c896fe29Sbellard arg = args[k++]; 1025eeacee4dSBlue Swirl qemu_log("$0x%" TCG_PRIlx, arg); 1026c896fe29Sbellard } 1027b03cce8eSbellard } 1028eeacee4dSBlue Swirl qemu_log("\n"); 1029c896fe29Sbellard args += nb_iargs + nb_oargs + nb_cargs; 1030c896fe29Sbellard } 1031c896fe29Sbellard } 1032c896fe29Sbellard 1033c896fe29Sbellard /* we give more priority to constraints with less registers */ 1034c896fe29Sbellard static int get_constraint_priority(const TCGOpDef *def, int k) 1035c896fe29Sbellard { 1036c896fe29Sbellard const TCGArgConstraint *arg_ct; 1037c896fe29Sbellard 1038c896fe29Sbellard int i, n; 1039c896fe29Sbellard arg_ct = &def->args_ct[k]; 1040c896fe29Sbellard if (arg_ct->ct & TCG_CT_ALIAS) { 1041c896fe29Sbellard /* an alias is equivalent to a single register */ 1042c896fe29Sbellard n = 1; 1043c896fe29Sbellard } else { 1044c896fe29Sbellard if (!(arg_ct->ct & TCG_CT_REG)) 1045c896fe29Sbellard return 0; 1046c896fe29Sbellard n = 0; 1047c896fe29Sbellard for(i = 0; i < TCG_TARGET_NB_REGS; i++) { 1048c896fe29Sbellard if (tcg_regset_test_reg(arg_ct->u.regs, i)) 1049c896fe29Sbellard n++; 1050c896fe29Sbellard } 1051c896fe29Sbellard } 1052c896fe29Sbellard return TCG_TARGET_NB_REGS - n + 1; 1053c896fe29Sbellard } 1054c896fe29Sbellard 1055c896fe29Sbellard /* sort from highest priority to lowest */ 1056c896fe29Sbellard static void sort_constraints(TCGOpDef *def, int start, int n) 1057c896fe29Sbellard { 1058c896fe29Sbellard int i, j, p1, p2, tmp; 1059c896fe29Sbellard 1060c896fe29Sbellard for(i = 0; i < n; i++) 1061c896fe29Sbellard def->sorted_args[start + i] = start + i; 1062c896fe29Sbellard if (n <= 1) 1063c896fe29Sbellard return; 1064c896fe29Sbellard for(i = 0; i < n - 1; i++) { 1065c896fe29Sbellard for(j = i + 1; j < n; j++) { 1066c896fe29Sbellard p1 = get_constraint_priority(def, def->sorted_args[start + i]); 1067c896fe29Sbellard p2 = get_constraint_priority(def, def->sorted_args[start + j]); 1068c896fe29Sbellard if (p1 < p2) { 1069c896fe29Sbellard tmp = def->sorted_args[start + i]; 1070c896fe29Sbellard def->sorted_args[start + i] = def->sorted_args[start + j]; 1071c896fe29Sbellard def->sorted_args[start + j] = tmp; 1072c896fe29Sbellard } 1073c896fe29Sbellard } 1074c896fe29Sbellard } 1075c896fe29Sbellard } 1076c896fe29Sbellard 1077c896fe29Sbellard void tcg_add_target_add_op_defs(const TCGTargetOpDef *tdefs) 1078c896fe29Sbellard { 1079a9751609SRichard Henderson TCGOpcode op; 1080c896fe29Sbellard TCGOpDef *def; 1081c896fe29Sbellard const char *ct_str; 1082c896fe29Sbellard int i, nb_args; 1083c896fe29Sbellard 1084c896fe29Sbellard for(;;) { 1085a9751609SRichard Henderson if (tdefs->op == (TCGOpcode)-1) 1086c896fe29Sbellard break; 1087c896fe29Sbellard op = tdefs->op; 1088c3b08d0eSStefan Weil assert((unsigned)op < NB_OPS); 1089c896fe29Sbellard def = &tcg_op_defs[op]; 1090c68aaa18SStefan Weil #if defined(CONFIG_DEBUG_TCG) 1091c68aaa18SStefan Weil /* Duplicate entry in op definitions? */ 1092c68aaa18SStefan Weil assert(!def->used); 1093c68aaa18SStefan Weil def->used = 1; 1094c68aaa18SStefan Weil #endif 1095c896fe29Sbellard nb_args = def->nb_iargs + def->nb_oargs; 1096c896fe29Sbellard for(i = 0; i < nb_args; i++) { 1097c896fe29Sbellard ct_str = tdefs->args_ct_str[i]; 1098c68aaa18SStefan Weil /* Incomplete TCGTargetOpDef entry? */ 1099c68aaa18SStefan Weil assert(ct_str != NULL); 1100c896fe29Sbellard tcg_regset_clear(def->args_ct[i].u.regs); 1101c896fe29Sbellard def->args_ct[i].ct = 0; 1102c896fe29Sbellard if (ct_str[0] >= '0' && ct_str[0] <= '9') { 1103c896fe29Sbellard int oarg; 1104c896fe29Sbellard oarg = ct_str[0] - '0'; 1105c896fe29Sbellard assert(oarg < def->nb_oargs); 1106c896fe29Sbellard assert(def->args_ct[oarg].ct & TCG_CT_REG); 1107c896fe29Sbellard /* TCG_CT_ALIAS is for the output arguments. The input 11085ff9d6a4Sbellard argument is tagged with TCG_CT_IALIAS. */ 1109c896fe29Sbellard def->args_ct[i] = def->args_ct[oarg]; 11105ff9d6a4Sbellard def->args_ct[oarg].ct = TCG_CT_ALIAS; 11115ff9d6a4Sbellard def->args_ct[oarg].alias_index = i; 1112c896fe29Sbellard def->args_ct[i].ct |= TCG_CT_IALIAS; 11135ff9d6a4Sbellard def->args_ct[i].alias_index = oarg; 1114c896fe29Sbellard } else { 1115c896fe29Sbellard for(;;) { 1116c896fe29Sbellard if (*ct_str == '\0') 1117c896fe29Sbellard break; 1118c896fe29Sbellard switch(*ct_str) { 1119c896fe29Sbellard case 'i': 1120c896fe29Sbellard def->args_ct[i].ct |= TCG_CT_CONST; 1121c896fe29Sbellard ct_str++; 1122c896fe29Sbellard break; 1123c896fe29Sbellard default: 1124c896fe29Sbellard if (target_parse_constraint(&def->args_ct[i], &ct_str) < 0) { 1125c896fe29Sbellard fprintf(stderr, "Invalid constraint '%s' for arg %d of operation '%s'\n", 1126c896fe29Sbellard ct_str, i, def->name); 1127c896fe29Sbellard exit(1); 1128c896fe29Sbellard } 1129c896fe29Sbellard } 1130c896fe29Sbellard } 1131c896fe29Sbellard } 1132c896fe29Sbellard } 1133c896fe29Sbellard 1134c68aaa18SStefan Weil /* TCGTargetOpDef entry with too much information? */ 1135c68aaa18SStefan Weil assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL); 1136c68aaa18SStefan Weil 1137c896fe29Sbellard /* sort the constraints (XXX: this is just an heuristic) */ 1138c896fe29Sbellard sort_constraints(def, 0, def->nb_oargs); 1139c896fe29Sbellard sort_constraints(def, def->nb_oargs, def->nb_iargs); 1140c896fe29Sbellard 1141c896fe29Sbellard #if 0 1142c896fe29Sbellard { 1143c896fe29Sbellard int i; 1144c896fe29Sbellard 1145c896fe29Sbellard printf("%s: sorted=", def->name); 1146c896fe29Sbellard for(i = 0; i < def->nb_oargs + def->nb_iargs; i++) 1147c896fe29Sbellard printf(" %d", def->sorted_args[i]); 1148c896fe29Sbellard printf("\n"); 1149c896fe29Sbellard } 1150c896fe29Sbellard #endif 1151c896fe29Sbellard tdefs++; 1152c896fe29Sbellard } 1153c896fe29Sbellard 1154c68aaa18SStefan Weil #if defined(CONFIG_DEBUG_TCG) 1155a9751609SRichard Henderson i = 0; 1156c68aaa18SStefan Weil for (op = 0; op < ARRAY_SIZE(tcg_op_defs); op++) { 1157f412c762SRichard Henderson const TCGOpDef *def = &tcg_op_defs[op]; 1158f412c762SRichard Henderson if (op < INDEX_op_call 1159f412c762SRichard Henderson || op == INDEX_op_debug_insn_start 1160f412c762SRichard Henderson || (def->flags & TCG_OPF_NOT_PRESENT)) { 1161c68aaa18SStefan Weil /* Wrong entry in op definitions? */ 1162f412c762SRichard Henderson if (def->used) { 1163f412c762SRichard Henderson fprintf(stderr, "Invalid op definition for %s\n", def->name); 1164a9751609SRichard Henderson i = 1; 1165a9751609SRichard Henderson } 1166c68aaa18SStefan Weil } else { 1167c68aaa18SStefan Weil /* Missing entry in op definitions? */ 1168f412c762SRichard Henderson if (!def->used) { 1169f412c762SRichard Henderson fprintf(stderr, "Missing op definition for %s\n", def->name); 1170a9751609SRichard Henderson i = 1; 1171c68aaa18SStefan Weil } 1172c68aaa18SStefan Weil } 1173a9751609SRichard Henderson } 1174a9751609SRichard Henderson if (i == 1) { 1175a9751609SRichard Henderson tcg_abort(); 1176a9751609SRichard Henderson } 1177c68aaa18SStefan Weil #endif 1178c896fe29Sbellard } 1179c896fe29Sbellard 1180c896fe29Sbellard #ifdef USE_LIVENESS_ANALYSIS 1181c896fe29Sbellard 1182c896fe29Sbellard /* set a nop for an operation using 'nb_args' */ 1183c896fe29Sbellard static inline void tcg_set_nop(TCGContext *s, uint16_t *opc_ptr, 1184c896fe29Sbellard TCGArg *args, int nb_args) 1185c896fe29Sbellard { 1186c896fe29Sbellard if (nb_args == 0) { 1187c896fe29Sbellard *opc_ptr = INDEX_op_nop; 1188c896fe29Sbellard } else { 1189c896fe29Sbellard *opc_ptr = INDEX_op_nopn; 1190c896fe29Sbellard args[0] = nb_args; 1191c896fe29Sbellard args[nb_args - 1] = nb_args; 1192c896fe29Sbellard } 1193c896fe29Sbellard } 1194c896fe29Sbellard 11959c43b68dSAurelien Jarno /* liveness analysis: end of function: all temps are dead, and globals 11969c43b68dSAurelien Jarno should be in memory. */ 11979c43b68dSAurelien Jarno static inline void tcg_la_func_end(TCGContext *s, uint8_t *dead_temps, 11989c43b68dSAurelien Jarno uint8_t *mem_temps) 1199c896fe29Sbellard { 12009c43b68dSAurelien Jarno memset(dead_temps, 1, s->nb_temps); 12019c43b68dSAurelien Jarno memset(mem_temps, 1, s->nb_globals); 12029c43b68dSAurelien Jarno memset(mem_temps + s->nb_globals, 0, s->nb_temps - s->nb_globals); 1203c896fe29Sbellard } 1204c896fe29Sbellard 12059c43b68dSAurelien Jarno /* liveness analysis: end of basic block: all temps are dead, globals 12069c43b68dSAurelien Jarno and local temps should be in memory. */ 12079c43b68dSAurelien Jarno static inline void tcg_la_bb_end(TCGContext *s, uint8_t *dead_temps, 12089c43b68dSAurelien Jarno uint8_t *mem_temps) 1209641d5fbeSbellard { 1210641d5fbeSbellard int i; 1211641d5fbeSbellard 12129c43b68dSAurelien Jarno memset(dead_temps, 1, s->nb_temps); 12139c43b68dSAurelien Jarno memset(mem_temps, 1, s->nb_globals); 1214641d5fbeSbellard for(i = s->nb_globals; i < s->nb_temps; i++) { 12159c43b68dSAurelien Jarno mem_temps[i] = s->temps[i].temp_local; 1216641d5fbeSbellard } 1217641d5fbeSbellard } 1218641d5fbeSbellard 1219866cb6cbSAurelien Jarno /* Liveness analysis : update the opc_dead_args array to tell if a 1220c896fe29Sbellard given input arguments is dead. Instructions updating dead 1221c896fe29Sbellard temporaries are removed. */ 12228fcd3692Sblueswir1 static void tcg_liveness_analysis(TCGContext *s) 1223c896fe29Sbellard { 1224a9751609SRichard Henderson int i, op_index, nb_args, nb_iargs, nb_oargs, arg, nb_ops; 1225a9751609SRichard Henderson TCGOpcode op; 1226c896fe29Sbellard TCGArg *args; 1227c896fe29Sbellard const TCGOpDef *def; 12289c43b68dSAurelien Jarno uint8_t *dead_temps, *mem_temps; 1229ec7a869dSAurelien Jarno uint16_t dead_args; 1230ec7a869dSAurelien Jarno uint8_t sync_args; 1231c896fe29Sbellard 1232efd7f486SEvgeny Voevodin s->gen_opc_ptr++; /* skip end */ 1233c896fe29Sbellard 1234*92414b31SEvgeny Voevodin nb_ops = s->gen_opc_ptr - s->gen_opc_buf; 1235c896fe29Sbellard 1236866cb6cbSAurelien Jarno s->op_dead_args = tcg_malloc(nb_ops * sizeof(uint16_t)); 1237ec7a869dSAurelien Jarno s->op_sync_args = tcg_malloc(nb_ops * sizeof(uint8_t)); 1238c896fe29Sbellard 1239c896fe29Sbellard dead_temps = tcg_malloc(s->nb_temps); 12409c43b68dSAurelien Jarno mem_temps = tcg_malloc(s->nb_temps); 12419c43b68dSAurelien Jarno tcg_la_func_end(s, dead_temps, mem_temps); 1242c896fe29Sbellard 1243c4afe5c4SEvgeny Voevodin args = s->gen_opparam_ptr; 1244c896fe29Sbellard op_index = nb_ops - 1; 1245c896fe29Sbellard while (op_index >= 0) { 1246*92414b31SEvgeny Voevodin op = s->gen_opc_buf[op_index]; 1247c896fe29Sbellard def = &tcg_op_defs[op]; 1248c896fe29Sbellard switch(op) { 1249c896fe29Sbellard case INDEX_op_call: 1250c6e113f5Sbellard { 1251c6e113f5Sbellard int call_flags; 1252c6e113f5Sbellard 1253c896fe29Sbellard nb_args = args[-1]; 1254c896fe29Sbellard args -= nb_args; 1255c896fe29Sbellard nb_iargs = args[0] & 0xffff; 1256c896fe29Sbellard nb_oargs = args[0] >> 16; 1257c896fe29Sbellard args++; 1258c6e113f5Sbellard call_flags = args[nb_oargs + nb_iargs]; 1259c6e113f5Sbellard 1260c6e113f5Sbellard /* pure functions can be removed if their result is not 1261c6e113f5Sbellard used */ 126278505279SAurelien Jarno if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) { 1263c6e113f5Sbellard for(i = 0; i < nb_oargs; i++) { 1264c6e113f5Sbellard arg = args[i]; 12659c43b68dSAurelien Jarno if (!dead_temps[arg] || mem_temps[arg]) { 1266c6e113f5Sbellard goto do_not_remove_call; 1267c6e113f5Sbellard } 12689c43b68dSAurelien Jarno } 1269*92414b31SEvgeny Voevodin tcg_set_nop(s, s->gen_opc_buf + op_index, 1270c6e113f5Sbellard args - 1, nb_args); 1271c6e113f5Sbellard } else { 1272c6e113f5Sbellard do_not_remove_call: 1273c896fe29Sbellard 1274c896fe29Sbellard /* output args are dead */ 12756b64b624SAurelien Jarno dead_args = 0; 1276ec7a869dSAurelien Jarno sync_args = 0; 1277c896fe29Sbellard for(i = 0; i < nb_oargs; i++) { 1278c896fe29Sbellard arg = args[i]; 12796b64b624SAurelien Jarno if (dead_temps[arg]) { 12806b64b624SAurelien Jarno dead_args |= (1 << i); 12816b64b624SAurelien Jarno } 12829c43b68dSAurelien Jarno if (mem_temps[arg]) { 12839c43b68dSAurelien Jarno sync_args |= (1 << i); 12849c43b68dSAurelien Jarno } 1285c896fe29Sbellard dead_temps[arg] = 1; 12869c43b68dSAurelien Jarno mem_temps[arg] = 0; 1287c896fe29Sbellard } 1288c896fe29Sbellard 128978505279SAurelien Jarno if (!(call_flags & TCG_CALL_NO_READ_GLOBALS)) { 129078505279SAurelien Jarno /* globals should be synced to memory */ 129178505279SAurelien Jarno memset(mem_temps, 1, s->nb_globals); 129278505279SAurelien Jarno } 129378505279SAurelien Jarno if (!(call_flags & (TCG_CALL_NO_WRITE_GLOBALS | 129478505279SAurelien Jarno TCG_CALL_NO_READ_GLOBALS))) { 12959c43b68dSAurelien Jarno /* globals should go back to memory */ 12969c43b68dSAurelien Jarno memset(dead_temps, 1, s->nb_globals); 1297b9c18f56Saurel32 } 1298c896fe29Sbellard 1299c896fe29Sbellard /* input args are live */ 1300866cb6cbSAurelien Jarno for(i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 1301866cb6cbSAurelien Jarno arg = args[i]; 130239cf05d3Sbellard if (arg != TCG_CALL_DUMMY_ARG) { 1303c896fe29Sbellard if (dead_temps[arg]) { 1304866cb6cbSAurelien Jarno dead_args |= (1 << i); 1305c896fe29Sbellard } 1306c896fe29Sbellard dead_temps[arg] = 0; 1307c896fe29Sbellard } 130839cf05d3Sbellard } 1309866cb6cbSAurelien Jarno s->op_dead_args[op_index] = dead_args; 1310ec7a869dSAurelien Jarno s->op_sync_args[op_index] = sync_args; 1311c6e113f5Sbellard } 1312c896fe29Sbellard args--; 1313c6e113f5Sbellard } 1314c896fe29Sbellard break; 13157e4597d7Sbellard case INDEX_op_debug_insn_start: 13167e4597d7Sbellard args -= def->nb_args; 13177e4597d7Sbellard break; 1318c896fe29Sbellard case INDEX_op_nopn: 1319c896fe29Sbellard nb_args = args[-1]; 1320c896fe29Sbellard args -= nb_args; 1321c896fe29Sbellard break; 13225ff9d6a4Sbellard case INDEX_op_discard: 13235ff9d6a4Sbellard args--; 13245ff9d6a4Sbellard /* mark the temporary as dead */ 13255ff9d6a4Sbellard dead_temps[args[0]] = 1; 13269c43b68dSAurelien Jarno mem_temps[args[0]] = 0; 13275ff9d6a4Sbellard break; 1328c896fe29Sbellard case INDEX_op_end: 1329c896fe29Sbellard break; 13301305c451SRichard Henderson 13311305c451SRichard Henderson case INDEX_op_add2_i32: 13321305c451SRichard Henderson case INDEX_op_sub2_i32: 13331305c451SRichard Henderson args -= 6; 13341305c451SRichard Henderson nb_iargs = 4; 13351305c451SRichard Henderson nb_oargs = 2; 13361305c451SRichard Henderson /* Test if the high part of the operation is dead, but not 13371305c451SRichard Henderson the low part. The result can be optimized to a simple 13381305c451SRichard Henderson add or sub. This happens often for x86_64 guest when the 13391305c451SRichard Henderson cpu mode is set to 32 bit. */ 13403c5645faSKirill Batuzov if (dead_temps[args[1]] && !mem_temps[args[1]]) { 13413c5645faSKirill Batuzov if (dead_temps[args[0]] && !mem_temps[args[0]]) { 13421305c451SRichard Henderson goto do_remove; 13431305c451SRichard Henderson } 13441305c451SRichard Henderson /* Create the single operation plus nop. */ 13451305c451SRichard Henderson if (op == INDEX_op_add2_i32) { 13461305c451SRichard Henderson op = INDEX_op_add_i32; 13471305c451SRichard Henderson } else { 13481305c451SRichard Henderson op = INDEX_op_sub_i32; 13491305c451SRichard Henderson } 1350*92414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = op; 13511305c451SRichard Henderson args[1] = args[2]; 13521305c451SRichard Henderson args[2] = args[4]; 1353*92414b31SEvgeny Voevodin assert(s->gen_opc_buf[op_index + 1] == INDEX_op_nop); 1354*92414b31SEvgeny Voevodin tcg_set_nop(s, s->gen_opc_buf + op_index + 1, args + 3, 3); 13551305c451SRichard Henderson /* Fall through and mark the single-word operation live. */ 13561305c451SRichard Henderson nb_iargs = 2; 13571305c451SRichard Henderson nb_oargs = 1; 13581305c451SRichard Henderson } 13591305c451SRichard Henderson goto do_not_remove; 13601305c451SRichard Henderson 13611414968aSRichard Henderson case INDEX_op_mulu2_i32: 13621414968aSRichard Henderson args -= 4; 13631414968aSRichard Henderson nb_iargs = 2; 13641414968aSRichard Henderson nb_oargs = 2; 13651414968aSRichard Henderson /* Likewise, test for the high part of the operation dead. */ 13663c5645faSKirill Batuzov if (dead_temps[args[1]] && !mem_temps[args[1]]) { 13673c5645faSKirill Batuzov if (dead_temps[args[0]] && !mem_temps[args[0]]) { 13681414968aSRichard Henderson goto do_remove; 13691414968aSRichard Henderson } 1370*92414b31SEvgeny Voevodin s->gen_opc_buf[op_index] = op = INDEX_op_mul_i32; 13711414968aSRichard Henderson args[1] = args[2]; 13721414968aSRichard Henderson args[2] = args[3]; 1373*92414b31SEvgeny Voevodin assert(s->gen_opc_buf[op_index + 1] == INDEX_op_nop); 1374*92414b31SEvgeny Voevodin tcg_set_nop(s, s->gen_opc_buf + op_index + 1, args + 3, 1); 13751414968aSRichard Henderson /* Fall through and mark the single-word operation live. */ 13761414968aSRichard Henderson nb_oargs = 1; 13771414968aSRichard Henderson } 13781414968aSRichard Henderson goto do_not_remove; 13791414968aSRichard Henderson 1380c896fe29Sbellard default: 13811305c451SRichard Henderson /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */ 1382c896fe29Sbellard args -= def->nb_args; 1383c896fe29Sbellard nb_iargs = def->nb_iargs; 1384c896fe29Sbellard nb_oargs = def->nb_oargs; 1385c896fe29Sbellard 1386c896fe29Sbellard /* Test if the operation can be removed because all 13875ff9d6a4Sbellard its outputs are dead. We assume that nb_oargs == 0 13885ff9d6a4Sbellard implies side effects */ 13895ff9d6a4Sbellard if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) { 1390c896fe29Sbellard for(i = 0; i < nb_oargs; i++) { 1391c896fe29Sbellard arg = args[i]; 13929c43b68dSAurelien Jarno if (!dead_temps[arg] || mem_temps[arg]) { 1393c896fe29Sbellard goto do_not_remove; 1394c896fe29Sbellard } 13959c43b68dSAurelien Jarno } 13961305c451SRichard Henderson do_remove: 1397*92414b31SEvgeny Voevodin tcg_set_nop(s, s->gen_opc_buf + op_index, args, def->nb_args); 1398c896fe29Sbellard #ifdef CONFIG_PROFILER 1399a23a9ec6Sbellard s->del_op_count++; 1400c896fe29Sbellard #endif 1401c896fe29Sbellard } else { 1402c896fe29Sbellard do_not_remove: 1403c896fe29Sbellard 1404c896fe29Sbellard /* output args are dead */ 14056b64b624SAurelien Jarno dead_args = 0; 1406ec7a869dSAurelien Jarno sync_args = 0; 1407c896fe29Sbellard for(i = 0; i < nb_oargs; i++) { 1408c896fe29Sbellard arg = args[i]; 14096b64b624SAurelien Jarno if (dead_temps[arg]) { 14106b64b624SAurelien Jarno dead_args |= (1 << i); 14116b64b624SAurelien Jarno } 14129c43b68dSAurelien Jarno if (mem_temps[arg]) { 14139c43b68dSAurelien Jarno sync_args |= (1 << i); 14149c43b68dSAurelien Jarno } 1415c896fe29Sbellard dead_temps[arg] = 1; 14169c43b68dSAurelien Jarno mem_temps[arg] = 0; 1417c896fe29Sbellard } 1418c896fe29Sbellard 1419c896fe29Sbellard /* if end of basic block, update */ 1420c896fe29Sbellard if (def->flags & TCG_OPF_BB_END) { 14219c43b68dSAurelien Jarno tcg_la_bb_end(s, dead_temps, mem_temps); 14223d5c5f87SAurelien Jarno } else if (def->flags & TCG_OPF_SIDE_EFFECTS) { 14233d5c5f87SAurelien Jarno /* globals should be synced to memory */ 14249c43b68dSAurelien Jarno memset(mem_temps, 1, s->nb_globals); 1425c896fe29Sbellard } 1426c896fe29Sbellard 1427c896fe29Sbellard /* input args are live */ 1428866cb6cbSAurelien Jarno for(i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 1429866cb6cbSAurelien Jarno arg = args[i]; 1430c896fe29Sbellard if (dead_temps[arg]) { 1431866cb6cbSAurelien Jarno dead_args |= (1 << i); 1432c896fe29Sbellard } 1433c896fe29Sbellard dead_temps[arg] = 0; 1434c896fe29Sbellard } 1435866cb6cbSAurelien Jarno s->op_dead_args[op_index] = dead_args; 1436ec7a869dSAurelien Jarno s->op_sync_args[op_index] = sync_args; 1437c896fe29Sbellard } 1438c896fe29Sbellard break; 1439c896fe29Sbellard } 1440c896fe29Sbellard op_index--; 1441c896fe29Sbellard } 1442c896fe29Sbellard 1443c896fe29Sbellard if (args != gen_opparam_buf) 1444c896fe29Sbellard tcg_abort(); 1445c896fe29Sbellard } 1446c896fe29Sbellard #else 1447c896fe29Sbellard /* dummy liveness analysis */ 1448655feed5Smalc static void tcg_liveness_analysis(TCGContext *s) 1449c896fe29Sbellard { 1450c896fe29Sbellard int nb_ops; 1451*92414b31SEvgeny Voevodin nb_ops = s->gen_opc_ptr - s->gen_opc_buf; 1452c896fe29Sbellard 1453866cb6cbSAurelien Jarno s->op_dead_args = tcg_malloc(nb_ops * sizeof(uint16_t)); 1454866cb6cbSAurelien Jarno memset(s->op_dead_args, 0, nb_ops * sizeof(uint16_t)); 1455ec7a869dSAurelien Jarno s->op_sync_args = tcg_malloc(nb_ops * sizeof(uint8_t)); 1456ec7a869dSAurelien Jarno memset(s->op_sync_args, 0, nb_ops * sizeof(uint8_t)); 1457c896fe29Sbellard } 1458c896fe29Sbellard #endif 1459c896fe29Sbellard 1460c896fe29Sbellard #ifndef NDEBUG 1461c896fe29Sbellard static void dump_regs(TCGContext *s) 1462c896fe29Sbellard { 1463c896fe29Sbellard TCGTemp *ts; 1464c896fe29Sbellard int i; 1465c896fe29Sbellard char buf[64]; 1466c896fe29Sbellard 1467c896fe29Sbellard for(i = 0; i < s->nb_temps; i++) { 1468c896fe29Sbellard ts = &s->temps[i]; 1469ac56dd48Spbrook printf(" %10s: ", tcg_get_arg_str_idx(s, buf, sizeof(buf), i)); 1470c896fe29Sbellard switch(ts->val_type) { 1471c896fe29Sbellard case TEMP_VAL_REG: 1472c896fe29Sbellard printf("%s", tcg_target_reg_names[ts->reg]); 1473c896fe29Sbellard break; 1474c896fe29Sbellard case TEMP_VAL_MEM: 1475c896fe29Sbellard printf("%d(%s)", (int)ts->mem_offset, tcg_target_reg_names[ts->mem_reg]); 1476c896fe29Sbellard break; 1477c896fe29Sbellard case TEMP_VAL_CONST: 1478c896fe29Sbellard printf("$0x%" TCG_PRIlx, ts->val); 1479c896fe29Sbellard break; 1480c896fe29Sbellard case TEMP_VAL_DEAD: 1481c896fe29Sbellard printf("D"); 1482c896fe29Sbellard break; 1483c896fe29Sbellard default: 1484c896fe29Sbellard printf("???"); 1485c896fe29Sbellard break; 1486c896fe29Sbellard } 1487c896fe29Sbellard printf("\n"); 1488c896fe29Sbellard } 1489c896fe29Sbellard 1490c896fe29Sbellard for(i = 0; i < TCG_TARGET_NB_REGS; i++) { 1491c896fe29Sbellard if (s->reg_to_temp[i] >= 0) { 1492c896fe29Sbellard printf("%s: %s\n", 1493c896fe29Sbellard tcg_target_reg_names[i], 1494ac56dd48Spbrook tcg_get_arg_str_idx(s, buf, sizeof(buf), s->reg_to_temp[i])); 1495c896fe29Sbellard } 1496c896fe29Sbellard } 1497c896fe29Sbellard } 1498c896fe29Sbellard 1499c896fe29Sbellard static void check_regs(TCGContext *s) 1500c896fe29Sbellard { 1501c896fe29Sbellard int reg, k; 1502c896fe29Sbellard TCGTemp *ts; 1503c896fe29Sbellard char buf[64]; 1504c896fe29Sbellard 1505c896fe29Sbellard for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) { 1506c896fe29Sbellard k = s->reg_to_temp[reg]; 1507c896fe29Sbellard if (k >= 0) { 1508c896fe29Sbellard ts = &s->temps[k]; 1509c896fe29Sbellard if (ts->val_type != TEMP_VAL_REG || 1510c896fe29Sbellard ts->reg != reg) { 1511c896fe29Sbellard printf("Inconsistency for register %s:\n", 1512c896fe29Sbellard tcg_target_reg_names[reg]); 1513b03cce8eSbellard goto fail; 1514c896fe29Sbellard } 1515c896fe29Sbellard } 1516c896fe29Sbellard } 1517c896fe29Sbellard for(k = 0; k < s->nb_temps; k++) { 1518c896fe29Sbellard ts = &s->temps[k]; 1519c896fe29Sbellard if (ts->val_type == TEMP_VAL_REG && 1520c896fe29Sbellard !ts->fixed_reg && 1521c896fe29Sbellard s->reg_to_temp[ts->reg] != k) { 1522c896fe29Sbellard printf("Inconsistency for temp %s:\n", 1523ac56dd48Spbrook tcg_get_arg_str_idx(s, buf, sizeof(buf), k)); 1524b03cce8eSbellard fail: 1525c896fe29Sbellard printf("reg state:\n"); 1526c896fe29Sbellard dump_regs(s); 1527c896fe29Sbellard tcg_abort(); 1528c896fe29Sbellard } 1529c896fe29Sbellard } 1530c896fe29Sbellard } 1531c896fe29Sbellard #endif 1532c896fe29Sbellard 1533c896fe29Sbellard static void temp_allocate_frame(TCGContext *s, int temp) 1534c896fe29Sbellard { 1535c896fe29Sbellard TCGTemp *ts; 1536c896fe29Sbellard ts = &s->temps[temp]; 15379b9c37c3SRichard Henderson #if !(defined(__sparc__) && TCG_TARGET_REG_BITS == 64) 15389b9c37c3SRichard Henderson /* Sparc64 stack is accessed with offset of 2047 */ 1539b591dc59SBlue Swirl s->current_frame_offset = (s->current_frame_offset + 1540b591dc59SBlue Swirl (tcg_target_long)sizeof(tcg_target_long) - 1) & 1541b591dc59SBlue Swirl ~(sizeof(tcg_target_long) - 1); 1542f44c9960SBlue Swirl #endif 1543b591dc59SBlue Swirl if (s->current_frame_offset + (tcg_target_long)sizeof(tcg_target_long) > 1544b591dc59SBlue Swirl s->frame_end) { 15455ff9d6a4Sbellard tcg_abort(); 1546b591dc59SBlue Swirl } 1547c896fe29Sbellard ts->mem_offset = s->current_frame_offset; 1548c896fe29Sbellard ts->mem_reg = s->frame_reg; 1549c896fe29Sbellard ts->mem_allocated = 1; 1550b591dc59SBlue Swirl s->current_frame_offset += (tcg_target_long)sizeof(tcg_target_long); 1551c896fe29Sbellard } 1552c896fe29Sbellard 15537f6ceedfSAurelien Jarno /* sync register 'reg' by saving it to the corresponding temporary */ 15547f6ceedfSAurelien Jarno static inline void tcg_reg_sync(TCGContext *s, int reg) 1555c896fe29Sbellard { 1556c896fe29Sbellard TCGTemp *ts; 1557c896fe29Sbellard int temp; 1558c896fe29Sbellard 1559c896fe29Sbellard temp = s->reg_to_temp[reg]; 1560c896fe29Sbellard ts = &s->temps[temp]; 1561c896fe29Sbellard assert(ts->val_type == TEMP_VAL_REG); 15627f6ceedfSAurelien Jarno if (!ts->mem_coherent && !ts->fixed_reg) { 15637f6ceedfSAurelien Jarno if (!ts->mem_allocated) { 1564c896fe29Sbellard temp_allocate_frame(s, temp); 15657f6ceedfSAurelien Jarno } 1566e4d5434cSblueswir1 tcg_out_st(s, ts->type, reg, ts->mem_reg, ts->mem_offset); 1567c896fe29Sbellard } 15687f6ceedfSAurelien Jarno ts->mem_coherent = 1; 15697f6ceedfSAurelien Jarno } 15707f6ceedfSAurelien Jarno 15717f6ceedfSAurelien Jarno /* free register 'reg' by spilling the corresponding temporary if necessary */ 15727f6ceedfSAurelien Jarno static void tcg_reg_free(TCGContext *s, int reg) 15737f6ceedfSAurelien Jarno { 15747f6ceedfSAurelien Jarno int temp; 15757f6ceedfSAurelien Jarno 15767f6ceedfSAurelien Jarno temp = s->reg_to_temp[reg]; 15777f6ceedfSAurelien Jarno if (temp != -1) { 15787f6ceedfSAurelien Jarno tcg_reg_sync(s, reg); 15797f6ceedfSAurelien Jarno s->temps[temp].val_type = TEMP_VAL_MEM; 1580c896fe29Sbellard s->reg_to_temp[reg] = -1; 1581c896fe29Sbellard } 1582c896fe29Sbellard } 1583c896fe29Sbellard 1584c896fe29Sbellard /* Allocate a register belonging to reg1 & ~reg2 */ 1585c896fe29Sbellard static int tcg_reg_alloc(TCGContext *s, TCGRegSet reg1, TCGRegSet reg2) 1586c896fe29Sbellard { 1587c896fe29Sbellard int i, reg; 1588c896fe29Sbellard TCGRegSet reg_ct; 1589c896fe29Sbellard 1590c896fe29Sbellard tcg_regset_andnot(reg_ct, reg1, reg2); 1591c896fe29Sbellard 1592c896fe29Sbellard /* first try free registers */ 15930954d0d9Sblueswir1 for(i = 0; i < ARRAY_SIZE(tcg_target_reg_alloc_order); i++) { 1594c896fe29Sbellard reg = tcg_target_reg_alloc_order[i]; 1595c896fe29Sbellard if (tcg_regset_test_reg(reg_ct, reg) && s->reg_to_temp[reg] == -1) 1596c896fe29Sbellard return reg; 1597c896fe29Sbellard } 1598c896fe29Sbellard 1599c896fe29Sbellard /* XXX: do better spill choice */ 16000954d0d9Sblueswir1 for(i = 0; i < ARRAY_SIZE(tcg_target_reg_alloc_order); i++) { 1601c896fe29Sbellard reg = tcg_target_reg_alloc_order[i]; 1602c896fe29Sbellard if (tcg_regset_test_reg(reg_ct, reg)) { 1603c896fe29Sbellard tcg_reg_free(s, reg); 1604c896fe29Sbellard return reg; 1605c896fe29Sbellard } 1606c896fe29Sbellard } 1607c896fe29Sbellard 1608c896fe29Sbellard tcg_abort(); 1609c896fe29Sbellard } 1610c896fe29Sbellard 1611639368ddSAurelien Jarno /* mark a temporary as dead. */ 1612639368ddSAurelien Jarno static inline void temp_dead(TCGContext *s, int temp) 1613639368ddSAurelien Jarno { 1614639368ddSAurelien Jarno TCGTemp *ts; 1615639368ddSAurelien Jarno 1616639368ddSAurelien Jarno ts = &s->temps[temp]; 1617639368ddSAurelien Jarno if (!ts->fixed_reg) { 1618639368ddSAurelien Jarno if (ts->val_type == TEMP_VAL_REG) { 1619639368ddSAurelien Jarno s->reg_to_temp[ts->reg] = -1; 1620639368ddSAurelien Jarno } 1621639368ddSAurelien Jarno if (temp < s->nb_globals || (ts->temp_local && ts->mem_allocated)) { 1622639368ddSAurelien Jarno ts->val_type = TEMP_VAL_MEM; 1623639368ddSAurelien Jarno } else { 1624639368ddSAurelien Jarno ts->val_type = TEMP_VAL_DEAD; 1625639368ddSAurelien Jarno } 1626639368ddSAurelien Jarno } 1627639368ddSAurelien Jarno } 1628639368ddSAurelien Jarno 16291ad80729SAurelien Jarno /* sync a temporary to memory. 'allocated_regs' is used in case a 1630e8996ee0Sbellard temporary registers needs to be allocated to store a constant. */ 16311ad80729SAurelien Jarno static inline void temp_sync(TCGContext *s, int temp, TCGRegSet allocated_regs) 1632c896fe29Sbellard { 1633c896fe29Sbellard TCGTemp *ts; 1634c896fe29Sbellard 1635641d5fbeSbellard ts = &s->temps[temp]; 1636c896fe29Sbellard if (!ts->fixed_reg) { 1637e8996ee0Sbellard switch(ts->val_type) { 16381ad80729SAurelien Jarno case TEMP_VAL_CONST: 16391ad80729SAurelien Jarno ts->reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type], 16401ad80729SAurelien Jarno allocated_regs); 16411ad80729SAurelien Jarno ts->val_type = TEMP_VAL_REG; 16421ad80729SAurelien Jarno s->reg_to_temp[ts->reg] = temp; 16431ad80729SAurelien Jarno ts->mem_coherent = 0; 16441ad80729SAurelien Jarno tcg_out_movi(s, ts->type, ts->reg, ts->val); 16451ad80729SAurelien Jarno /* fallthrough*/ 1646e8996ee0Sbellard case TEMP_VAL_REG: 16471ad80729SAurelien Jarno tcg_reg_sync(s, ts->reg); 1648e8996ee0Sbellard break; 1649e8996ee0Sbellard case TEMP_VAL_DEAD: 1650e8996ee0Sbellard case TEMP_VAL_MEM: 1651e8996ee0Sbellard break; 1652e8996ee0Sbellard default: 1653e8996ee0Sbellard tcg_abort(); 1654c896fe29Sbellard } 1655c896fe29Sbellard } 1656c896fe29Sbellard } 1657641d5fbeSbellard 16581ad80729SAurelien Jarno /* save a temporary to memory. 'allocated_regs' is used in case a 16591ad80729SAurelien Jarno temporary registers needs to be allocated to store a constant. */ 16601ad80729SAurelien Jarno static inline void temp_save(TCGContext *s, int temp, TCGRegSet allocated_regs) 16611ad80729SAurelien Jarno { 16622c0366f0SAurelien Jarno #ifdef USE_LIVENESS_ANALYSIS 16632c0366f0SAurelien Jarno /* The liveness analysis already ensures that globals are back 16642c0366f0SAurelien Jarno in memory. Keep an assert for safety. */ 16652c0366f0SAurelien Jarno assert(s->temps[temp].val_type == TEMP_VAL_MEM || s->temps[temp].fixed_reg); 16662c0366f0SAurelien Jarno #else 16671ad80729SAurelien Jarno temp_sync(s, temp, allocated_regs); 16681ad80729SAurelien Jarno temp_dead(s, temp); 16692c0366f0SAurelien Jarno #endif 16701ad80729SAurelien Jarno } 16711ad80729SAurelien Jarno 16729814dd27SDong Xu Wang /* save globals to their canonical location and assume they can be 1673641d5fbeSbellard modified be the following code. 'allocated_regs' is used in case a 1674641d5fbeSbellard temporary registers needs to be allocated to store a constant. */ 1675641d5fbeSbellard static void save_globals(TCGContext *s, TCGRegSet allocated_regs) 1676641d5fbeSbellard { 1677641d5fbeSbellard int i; 1678641d5fbeSbellard 1679641d5fbeSbellard for(i = 0; i < s->nb_globals; i++) { 1680641d5fbeSbellard temp_save(s, i, allocated_regs); 1681641d5fbeSbellard } 1682e5097dc8Sbellard } 1683e5097dc8Sbellard 16843d5c5f87SAurelien Jarno /* sync globals to their canonical location and assume they can be 16853d5c5f87SAurelien Jarno read by the following code. 'allocated_regs' is used in case a 16863d5c5f87SAurelien Jarno temporary registers needs to be allocated to store a constant. */ 16873d5c5f87SAurelien Jarno static void sync_globals(TCGContext *s, TCGRegSet allocated_regs) 16883d5c5f87SAurelien Jarno { 16893d5c5f87SAurelien Jarno int i; 16903d5c5f87SAurelien Jarno 16913d5c5f87SAurelien Jarno for (i = 0; i < s->nb_globals; i++) { 16923d5c5f87SAurelien Jarno #ifdef USE_LIVENESS_ANALYSIS 16933d5c5f87SAurelien Jarno assert(s->temps[i].val_type != TEMP_VAL_REG || s->temps[i].fixed_reg || 16943d5c5f87SAurelien Jarno s->temps[i].mem_coherent); 16953d5c5f87SAurelien Jarno #else 16963d5c5f87SAurelien Jarno temp_sync(s, i, allocated_regs); 16973d5c5f87SAurelien Jarno #endif 16983d5c5f87SAurelien Jarno } 16993d5c5f87SAurelien Jarno } 17003d5c5f87SAurelien Jarno 1701e5097dc8Sbellard /* at the end of a basic block, we assume all temporaries are dead and 1702e8996ee0Sbellard all globals are stored at their canonical location. */ 1703e8996ee0Sbellard static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs) 1704e5097dc8Sbellard { 1705e5097dc8Sbellard TCGTemp *ts; 1706e5097dc8Sbellard int i; 1707e5097dc8Sbellard 1708c896fe29Sbellard for(i = s->nb_globals; i < s->nb_temps; i++) { 1709c896fe29Sbellard ts = &s->temps[i]; 1710641d5fbeSbellard if (ts->temp_local) { 1711641d5fbeSbellard temp_save(s, i, allocated_regs); 1712641d5fbeSbellard } else { 17132c0366f0SAurelien Jarno #ifdef USE_LIVENESS_ANALYSIS 17142c0366f0SAurelien Jarno /* The liveness analysis already ensures that temps are dead. 17152c0366f0SAurelien Jarno Keep an assert for safety. */ 17162c0366f0SAurelien Jarno assert(ts->val_type == TEMP_VAL_DEAD); 17172c0366f0SAurelien Jarno #else 1718639368ddSAurelien Jarno temp_dead(s, i); 17192c0366f0SAurelien Jarno #endif 1720c896fe29Sbellard } 1721641d5fbeSbellard } 1722e8996ee0Sbellard 1723e8996ee0Sbellard save_globals(s, allocated_regs); 1724c896fe29Sbellard } 1725c896fe29Sbellard 1726866cb6cbSAurelien Jarno #define IS_DEAD_ARG(n) ((dead_args >> (n)) & 1) 1727ec7a869dSAurelien Jarno #define NEED_SYNC_ARG(n) ((sync_args >> (n)) & 1) 1728c896fe29Sbellard 1729ec7a869dSAurelien Jarno static void tcg_reg_alloc_movi(TCGContext *s, const TCGArg *args, 1730ec7a869dSAurelien Jarno uint16_t dead_args, uint8_t sync_args) 1731e8996ee0Sbellard { 1732e8996ee0Sbellard TCGTemp *ots; 1733e8996ee0Sbellard tcg_target_ulong val; 1734e8996ee0Sbellard 1735e8996ee0Sbellard ots = &s->temps[args[0]]; 1736e8996ee0Sbellard val = args[1]; 1737e8996ee0Sbellard 1738e8996ee0Sbellard if (ots->fixed_reg) { 1739e8996ee0Sbellard /* for fixed registers, we do not do any constant 1740e8996ee0Sbellard propagation */ 1741e8996ee0Sbellard tcg_out_movi(s, ots->type, ots->reg, val); 1742e8996ee0Sbellard } else { 17431235fc06Sths /* The movi is not explicitly generated here */ 1744e8996ee0Sbellard if (ots->val_type == TEMP_VAL_REG) 1745e8996ee0Sbellard s->reg_to_temp[ots->reg] = -1; 1746e8996ee0Sbellard ots->val_type = TEMP_VAL_CONST; 1747e8996ee0Sbellard ots->val = val; 1748e8996ee0Sbellard } 1749ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(0)) { 1750ec7a869dSAurelien Jarno temp_sync(s, args[0], s->reserved_regs); 1751ec7a869dSAurelien Jarno } 17524c4e1ab2SAurelien Jarno if (IS_DEAD_ARG(0)) { 17534c4e1ab2SAurelien Jarno temp_dead(s, args[0]); 17544c4e1ab2SAurelien Jarno } 1755e8996ee0Sbellard } 1756e8996ee0Sbellard 1757c896fe29Sbellard static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def, 1758ec7a869dSAurelien Jarno const TCGArg *args, uint16_t dead_args, 1759ec7a869dSAurelien Jarno uint8_t sync_args) 1760c896fe29Sbellard { 1761c29c1d7eSAurelien Jarno TCGRegSet allocated_regs; 1762c896fe29Sbellard TCGTemp *ts, *ots; 1763c29c1d7eSAurelien Jarno const TCGArgConstraint *arg_ct, *oarg_ct; 1764c896fe29Sbellard 1765c29c1d7eSAurelien Jarno tcg_regset_set(allocated_regs, s->reserved_regs); 1766c896fe29Sbellard ots = &s->temps[args[0]]; 1767c896fe29Sbellard ts = &s->temps[args[1]]; 1768c29c1d7eSAurelien Jarno oarg_ct = &def->args_ct[0]; 1769c29c1d7eSAurelien Jarno arg_ct = &def->args_ct[1]; 1770c896fe29Sbellard 1771c29c1d7eSAurelien Jarno /* If the source value is not in a register, and we're going to be 1772c29c1d7eSAurelien Jarno forced to have it in a register in order to perform the copy, 1773c29c1d7eSAurelien Jarno then copy the SOURCE value into its own register first. That way 1774c29c1d7eSAurelien Jarno we don't have to reload SOURCE the next time it is used. */ 1775c29c1d7eSAurelien Jarno if (((NEED_SYNC_ARG(0) || ots->fixed_reg) && ts->val_type != TEMP_VAL_REG) 1776c29c1d7eSAurelien Jarno || ts->val_type == TEMP_VAL_MEM) { 1777c29c1d7eSAurelien Jarno ts->reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); 1778c29c1d7eSAurelien Jarno if (ts->val_type == TEMP_VAL_MEM) { 1779c29c1d7eSAurelien Jarno tcg_out_ld(s, ts->type, ts->reg, ts->mem_reg, ts->mem_offset); 1780c29c1d7eSAurelien Jarno ts->mem_coherent = 1; 1781c896fe29Sbellard } else if (ts->val_type == TEMP_VAL_CONST) { 1782c29c1d7eSAurelien Jarno tcg_out_movi(s, ts->type, ts->reg, ts->val); 1783c29c1d7eSAurelien Jarno } 1784c29c1d7eSAurelien Jarno s->reg_to_temp[ts->reg] = args[1]; 1785c29c1d7eSAurelien Jarno ts->val_type = TEMP_VAL_REG; 1786c29c1d7eSAurelien Jarno } 1787c29c1d7eSAurelien Jarno 1788c29c1d7eSAurelien Jarno if (IS_DEAD_ARG(0) && !ots->fixed_reg) { 1789c29c1d7eSAurelien Jarno /* mov to a non-saved dead register makes no sense (even with 1790c29c1d7eSAurelien Jarno liveness analysis disabled). */ 1791c29c1d7eSAurelien Jarno assert(NEED_SYNC_ARG(0)); 1792c29c1d7eSAurelien Jarno /* The code above should have moved the temp to a register. */ 1793c29c1d7eSAurelien Jarno assert(ts->val_type == TEMP_VAL_REG); 1794c29c1d7eSAurelien Jarno if (!ots->mem_allocated) { 1795c29c1d7eSAurelien Jarno temp_allocate_frame(s, args[0]); 1796c29c1d7eSAurelien Jarno } 1797c29c1d7eSAurelien Jarno tcg_out_st(s, ots->type, ts->reg, ots->mem_reg, ots->mem_offset); 1798c29c1d7eSAurelien Jarno if (IS_DEAD_ARG(1)) { 1799c29c1d7eSAurelien Jarno temp_dead(s, args[1]); 1800c29c1d7eSAurelien Jarno } 1801c29c1d7eSAurelien Jarno temp_dead(s, args[0]); 1802c29c1d7eSAurelien Jarno } else if (ts->val_type == TEMP_VAL_CONST) { 1803e8996ee0Sbellard /* propagate constant */ 1804c29c1d7eSAurelien Jarno if (ots->val_type == TEMP_VAL_REG) { 1805e8996ee0Sbellard s->reg_to_temp[ots->reg] = -1; 1806c29c1d7eSAurelien Jarno } 1807e8996ee0Sbellard ots->val_type = TEMP_VAL_CONST; 1808e8996ee0Sbellard ots->val = ts->val; 1809e8996ee0Sbellard } else { 1810c29c1d7eSAurelien Jarno /* The code in the first if block should have moved the 1811c29c1d7eSAurelien Jarno temp to a register. */ 1812c29c1d7eSAurelien Jarno assert(ts->val_type == TEMP_VAL_REG); 1813c29c1d7eSAurelien Jarno if (IS_DEAD_ARG(1) && !ts->fixed_reg && !ots->fixed_reg) { 1814c29c1d7eSAurelien Jarno /* the mov can be suppressed */ 1815c29c1d7eSAurelien Jarno if (ots->val_type == TEMP_VAL_REG) { 1816c29c1d7eSAurelien Jarno s->reg_to_temp[ots->reg] = -1; 1817c896fe29Sbellard } 1818c29c1d7eSAurelien Jarno ots->reg = ts->reg; 1819c29c1d7eSAurelien Jarno temp_dead(s, args[1]); 1820c29c1d7eSAurelien Jarno } else { 1821c29c1d7eSAurelien Jarno if (ots->val_type != TEMP_VAL_REG) { 1822c29c1d7eSAurelien Jarno /* When allocating a new register, make sure to not spill the 1823c29c1d7eSAurelien Jarno input one. */ 1824c29c1d7eSAurelien Jarno tcg_regset_set_reg(allocated_regs, ts->reg); 1825c29c1d7eSAurelien Jarno ots->reg = tcg_reg_alloc(s, oarg_ct->u.regs, allocated_regs); 1826c29c1d7eSAurelien Jarno } 1827c29c1d7eSAurelien Jarno tcg_out_mov(s, ots->type, ots->reg, ts->reg); 1828c29c1d7eSAurelien Jarno } 1829c896fe29Sbellard ots->val_type = TEMP_VAL_REG; 1830c896fe29Sbellard ots->mem_coherent = 0; 1831c29c1d7eSAurelien Jarno s->reg_to_temp[ots->reg] = args[0]; 1832ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(0)) { 1833c29c1d7eSAurelien Jarno tcg_reg_sync(s, ots->reg); 1834c29c1d7eSAurelien Jarno } 1835ec7a869dSAurelien Jarno } 1836c896fe29Sbellard } 1837c896fe29Sbellard 1838c896fe29Sbellard static void tcg_reg_alloc_op(TCGContext *s, 1839a9751609SRichard Henderson const TCGOpDef *def, TCGOpcode opc, 1840ec7a869dSAurelien Jarno const TCGArg *args, uint16_t dead_args, 1841ec7a869dSAurelien Jarno uint8_t sync_args) 1842c896fe29Sbellard { 1843c896fe29Sbellard TCGRegSet allocated_regs; 1844c896fe29Sbellard int i, k, nb_iargs, nb_oargs, reg; 1845c896fe29Sbellard TCGArg arg; 1846c896fe29Sbellard const TCGArgConstraint *arg_ct; 1847c896fe29Sbellard TCGTemp *ts; 1848c896fe29Sbellard TCGArg new_args[TCG_MAX_OP_ARGS]; 1849c896fe29Sbellard int const_args[TCG_MAX_OP_ARGS]; 1850c896fe29Sbellard 1851c896fe29Sbellard nb_oargs = def->nb_oargs; 1852c896fe29Sbellard nb_iargs = def->nb_iargs; 1853c896fe29Sbellard 1854c896fe29Sbellard /* copy constants */ 1855c896fe29Sbellard memcpy(new_args + nb_oargs + nb_iargs, 1856c896fe29Sbellard args + nb_oargs + nb_iargs, 1857c896fe29Sbellard sizeof(TCGArg) * def->nb_cargs); 1858c896fe29Sbellard 1859c896fe29Sbellard /* satisfy input constraints */ 1860c896fe29Sbellard tcg_regset_set(allocated_regs, s->reserved_regs); 1861c896fe29Sbellard for(k = 0; k < nb_iargs; k++) { 1862c896fe29Sbellard i = def->sorted_args[nb_oargs + k]; 1863c896fe29Sbellard arg = args[i]; 1864c896fe29Sbellard arg_ct = &def->args_ct[i]; 1865c896fe29Sbellard ts = &s->temps[arg]; 1866c896fe29Sbellard if (ts->val_type == TEMP_VAL_MEM) { 1867c896fe29Sbellard reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); 1868e4d5434cSblueswir1 tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset); 1869c896fe29Sbellard ts->val_type = TEMP_VAL_REG; 1870c896fe29Sbellard ts->reg = reg; 1871c896fe29Sbellard ts->mem_coherent = 1; 1872c896fe29Sbellard s->reg_to_temp[reg] = arg; 1873c896fe29Sbellard } else if (ts->val_type == TEMP_VAL_CONST) { 1874c896fe29Sbellard if (tcg_target_const_match(ts->val, arg_ct)) { 1875c896fe29Sbellard /* constant is OK for instruction */ 1876c896fe29Sbellard const_args[i] = 1; 1877c896fe29Sbellard new_args[i] = ts->val; 1878c896fe29Sbellard goto iarg_end; 1879c896fe29Sbellard } else { 1880c896fe29Sbellard /* need to move to a register */ 1881c896fe29Sbellard reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); 1882c896fe29Sbellard tcg_out_movi(s, ts->type, reg, ts->val); 1883e8996ee0Sbellard ts->val_type = TEMP_VAL_REG; 1884e8996ee0Sbellard ts->reg = reg; 1885e8996ee0Sbellard ts->mem_coherent = 0; 1886e8996ee0Sbellard s->reg_to_temp[reg] = arg; 1887c896fe29Sbellard } 1888c896fe29Sbellard } 1889c896fe29Sbellard assert(ts->val_type == TEMP_VAL_REG); 18905ff9d6a4Sbellard if (arg_ct->ct & TCG_CT_IALIAS) { 18915ff9d6a4Sbellard if (ts->fixed_reg) { 18925ff9d6a4Sbellard /* if fixed register, we must allocate a new register 18935ff9d6a4Sbellard if the alias is not the same register */ 18945ff9d6a4Sbellard if (arg != args[arg_ct->alias_index]) 18955ff9d6a4Sbellard goto allocate_in_reg; 18965ff9d6a4Sbellard } else { 1897c896fe29Sbellard /* if the input is aliased to an output and if it is 1898c896fe29Sbellard not dead after the instruction, we must allocate 1899c896fe29Sbellard a new register and move it */ 1900866cb6cbSAurelien Jarno if (!IS_DEAD_ARG(i)) { 1901c896fe29Sbellard goto allocate_in_reg; 1902c896fe29Sbellard } 19035ff9d6a4Sbellard } 1904866cb6cbSAurelien Jarno } 1905c896fe29Sbellard reg = ts->reg; 1906c896fe29Sbellard if (tcg_regset_test_reg(arg_ct->u.regs, reg)) { 1907c896fe29Sbellard /* nothing to do : the constraint is satisfied */ 1908c896fe29Sbellard } else { 1909c896fe29Sbellard allocate_in_reg: 1910c896fe29Sbellard /* allocate a new register matching the constraint 1911c896fe29Sbellard and move the temporary register into it */ 1912c896fe29Sbellard reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); 19133b6dac34SRichard Henderson tcg_out_mov(s, ts->type, reg, ts->reg); 1914c896fe29Sbellard } 1915c896fe29Sbellard new_args[i] = reg; 1916c896fe29Sbellard const_args[i] = 0; 1917c896fe29Sbellard tcg_regset_set_reg(allocated_regs, reg); 1918c896fe29Sbellard iarg_end: ; 1919c896fe29Sbellard } 1920c896fe29Sbellard 1921c896fe29Sbellard /* mark dead temporaries and free the associated registers */ 1922866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 1923866cb6cbSAurelien Jarno if (IS_DEAD_ARG(i)) { 1924639368ddSAurelien Jarno temp_dead(s, args[i]); 1925c896fe29Sbellard } 1926c896fe29Sbellard } 1927c896fe29Sbellard 1928a52ad07eSAurelien Jarno if (def->flags & TCG_OPF_BB_END) { 1929a52ad07eSAurelien Jarno tcg_reg_alloc_bb_end(s, allocated_regs); 1930a52ad07eSAurelien Jarno } else { 1931c896fe29Sbellard if (def->flags & TCG_OPF_CALL_CLOBBER) { 1932b03cce8eSbellard /* XXX: permit generic clobber register list ? */ 1933c896fe29Sbellard for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) { 1934c896fe29Sbellard if (tcg_regset_test_reg(tcg_target_call_clobber_regs, reg)) { 1935c896fe29Sbellard tcg_reg_free(s, reg); 1936c896fe29Sbellard } 1937c896fe29Sbellard } 19383d5c5f87SAurelien Jarno } 19393d5c5f87SAurelien Jarno if (def->flags & TCG_OPF_SIDE_EFFECTS) { 19403d5c5f87SAurelien Jarno /* sync globals if the op has side effects and might trigger 19413d5c5f87SAurelien Jarno an exception. */ 19423d5c5f87SAurelien Jarno sync_globals(s, allocated_regs); 1943c896fe29Sbellard } 1944c896fe29Sbellard 1945c896fe29Sbellard /* satisfy the output constraints */ 1946c896fe29Sbellard tcg_regset_set(allocated_regs, s->reserved_regs); 1947c896fe29Sbellard for(k = 0; k < nb_oargs; k++) { 1948c896fe29Sbellard i = def->sorted_args[k]; 1949c896fe29Sbellard arg = args[i]; 1950c896fe29Sbellard arg_ct = &def->args_ct[i]; 1951c896fe29Sbellard ts = &s->temps[arg]; 1952c896fe29Sbellard if (arg_ct->ct & TCG_CT_ALIAS) { 19535ff9d6a4Sbellard reg = new_args[arg_ct->alias_index]; 1954c896fe29Sbellard } else { 1955c896fe29Sbellard /* if fixed register, we try to use it */ 1956c896fe29Sbellard reg = ts->reg; 1957c896fe29Sbellard if (ts->fixed_reg && 1958c896fe29Sbellard tcg_regset_test_reg(arg_ct->u.regs, reg)) { 1959c896fe29Sbellard goto oarg_end; 1960c896fe29Sbellard } 1961c896fe29Sbellard reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); 1962c896fe29Sbellard } 1963c896fe29Sbellard tcg_regset_set_reg(allocated_regs, reg); 1964c896fe29Sbellard /* if a fixed register is used, then a move will be done afterwards */ 1965c896fe29Sbellard if (!ts->fixed_reg) { 1966639368ddSAurelien Jarno if (ts->val_type == TEMP_VAL_REG) { 1967639368ddSAurelien Jarno s->reg_to_temp[ts->reg] = -1; 1968639368ddSAurelien Jarno } 1969c896fe29Sbellard ts->val_type = TEMP_VAL_REG; 1970c896fe29Sbellard ts->reg = reg; 1971c896fe29Sbellard /* temp value is modified, so the value kept in memory is 1972c896fe29Sbellard potentially not the same */ 1973c896fe29Sbellard ts->mem_coherent = 0; 1974c896fe29Sbellard s->reg_to_temp[reg] = arg; 1975c896fe29Sbellard } 1976c896fe29Sbellard oarg_end: 1977c896fe29Sbellard new_args[i] = reg; 1978c896fe29Sbellard } 1979e8996ee0Sbellard } 1980c896fe29Sbellard 1981c896fe29Sbellard /* emit instruction */ 1982c896fe29Sbellard tcg_out_op(s, opc, new_args, const_args); 1983c896fe29Sbellard 1984c896fe29Sbellard /* move the outputs in the correct register if needed */ 1985c896fe29Sbellard for(i = 0; i < nb_oargs; i++) { 1986c896fe29Sbellard ts = &s->temps[args[i]]; 1987c896fe29Sbellard reg = new_args[i]; 1988c896fe29Sbellard if (ts->fixed_reg && ts->reg != reg) { 19893b6dac34SRichard Henderson tcg_out_mov(s, ts->type, ts->reg, reg); 1990c896fe29Sbellard } 1991ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(i)) { 1992ec7a869dSAurelien Jarno tcg_reg_sync(s, reg); 1993ec7a869dSAurelien Jarno } 1994ec7a869dSAurelien Jarno if (IS_DEAD_ARG(i)) { 1995ec7a869dSAurelien Jarno temp_dead(s, args[i]); 1996ec7a869dSAurelien Jarno } 1997c896fe29Sbellard } 1998c896fe29Sbellard } 1999c896fe29Sbellard 2000b03cce8eSbellard #ifdef TCG_TARGET_STACK_GROWSUP 2001b03cce8eSbellard #define STACK_DIR(x) (-(x)) 2002b03cce8eSbellard #else 2003b03cce8eSbellard #define STACK_DIR(x) (x) 2004b03cce8eSbellard #endif 2005b03cce8eSbellard 2006c896fe29Sbellard static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def, 2007a9751609SRichard Henderson TCGOpcode opc, const TCGArg *args, 2008ec7a869dSAurelien Jarno uint16_t dead_args, uint8_t sync_args) 2009c896fe29Sbellard { 2010c896fe29Sbellard int nb_iargs, nb_oargs, flags, nb_regs, i, reg, nb_params; 2011c896fe29Sbellard TCGArg arg, func_arg; 2012c896fe29Sbellard TCGTemp *ts; 2013f54b3f92Saurel32 tcg_target_long stack_offset, call_stack_size, func_addr; 2014b03cce8eSbellard int const_func_arg, allocate_args; 2015c896fe29Sbellard TCGRegSet allocated_regs; 2016c896fe29Sbellard const TCGArgConstraint *arg_ct; 2017c896fe29Sbellard 2018c896fe29Sbellard arg = *args++; 2019c896fe29Sbellard 2020c896fe29Sbellard nb_oargs = arg >> 16; 2021c896fe29Sbellard nb_iargs = arg & 0xffff; 2022c896fe29Sbellard nb_params = nb_iargs - 1; 2023c896fe29Sbellard 2024c896fe29Sbellard flags = args[nb_oargs + nb_iargs]; 2025c896fe29Sbellard 20266e17d0c5SStefan Weil nb_regs = ARRAY_SIZE(tcg_target_call_iarg_regs); 2027c896fe29Sbellard if (nb_regs > nb_params) 2028c896fe29Sbellard nb_regs = nb_params; 2029c896fe29Sbellard 2030c896fe29Sbellard /* assign stack slots first */ 2031c896fe29Sbellard call_stack_size = (nb_params - nb_regs) * sizeof(tcg_target_long); 2032c896fe29Sbellard call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) & 2033c896fe29Sbellard ~(TCG_TARGET_STACK_ALIGN - 1); 2034b03cce8eSbellard allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE); 2035b03cce8eSbellard if (allocate_args) { 2036345649c0SBlue Swirl /* XXX: if more than TCG_STATIC_CALL_ARGS_SIZE is needed, 2037345649c0SBlue Swirl preallocate call stack */ 2038345649c0SBlue Swirl tcg_abort(); 2039b03cce8eSbellard } 204039cf05d3Sbellard 204139cf05d3Sbellard stack_offset = TCG_TARGET_CALL_STACK_OFFSET; 2042c896fe29Sbellard for(i = nb_regs; i < nb_params; i++) { 2043c896fe29Sbellard arg = args[nb_oargs + i]; 204439cf05d3Sbellard #ifdef TCG_TARGET_STACK_GROWSUP 204539cf05d3Sbellard stack_offset -= sizeof(tcg_target_long); 204639cf05d3Sbellard #endif 204739cf05d3Sbellard if (arg != TCG_CALL_DUMMY_ARG) { 2048c896fe29Sbellard ts = &s->temps[arg]; 2049c896fe29Sbellard if (ts->val_type == TEMP_VAL_REG) { 2050e4d5434cSblueswir1 tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, stack_offset); 2051c896fe29Sbellard } else if (ts->val_type == TEMP_VAL_MEM) { 2052c896fe29Sbellard reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type], 2053c896fe29Sbellard s->reserved_regs); 2054c896fe29Sbellard /* XXX: not correct if reading values from the stack */ 2055e4d5434cSblueswir1 tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset); 2056e4d5434cSblueswir1 tcg_out_st(s, ts->type, reg, TCG_REG_CALL_STACK, stack_offset); 2057c896fe29Sbellard } else if (ts->val_type == TEMP_VAL_CONST) { 2058c896fe29Sbellard reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type], 2059c896fe29Sbellard s->reserved_regs); 2060c896fe29Sbellard /* XXX: sign extend may be needed on some targets */ 2061c896fe29Sbellard tcg_out_movi(s, ts->type, reg, ts->val); 2062e4d5434cSblueswir1 tcg_out_st(s, ts->type, reg, TCG_REG_CALL_STACK, stack_offset); 2063c896fe29Sbellard } else { 2064c896fe29Sbellard tcg_abort(); 2065c896fe29Sbellard } 206639cf05d3Sbellard } 206739cf05d3Sbellard #ifndef TCG_TARGET_STACK_GROWSUP 206839cf05d3Sbellard stack_offset += sizeof(tcg_target_long); 206939cf05d3Sbellard #endif 2070c896fe29Sbellard } 2071c896fe29Sbellard 2072c896fe29Sbellard /* assign input registers */ 2073c896fe29Sbellard tcg_regset_set(allocated_regs, s->reserved_regs); 2074c896fe29Sbellard for(i = 0; i < nb_regs; i++) { 2075c896fe29Sbellard arg = args[nb_oargs + i]; 207639cf05d3Sbellard if (arg != TCG_CALL_DUMMY_ARG) { 2077c896fe29Sbellard ts = &s->temps[arg]; 2078c896fe29Sbellard reg = tcg_target_call_iarg_regs[i]; 2079c896fe29Sbellard tcg_reg_free(s, reg); 2080c896fe29Sbellard if (ts->val_type == TEMP_VAL_REG) { 2081c896fe29Sbellard if (ts->reg != reg) { 20823b6dac34SRichard Henderson tcg_out_mov(s, ts->type, reg, ts->reg); 2083c896fe29Sbellard } 2084c896fe29Sbellard } else if (ts->val_type == TEMP_VAL_MEM) { 2085e4d5434cSblueswir1 tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset); 2086c896fe29Sbellard } else if (ts->val_type == TEMP_VAL_CONST) { 2087c896fe29Sbellard /* XXX: sign extend ? */ 2088c896fe29Sbellard tcg_out_movi(s, ts->type, reg, ts->val); 2089c896fe29Sbellard } else { 2090c896fe29Sbellard tcg_abort(); 2091c896fe29Sbellard } 2092c896fe29Sbellard tcg_regset_set_reg(allocated_regs, reg); 2093c896fe29Sbellard } 209439cf05d3Sbellard } 2095c896fe29Sbellard 2096c896fe29Sbellard /* assign function address */ 2097c896fe29Sbellard func_arg = args[nb_oargs + nb_iargs - 1]; 2098c896fe29Sbellard arg_ct = &def->args_ct[0]; 2099c896fe29Sbellard ts = &s->temps[func_arg]; 2100f54b3f92Saurel32 func_addr = ts->val; 2101c896fe29Sbellard const_func_arg = 0; 2102c896fe29Sbellard if (ts->val_type == TEMP_VAL_MEM) { 2103c896fe29Sbellard reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); 2104e4d5434cSblueswir1 tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset); 2105c896fe29Sbellard func_arg = reg; 2106e8996ee0Sbellard tcg_regset_set_reg(allocated_regs, reg); 2107c896fe29Sbellard } else if (ts->val_type == TEMP_VAL_REG) { 2108c896fe29Sbellard reg = ts->reg; 2109c896fe29Sbellard if (!tcg_regset_test_reg(arg_ct->u.regs, reg)) { 2110c896fe29Sbellard reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); 21113b6dac34SRichard Henderson tcg_out_mov(s, ts->type, reg, ts->reg); 2112c896fe29Sbellard } 2113c896fe29Sbellard func_arg = reg; 2114e8996ee0Sbellard tcg_regset_set_reg(allocated_regs, reg); 2115c896fe29Sbellard } else if (ts->val_type == TEMP_VAL_CONST) { 2116f54b3f92Saurel32 if (tcg_target_const_match(func_addr, arg_ct)) { 2117c896fe29Sbellard const_func_arg = 1; 2118f54b3f92Saurel32 func_arg = func_addr; 2119c896fe29Sbellard } else { 2120c896fe29Sbellard reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); 2121f54b3f92Saurel32 tcg_out_movi(s, ts->type, reg, func_addr); 2122c896fe29Sbellard func_arg = reg; 2123e8996ee0Sbellard tcg_regset_set_reg(allocated_regs, reg); 2124c896fe29Sbellard } 2125c896fe29Sbellard } else { 2126c896fe29Sbellard tcg_abort(); 2127c896fe29Sbellard } 2128c896fe29Sbellard 2129e8996ee0Sbellard 2130c896fe29Sbellard /* mark dead temporaries and free the associated registers */ 2131866cb6cbSAurelien Jarno for(i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 2132866cb6cbSAurelien Jarno if (IS_DEAD_ARG(i)) { 2133639368ddSAurelien Jarno temp_dead(s, args[i]); 2134c896fe29Sbellard } 2135c896fe29Sbellard } 2136c896fe29Sbellard 2137c896fe29Sbellard /* clobber call registers */ 2138c896fe29Sbellard for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) { 2139c896fe29Sbellard if (tcg_regset_test_reg(tcg_target_call_clobber_regs, reg)) { 2140c896fe29Sbellard tcg_reg_free(s, reg); 2141c896fe29Sbellard } 2142c896fe29Sbellard } 2143c896fe29Sbellard 214478505279SAurelien Jarno /* Save globals if they might be written by the helper, sync them if 214578505279SAurelien Jarno they might be read. */ 214678505279SAurelien Jarno if (flags & TCG_CALL_NO_READ_GLOBALS) { 214778505279SAurelien Jarno /* Nothing to do */ 214878505279SAurelien Jarno } else if (flags & TCG_CALL_NO_WRITE_GLOBALS) { 214978505279SAurelien Jarno sync_globals(s, allocated_regs); 215078505279SAurelien Jarno } else { 2151e8996ee0Sbellard save_globals(s, allocated_regs); 2152b9c18f56Saurel32 } 2153c896fe29Sbellard 2154c896fe29Sbellard tcg_out_op(s, opc, &func_arg, &const_func_arg); 2155c896fe29Sbellard 2156c896fe29Sbellard /* assign output registers and emit moves if needed */ 2157c896fe29Sbellard for(i = 0; i < nb_oargs; i++) { 2158c896fe29Sbellard arg = args[i]; 2159c896fe29Sbellard ts = &s->temps[arg]; 2160c896fe29Sbellard reg = tcg_target_call_oarg_regs[i]; 2161e8996ee0Sbellard assert(s->reg_to_temp[reg] == -1); 2162c896fe29Sbellard if (ts->fixed_reg) { 2163c896fe29Sbellard if (ts->reg != reg) { 21643b6dac34SRichard Henderson tcg_out_mov(s, ts->type, ts->reg, reg); 2165c896fe29Sbellard } 2166c896fe29Sbellard } else { 2167639368ddSAurelien Jarno if (ts->val_type == TEMP_VAL_REG) { 2168639368ddSAurelien Jarno s->reg_to_temp[ts->reg] = -1; 2169639368ddSAurelien Jarno } 2170c896fe29Sbellard ts->val_type = TEMP_VAL_REG; 2171c896fe29Sbellard ts->reg = reg; 2172c896fe29Sbellard ts->mem_coherent = 0; 2173c896fe29Sbellard s->reg_to_temp[reg] = arg; 2174ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(i)) { 2175ec7a869dSAurelien Jarno tcg_reg_sync(s, reg); 2176ec7a869dSAurelien Jarno } 2177ec7a869dSAurelien Jarno if (IS_DEAD_ARG(i)) { 2178ec7a869dSAurelien Jarno temp_dead(s, args[i]); 2179c896fe29Sbellard } 2180c896fe29Sbellard } 21818c11ad25SAurelien Jarno } 2182c896fe29Sbellard 2183c896fe29Sbellard return nb_iargs + nb_oargs + def->nb_cargs + 1; 2184c896fe29Sbellard } 2185c896fe29Sbellard 2186c896fe29Sbellard #ifdef CONFIG_PROFILER 2187c896fe29Sbellard 218854604f74Saurel32 static int64_t tcg_table_op_count[NB_OPS]; 2189c896fe29Sbellard 2190871e6c35SBlue Swirl static void dump_op_count(void) 2191c896fe29Sbellard { 2192c896fe29Sbellard int i; 2193c896fe29Sbellard FILE *f; 219454604f74Saurel32 f = fopen("/tmp/op.log", "w"); 2195c896fe29Sbellard for(i = INDEX_op_end; i < NB_OPS; i++) { 219654604f74Saurel32 fprintf(f, "%s %" PRId64 "\n", tcg_op_defs[i].name, tcg_table_op_count[i]); 2197c896fe29Sbellard } 2198c896fe29Sbellard fclose(f); 2199c896fe29Sbellard } 2200c896fe29Sbellard #endif 2201c896fe29Sbellard 2202c896fe29Sbellard 2203c896fe29Sbellard static inline int tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf, 22042ba1eeb6Spbrook long search_pc) 2205c896fe29Sbellard { 2206a9751609SRichard Henderson TCGOpcode opc; 2207a9751609SRichard Henderson int op_index; 2208c896fe29Sbellard const TCGOpDef *def; 2209c896fe29Sbellard const TCGArg *args; 2210c896fe29Sbellard 2211c896fe29Sbellard #ifdef DEBUG_DISAS 22128fec2b8cSaliguori if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP))) { 221393fcfe39Saliguori qemu_log("OP:\n"); 2214eeacee4dSBlue Swirl tcg_dump_ops(s); 221593fcfe39Saliguori qemu_log("\n"); 2216c896fe29Sbellard } 2217c896fe29Sbellard #endif 2218c896fe29Sbellard 2219c5cc28ffSAurelien Jarno #ifdef CONFIG_PROFILER 2220c5cc28ffSAurelien Jarno s->opt_time -= profile_getclock(); 2221c5cc28ffSAurelien Jarno #endif 2222c5cc28ffSAurelien Jarno 22238f2e8c07SKirill Batuzov #ifdef USE_TCG_OPTIMIZATIONS 2224c4afe5c4SEvgeny Voevodin s->gen_opparam_ptr = 2225efd7f486SEvgeny Voevodin tcg_optimize(s, s->gen_opc_ptr, gen_opparam_buf, tcg_op_defs); 22268f2e8c07SKirill Batuzov #endif 22278f2e8c07SKirill Batuzov 2228a23a9ec6Sbellard #ifdef CONFIG_PROFILER 2229c5cc28ffSAurelien Jarno s->opt_time += profile_getclock(); 2230a23a9ec6Sbellard s->la_time -= profile_getclock(); 2231a23a9ec6Sbellard #endif 2232c5cc28ffSAurelien Jarno 2233c896fe29Sbellard tcg_liveness_analysis(s); 2234c5cc28ffSAurelien Jarno 2235a23a9ec6Sbellard #ifdef CONFIG_PROFILER 2236a23a9ec6Sbellard s->la_time += profile_getclock(); 2237a23a9ec6Sbellard #endif 2238c896fe29Sbellard 2239c896fe29Sbellard #ifdef DEBUG_DISAS 22408fec2b8cSaliguori if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT))) { 2241c5cc28ffSAurelien Jarno qemu_log("OP after optimization and liveness analysis:\n"); 2242eeacee4dSBlue Swirl tcg_dump_ops(s); 224393fcfe39Saliguori qemu_log("\n"); 2244c896fe29Sbellard } 2245c896fe29Sbellard #endif 2246c896fe29Sbellard 2247c896fe29Sbellard tcg_reg_alloc_start(s); 2248c896fe29Sbellard 2249c896fe29Sbellard s->code_buf = gen_code_buf; 2250c896fe29Sbellard s->code_ptr = gen_code_buf; 2251c896fe29Sbellard 2252c896fe29Sbellard args = gen_opparam_buf; 2253c896fe29Sbellard op_index = 0; 2254b3db8758Sblueswir1 2255c896fe29Sbellard for(;;) { 2256*92414b31SEvgeny Voevodin opc = s->gen_opc_buf[op_index]; 2257c896fe29Sbellard #ifdef CONFIG_PROFILER 225854604f74Saurel32 tcg_table_op_count[opc]++; 2259c896fe29Sbellard #endif 2260c896fe29Sbellard def = &tcg_op_defs[opc]; 2261c896fe29Sbellard #if 0 2262c896fe29Sbellard printf("%s: %d %d %d\n", def->name, 2263c896fe29Sbellard def->nb_oargs, def->nb_iargs, def->nb_cargs); 2264c896fe29Sbellard // dump_regs(s); 2265c896fe29Sbellard #endif 2266c896fe29Sbellard switch(opc) { 2267c896fe29Sbellard case INDEX_op_mov_i32: 2268c896fe29Sbellard case INDEX_op_mov_i64: 2269ec7a869dSAurelien Jarno tcg_reg_alloc_mov(s, def, args, s->op_dead_args[op_index], 2270ec7a869dSAurelien Jarno s->op_sync_args[op_index]); 2271c896fe29Sbellard break; 2272e8996ee0Sbellard case INDEX_op_movi_i32: 2273e8996ee0Sbellard case INDEX_op_movi_i64: 2274ec7a869dSAurelien Jarno tcg_reg_alloc_movi(s, args, s->op_dead_args[op_index], 2275ec7a869dSAurelien Jarno s->op_sync_args[op_index]); 2276e8996ee0Sbellard break; 22777e4597d7Sbellard case INDEX_op_debug_insn_start: 22787e4597d7Sbellard /* debug instruction */ 22797e4597d7Sbellard break; 2280c896fe29Sbellard case INDEX_op_nop: 2281c896fe29Sbellard case INDEX_op_nop1: 2282c896fe29Sbellard case INDEX_op_nop2: 2283c896fe29Sbellard case INDEX_op_nop3: 2284c896fe29Sbellard break; 2285c896fe29Sbellard case INDEX_op_nopn: 2286c896fe29Sbellard args += args[0]; 2287c896fe29Sbellard goto next; 22885ff9d6a4Sbellard case INDEX_op_discard: 2289639368ddSAurelien Jarno temp_dead(s, args[0]); 22905ff9d6a4Sbellard break; 2291c896fe29Sbellard case INDEX_op_set_label: 2292e8996ee0Sbellard tcg_reg_alloc_bb_end(s, s->reserved_regs); 22939d6fca70SStefan Weil tcg_out_label(s, args[0], s->code_ptr); 2294c896fe29Sbellard break; 2295c896fe29Sbellard case INDEX_op_call: 2296ec7a869dSAurelien Jarno args += tcg_reg_alloc_call(s, def, opc, args, 2297ec7a869dSAurelien Jarno s->op_dead_args[op_index], 2298ec7a869dSAurelien Jarno s->op_sync_args[op_index]); 2299c896fe29Sbellard goto next; 2300c896fe29Sbellard case INDEX_op_end: 2301c896fe29Sbellard goto the_end; 2302c896fe29Sbellard default: 230325c4d9ccSRichard Henderson /* Sanity check that we've not introduced any unhandled opcodes. */ 230425c4d9ccSRichard Henderson if (def->flags & TCG_OPF_NOT_PRESENT) { 230525c4d9ccSRichard Henderson tcg_abort(); 230625c4d9ccSRichard Henderson } 2307c896fe29Sbellard /* Note: in order to speed up the code, it would be much 2308c896fe29Sbellard faster to have specialized register allocator functions for 2309c896fe29Sbellard some common argument patterns */ 2310ec7a869dSAurelien Jarno tcg_reg_alloc_op(s, def, opc, args, s->op_dead_args[op_index], 2311ec7a869dSAurelien Jarno s->op_sync_args[op_index]); 2312c896fe29Sbellard break; 2313c896fe29Sbellard } 2314c896fe29Sbellard args += def->nb_args; 23158df1ca4bSths next: 23162ba1eeb6Spbrook if (search_pc >= 0 && search_pc < s->code_ptr - gen_code_buf) { 2317c896fe29Sbellard return op_index; 2318c896fe29Sbellard } 2319c896fe29Sbellard op_index++; 2320c896fe29Sbellard #ifndef NDEBUG 2321c896fe29Sbellard check_regs(s); 2322c896fe29Sbellard #endif 2323c896fe29Sbellard } 2324c896fe29Sbellard the_end: 2325b76f0d8cSYeongkyoon Lee #if defined(CONFIG_QEMU_LDST_OPTIMIZATION) && defined(CONFIG_SOFTMMU) 2326b76f0d8cSYeongkyoon Lee /* Generate TB finalization at the end of block */ 2327b76f0d8cSYeongkyoon Lee tcg_out_tb_finalize(s); 2328b76f0d8cSYeongkyoon Lee #endif 2329c896fe29Sbellard return -1; 2330c896fe29Sbellard } 2331c896fe29Sbellard 233254604f74Saurel32 int tcg_gen_code(TCGContext *s, uint8_t *gen_code_buf) 2333c896fe29Sbellard { 2334c896fe29Sbellard #ifdef CONFIG_PROFILER 2335c896fe29Sbellard { 2336c896fe29Sbellard int n; 2337*92414b31SEvgeny Voevodin n = (s->gen_opc_ptr - s->gen_opc_buf); 2338a23a9ec6Sbellard s->op_count += n; 2339a23a9ec6Sbellard if (n > s->op_count_max) 2340a23a9ec6Sbellard s->op_count_max = n; 2341a23a9ec6Sbellard 2342a23a9ec6Sbellard s->temp_count += s->nb_temps; 2343a23a9ec6Sbellard if (s->nb_temps > s->temp_count_max) 2344a23a9ec6Sbellard s->temp_count_max = s->nb_temps; 2345c896fe29Sbellard } 2346c896fe29Sbellard #endif 2347c896fe29Sbellard 23482ba1eeb6Spbrook tcg_gen_code_common(s, gen_code_buf, -1); 2349c896fe29Sbellard 2350c896fe29Sbellard /* flush instruction cache */ 23512aeabc08SStefan Weil flush_icache_range((tcg_target_ulong)gen_code_buf, 23522aeabc08SStefan Weil (tcg_target_ulong)s->code_ptr); 23532aeabc08SStefan Weil 2354c896fe29Sbellard return s->code_ptr - gen_code_buf; 2355c896fe29Sbellard } 2356c896fe29Sbellard 23572ba1eeb6Spbrook /* Return the index of the micro operation such as the pc after is < 2358623e265cSpbrook offset bytes from the start of the TB. The contents of gen_code_buf must 2359623e265cSpbrook not be changed, though writing the same values is ok. 2360623e265cSpbrook Return -1 if not found. */ 236154604f74Saurel32 int tcg_gen_code_search_pc(TCGContext *s, uint8_t *gen_code_buf, long offset) 2362c896fe29Sbellard { 2363623e265cSpbrook return tcg_gen_code_common(s, gen_code_buf, offset); 2364c896fe29Sbellard } 2365a23a9ec6Sbellard 2366a23a9ec6Sbellard #ifdef CONFIG_PROFILER 2367405cf9ffSStefan Weil void tcg_dump_info(FILE *f, fprintf_function cpu_fprintf) 2368a23a9ec6Sbellard { 2369a23a9ec6Sbellard TCGContext *s = &tcg_ctx; 2370a23a9ec6Sbellard int64_t tot; 2371a23a9ec6Sbellard 2372a23a9ec6Sbellard tot = s->interm_time + s->code_time; 2373a23a9ec6Sbellard cpu_fprintf(f, "JIT cycles %" PRId64 " (%0.3f s at 2.4 GHz)\n", 2374a23a9ec6Sbellard tot, tot / 2.4e9); 2375a23a9ec6Sbellard cpu_fprintf(f, "translated TBs %" PRId64 " (aborted=%" PRId64 " %0.1f%%)\n", 2376a23a9ec6Sbellard s->tb_count, 2377a23a9ec6Sbellard s->tb_count1 - s->tb_count, 2378a23a9ec6Sbellard s->tb_count1 ? (double)(s->tb_count1 - s->tb_count) / s->tb_count1 * 100.0 : 0); 2379a23a9ec6Sbellard cpu_fprintf(f, "avg ops/TB %0.1f max=%d\n", 2380a23a9ec6Sbellard s->tb_count ? (double)s->op_count / s->tb_count : 0, s->op_count_max); 2381a23a9ec6Sbellard cpu_fprintf(f, "deleted ops/TB %0.2f\n", 2382a23a9ec6Sbellard s->tb_count ? 2383a23a9ec6Sbellard (double)s->del_op_count / s->tb_count : 0); 2384a23a9ec6Sbellard cpu_fprintf(f, "avg temps/TB %0.2f max=%d\n", 2385a23a9ec6Sbellard s->tb_count ? 2386a23a9ec6Sbellard (double)s->temp_count / s->tb_count : 0, 2387a23a9ec6Sbellard s->temp_count_max); 2388a23a9ec6Sbellard 2389a23a9ec6Sbellard cpu_fprintf(f, "cycles/op %0.1f\n", 2390a23a9ec6Sbellard s->op_count ? (double)tot / s->op_count : 0); 2391a23a9ec6Sbellard cpu_fprintf(f, "cycles/in byte %0.1f\n", 2392a23a9ec6Sbellard s->code_in_len ? (double)tot / s->code_in_len : 0); 2393a23a9ec6Sbellard cpu_fprintf(f, "cycles/out byte %0.1f\n", 2394a23a9ec6Sbellard s->code_out_len ? (double)tot / s->code_out_len : 0); 2395a23a9ec6Sbellard if (tot == 0) 2396a23a9ec6Sbellard tot = 1; 2397a23a9ec6Sbellard cpu_fprintf(f, " gen_interm time %0.1f%%\n", 2398a23a9ec6Sbellard (double)s->interm_time / tot * 100.0); 2399a23a9ec6Sbellard cpu_fprintf(f, " gen_code time %0.1f%%\n", 2400a23a9ec6Sbellard (double)s->code_time / tot * 100.0); 2401c5cc28ffSAurelien Jarno cpu_fprintf(f, "optim./code time %0.1f%%\n", 2402c5cc28ffSAurelien Jarno (double)s->opt_time / (s->code_time ? s->code_time : 1) 2403c5cc28ffSAurelien Jarno * 100.0); 2404a23a9ec6Sbellard cpu_fprintf(f, "liveness/code time %0.1f%%\n", 2405a23a9ec6Sbellard (double)s->la_time / (s->code_time ? s->code_time : 1) * 100.0); 2406a23a9ec6Sbellard cpu_fprintf(f, "cpu_restore count %" PRId64 "\n", 2407a23a9ec6Sbellard s->restore_count); 2408a23a9ec6Sbellard cpu_fprintf(f, " avg cycles %0.1f\n", 2409a23a9ec6Sbellard s->restore_count ? (double)s->restore_time / s->restore_count : 0); 2410871e6c35SBlue Swirl 2411a23a9ec6Sbellard dump_op_count(); 2412a23a9ec6Sbellard } 2413a23a9ec6Sbellard #else 2414405cf9ffSStefan Weil void tcg_dump_info(FILE *f, fprintf_function cpu_fprintf) 2415a23a9ec6Sbellard { 241624bf7b3aSbellard cpu_fprintf(f, "[TCG profiler not compiled]\n"); 2417a23a9ec6Sbellard } 2418a23a9ec6Sbellard #endif 2419813da627SRichard Henderson 2420813da627SRichard Henderson #ifdef ELF_HOST_MACHINE 24215872bbf2SRichard Henderson /* In order to use this feature, the backend needs to do three things: 24225872bbf2SRichard Henderson 24235872bbf2SRichard Henderson (1) Define ELF_HOST_MACHINE to indicate both what value to 24245872bbf2SRichard Henderson put into the ELF image and to indicate support for the feature. 24255872bbf2SRichard Henderson 24265872bbf2SRichard Henderson (2) Define tcg_register_jit. This should create a buffer containing 24275872bbf2SRichard Henderson the contents of a .debug_frame section that describes the post- 24285872bbf2SRichard Henderson prologue unwind info for the tcg machine. 24295872bbf2SRichard Henderson 24305872bbf2SRichard Henderson (3) Call tcg_register_jit_int, with the constructed .debug_frame. 24315872bbf2SRichard Henderson */ 2432813da627SRichard Henderson 2433813da627SRichard Henderson /* Begin GDB interface. THE FOLLOWING MUST MATCH GDB DOCS. */ 2434813da627SRichard Henderson typedef enum { 2435813da627SRichard Henderson JIT_NOACTION = 0, 2436813da627SRichard Henderson JIT_REGISTER_FN, 2437813da627SRichard Henderson JIT_UNREGISTER_FN 2438813da627SRichard Henderson } jit_actions_t; 2439813da627SRichard Henderson 2440813da627SRichard Henderson struct jit_code_entry { 2441813da627SRichard Henderson struct jit_code_entry *next_entry; 2442813da627SRichard Henderson struct jit_code_entry *prev_entry; 2443813da627SRichard Henderson const void *symfile_addr; 2444813da627SRichard Henderson uint64_t symfile_size; 2445813da627SRichard Henderson }; 2446813da627SRichard Henderson 2447813da627SRichard Henderson struct jit_descriptor { 2448813da627SRichard Henderson uint32_t version; 2449813da627SRichard Henderson uint32_t action_flag; 2450813da627SRichard Henderson struct jit_code_entry *relevant_entry; 2451813da627SRichard Henderson struct jit_code_entry *first_entry; 2452813da627SRichard Henderson }; 2453813da627SRichard Henderson 2454813da627SRichard Henderson void __jit_debug_register_code(void) __attribute__((noinline)); 2455813da627SRichard Henderson void __jit_debug_register_code(void) 2456813da627SRichard Henderson { 2457813da627SRichard Henderson asm(""); 2458813da627SRichard Henderson } 2459813da627SRichard Henderson 2460813da627SRichard Henderson /* Must statically initialize the version, because GDB may check 2461813da627SRichard Henderson the version before we can set it. */ 2462813da627SRichard Henderson struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 }; 2463813da627SRichard Henderson 2464813da627SRichard Henderson /* End GDB interface. */ 2465813da627SRichard Henderson 2466813da627SRichard Henderson static int find_string(const char *strtab, const char *str) 2467813da627SRichard Henderson { 2468813da627SRichard Henderson const char *p = strtab + 1; 2469813da627SRichard Henderson 2470813da627SRichard Henderson while (1) { 2471813da627SRichard Henderson if (strcmp(p, str) == 0) { 2472813da627SRichard Henderson return p - strtab; 2473813da627SRichard Henderson } 2474813da627SRichard Henderson p += strlen(p) + 1; 2475813da627SRichard Henderson } 2476813da627SRichard Henderson } 2477813da627SRichard Henderson 24785872bbf2SRichard Henderson static void tcg_register_jit_int(void *buf_ptr, size_t buf_size, 2479813da627SRichard Henderson void *debug_frame, size_t debug_frame_size) 2480813da627SRichard Henderson { 24815872bbf2SRichard Henderson struct __attribute__((packed)) DebugInfo { 24825872bbf2SRichard Henderson uint32_t len; 24835872bbf2SRichard Henderson uint16_t version; 24845872bbf2SRichard Henderson uint32_t abbrev; 24855872bbf2SRichard Henderson uint8_t ptr_size; 24865872bbf2SRichard Henderson uint8_t cu_die; 24875872bbf2SRichard Henderson uint16_t cu_lang; 24885872bbf2SRichard Henderson uintptr_t cu_low_pc; 24895872bbf2SRichard Henderson uintptr_t cu_high_pc; 24905872bbf2SRichard Henderson uint8_t fn_die; 24915872bbf2SRichard Henderson char fn_name[16]; 24925872bbf2SRichard Henderson uintptr_t fn_low_pc; 24935872bbf2SRichard Henderson uintptr_t fn_high_pc; 24945872bbf2SRichard Henderson uint8_t cu_eoc; 24955872bbf2SRichard Henderson }; 2496813da627SRichard Henderson 2497813da627SRichard Henderson struct ElfImage { 2498813da627SRichard Henderson ElfW(Ehdr) ehdr; 2499813da627SRichard Henderson ElfW(Phdr) phdr; 25005872bbf2SRichard Henderson ElfW(Shdr) shdr[7]; 25015872bbf2SRichard Henderson ElfW(Sym) sym[2]; 25025872bbf2SRichard Henderson struct DebugInfo di; 25035872bbf2SRichard Henderson uint8_t da[24]; 25045872bbf2SRichard Henderson char str[80]; 25055872bbf2SRichard Henderson }; 25065872bbf2SRichard Henderson 25075872bbf2SRichard Henderson struct ElfImage *img; 25085872bbf2SRichard Henderson 25095872bbf2SRichard Henderson static const struct ElfImage img_template = { 25105872bbf2SRichard Henderson .ehdr = { 25115872bbf2SRichard Henderson .e_ident[EI_MAG0] = ELFMAG0, 25125872bbf2SRichard Henderson .e_ident[EI_MAG1] = ELFMAG1, 25135872bbf2SRichard Henderson .e_ident[EI_MAG2] = ELFMAG2, 25145872bbf2SRichard Henderson .e_ident[EI_MAG3] = ELFMAG3, 25155872bbf2SRichard Henderson .e_ident[EI_CLASS] = ELF_CLASS, 25165872bbf2SRichard Henderson .e_ident[EI_DATA] = ELF_DATA, 25175872bbf2SRichard Henderson .e_ident[EI_VERSION] = EV_CURRENT, 25185872bbf2SRichard Henderson .e_type = ET_EXEC, 25195872bbf2SRichard Henderson .e_machine = ELF_HOST_MACHINE, 25205872bbf2SRichard Henderson .e_version = EV_CURRENT, 25215872bbf2SRichard Henderson .e_phoff = offsetof(struct ElfImage, phdr), 25225872bbf2SRichard Henderson .e_shoff = offsetof(struct ElfImage, shdr), 25235872bbf2SRichard Henderson .e_ehsize = sizeof(ElfW(Shdr)), 25245872bbf2SRichard Henderson .e_phentsize = sizeof(ElfW(Phdr)), 25255872bbf2SRichard Henderson .e_phnum = 1, 25265872bbf2SRichard Henderson .e_shentsize = sizeof(ElfW(Shdr)), 25275872bbf2SRichard Henderson .e_shnum = ARRAY_SIZE(img->shdr), 25285872bbf2SRichard Henderson .e_shstrndx = ARRAY_SIZE(img->shdr) - 1, 2529abbb3eaeSRichard Henderson #ifdef ELF_HOST_FLAGS 2530abbb3eaeSRichard Henderson .e_flags = ELF_HOST_FLAGS, 2531abbb3eaeSRichard Henderson #endif 2532abbb3eaeSRichard Henderson #ifdef ELF_OSABI 2533abbb3eaeSRichard Henderson .e_ident[EI_OSABI] = ELF_OSABI, 2534abbb3eaeSRichard Henderson #endif 25355872bbf2SRichard Henderson }, 25365872bbf2SRichard Henderson .phdr = { 25375872bbf2SRichard Henderson .p_type = PT_LOAD, 25385872bbf2SRichard Henderson .p_flags = PF_X, 25395872bbf2SRichard Henderson }, 25405872bbf2SRichard Henderson .shdr = { 25415872bbf2SRichard Henderson [0] = { .sh_type = SHT_NULL }, 25425872bbf2SRichard Henderson /* Trick: The contents of code_gen_buffer are not present in 25435872bbf2SRichard Henderson this fake ELF file; that got allocated elsewhere. Therefore 25445872bbf2SRichard Henderson we mark .text as SHT_NOBITS (similar to .bss) so that readers 25455872bbf2SRichard Henderson will not look for contents. We can record any address. */ 25465872bbf2SRichard Henderson [1] = { /* .text */ 25475872bbf2SRichard Henderson .sh_type = SHT_NOBITS, 25485872bbf2SRichard Henderson .sh_flags = SHF_EXECINSTR | SHF_ALLOC, 25495872bbf2SRichard Henderson }, 25505872bbf2SRichard Henderson [2] = { /* .debug_info */ 25515872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 25525872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, di), 25535872bbf2SRichard Henderson .sh_size = sizeof(struct DebugInfo), 25545872bbf2SRichard Henderson }, 25555872bbf2SRichard Henderson [3] = { /* .debug_abbrev */ 25565872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 25575872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, da), 25585872bbf2SRichard Henderson .sh_size = sizeof(img->da), 25595872bbf2SRichard Henderson }, 25605872bbf2SRichard Henderson [4] = { /* .debug_frame */ 25615872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 25625872bbf2SRichard Henderson .sh_offset = sizeof(struct ElfImage), 25635872bbf2SRichard Henderson }, 25645872bbf2SRichard Henderson [5] = { /* .symtab */ 25655872bbf2SRichard Henderson .sh_type = SHT_SYMTAB, 25665872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, sym), 25675872bbf2SRichard Henderson .sh_size = sizeof(img->sym), 25685872bbf2SRichard Henderson .sh_info = 1, 25695872bbf2SRichard Henderson .sh_link = ARRAY_SIZE(img->shdr) - 1, 25705872bbf2SRichard Henderson .sh_entsize = sizeof(ElfW(Sym)), 25715872bbf2SRichard Henderson }, 25725872bbf2SRichard Henderson [6] = { /* .strtab */ 25735872bbf2SRichard Henderson .sh_type = SHT_STRTAB, 25745872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, str), 25755872bbf2SRichard Henderson .sh_size = sizeof(img->str), 25765872bbf2SRichard Henderson } 25775872bbf2SRichard Henderson }, 25785872bbf2SRichard Henderson .sym = { 25795872bbf2SRichard Henderson [1] = { /* code_gen_buffer */ 25805872bbf2SRichard Henderson .st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC), 25815872bbf2SRichard Henderson .st_shndx = 1, 25825872bbf2SRichard Henderson } 25835872bbf2SRichard Henderson }, 25845872bbf2SRichard Henderson .di = { 25855872bbf2SRichard Henderson .len = sizeof(struct DebugInfo) - 4, 25865872bbf2SRichard Henderson .version = 2, 25875872bbf2SRichard Henderson .ptr_size = sizeof(void *), 25885872bbf2SRichard Henderson .cu_die = 1, 25895872bbf2SRichard Henderson .cu_lang = 0x8001, /* DW_LANG_Mips_Assembler */ 25905872bbf2SRichard Henderson .fn_die = 2, 25915872bbf2SRichard Henderson .fn_name = "code_gen_buffer" 25925872bbf2SRichard Henderson }, 25935872bbf2SRichard Henderson .da = { 25945872bbf2SRichard Henderson 1, /* abbrev number (the cu) */ 25955872bbf2SRichard Henderson 0x11, 1, /* DW_TAG_compile_unit, has children */ 25965872bbf2SRichard Henderson 0x13, 0x5, /* DW_AT_language, DW_FORM_data2 */ 25975872bbf2SRichard Henderson 0x11, 0x1, /* DW_AT_low_pc, DW_FORM_addr */ 25985872bbf2SRichard Henderson 0x12, 0x1, /* DW_AT_high_pc, DW_FORM_addr */ 25995872bbf2SRichard Henderson 0, 0, /* end of abbrev */ 26005872bbf2SRichard Henderson 2, /* abbrev number (the fn) */ 26015872bbf2SRichard Henderson 0x2e, 0, /* DW_TAG_subprogram, no children */ 26025872bbf2SRichard Henderson 0x3, 0x8, /* DW_AT_name, DW_FORM_string */ 26035872bbf2SRichard Henderson 0x11, 0x1, /* DW_AT_low_pc, DW_FORM_addr */ 26045872bbf2SRichard Henderson 0x12, 0x1, /* DW_AT_high_pc, DW_FORM_addr */ 26055872bbf2SRichard Henderson 0, 0, /* end of abbrev */ 26065872bbf2SRichard Henderson 0 /* no more abbrev */ 26075872bbf2SRichard Henderson }, 26085872bbf2SRichard Henderson .str = "\0" ".text\0" ".debug_info\0" ".debug_abbrev\0" 26095872bbf2SRichard Henderson ".debug_frame\0" ".symtab\0" ".strtab\0" "code_gen_buffer", 2610813da627SRichard Henderson }; 2611813da627SRichard Henderson 2612813da627SRichard Henderson /* We only need a single jit entry; statically allocate it. */ 2613813da627SRichard Henderson static struct jit_code_entry one_entry; 2614813da627SRichard Henderson 26155872bbf2SRichard Henderson uintptr_t buf = (uintptr_t)buf_ptr; 2616813da627SRichard Henderson size_t img_size = sizeof(struct ElfImage) + debug_frame_size; 2617813da627SRichard Henderson 26185872bbf2SRichard Henderson img = g_malloc(img_size); 26195872bbf2SRichard Henderson *img = img_template; 2620813da627SRichard Henderson memcpy(img + 1, debug_frame, debug_frame_size); 2621813da627SRichard Henderson 26225872bbf2SRichard Henderson img->phdr.p_vaddr = buf; 26235872bbf2SRichard Henderson img->phdr.p_paddr = buf; 26245872bbf2SRichard Henderson img->phdr.p_memsz = buf_size; 2625813da627SRichard Henderson 26265872bbf2SRichard Henderson img->shdr[1].sh_name = find_string(img->str, ".text"); 26275872bbf2SRichard Henderson img->shdr[1].sh_addr = buf; 26285872bbf2SRichard Henderson img->shdr[1].sh_size = buf_size; 2629813da627SRichard Henderson 26305872bbf2SRichard Henderson img->shdr[2].sh_name = find_string(img->str, ".debug_info"); 26315872bbf2SRichard Henderson img->shdr[3].sh_name = find_string(img->str, ".debug_abbrev"); 26325872bbf2SRichard Henderson 26335872bbf2SRichard Henderson img->shdr[4].sh_name = find_string(img->str, ".debug_frame"); 26345872bbf2SRichard Henderson img->shdr[4].sh_size = debug_frame_size; 26355872bbf2SRichard Henderson 26365872bbf2SRichard Henderson img->shdr[5].sh_name = find_string(img->str, ".symtab"); 26375872bbf2SRichard Henderson img->shdr[6].sh_name = find_string(img->str, ".strtab"); 26385872bbf2SRichard Henderson 26395872bbf2SRichard Henderson img->sym[1].st_name = find_string(img->str, "code_gen_buffer"); 26405872bbf2SRichard Henderson img->sym[1].st_value = buf; 26415872bbf2SRichard Henderson img->sym[1].st_size = buf_size; 26425872bbf2SRichard Henderson 26435872bbf2SRichard Henderson img->di.cu_low_pc = buf; 26445872bbf2SRichard Henderson img->di.cu_high_pc = buf_size; 26455872bbf2SRichard Henderson img->di.fn_low_pc = buf; 26465872bbf2SRichard Henderson img->di.fn_high_pc = buf_size; 2647813da627SRichard Henderson 2648813da627SRichard Henderson #ifdef DEBUG_JIT 2649813da627SRichard Henderson /* Enable this block to be able to debug the ELF image file creation. 2650813da627SRichard Henderson One can use readelf, objdump, or other inspection utilities. */ 2651813da627SRichard Henderson { 2652813da627SRichard Henderson FILE *f = fopen("/tmp/qemu.jit", "w+b"); 2653813da627SRichard Henderson if (f) { 26545872bbf2SRichard Henderson if (fwrite(img, img_size, 1, f) != img_size) { 2655813da627SRichard Henderson /* Avoid stupid unused return value warning for fwrite. */ 2656813da627SRichard Henderson } 2657813da627SRichard Henderson fclose(f); 2658813da627SRichard Henderson } 2659813da627SRichard Henderson } 2660813da627SRichard Henderson #endif 2661813da627SRichard Henderson 2662813da627SRichard Henderson one_entry.symfile_addr = img; 2663813da627SRichard Henderson one_entry.symfile_size = img_size; 2664813da627SRichard Henderson 2665813da627SRichard Henderson __jit_debug_descriptor.action_flag = JIT_REGISTER_FN; 2666813da627SRichard Henderson __jit_debug_descriptor.relevant_entry = &one_entry; 2667813da627SRichard Henderson __jit_debug_descriptor.first_entry = &one_entry; 2668813da627SRichard Henderson __jit_debug_register_code(); 2669813da627SRichard Henderson } 2670813da627SRichard Henderson #else 26715872bbf2SRichard Henderson /* No support for the feature. Provide the entry point expected by exec.c, 26725872bbf2SRichard Henderson and implement the internal function we declared earlier. */ 2673813da627SRichard Henderson 2674813da627SRichard Henderson static void tcg_register_jit_int(void *buf, size_t size, 2675813da627SRichard Henderson void *debug_frame, size_t debug_frame_size) 2676813da627SRichard Henderson { 2677813da627SRichard Henderson } 2678813da627SRichard Henderson 2679813da627SRichard Henderson void tcg_register_jit(void *buf, size_t buf_size) 2680813da627SRichard Henderson { 2681813da627SRichard Henderson } 2682813da627SRichard Henderson #endif /* ELF_HOST_MACHINE */ 2683