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