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 66c896fe29Sbellard TCGRegSet tcg_target_available_regs[2]; 67c896fe29Sbellard 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 /* free all the pool */ 200c896fe29Sbellard void tcg_pool_free(TCGContext *s) 201c896fe29Sbellard { 202c896fe29Sbellard TCGPool *p, *p1; 203c896fe29Sbellard 204c896fe29Sbellard for(p = s->pool_first; p != NULL; p = p1) { 205c896fe29Sbellard p1 = p->next; 206c896fe29Sbellard qemu_free(p); 207c896fe29Sbellard } 208c896fe29Sbellard s->pool_first = NULL; 209c896fe29Sbellard s->pool_cur = s->pool_end = NULL; 210c896fe29Sbellard } 211c896fe29Sbellard 212c896fe29Sbellard void tcg_context_init(TCGContext *s) 213c896fe29Sbellard { 214c896fe29Sbellard int op, total_args, n; 215c896fe29Sbellard TCGOpDef *def; 216c896fe29Sbellard TCGArgConstraint *args_ct; 217c896fe29Sbellard int *sorted_args; 218c896fe29Sbellard 219c896fe29Sbellard memset(s, 0, sizeof(*s)); 220c896fe29Sbellard s->temps = s->static_temps; 221c896fe29Sbellard s->nb_globals = 0; 222c896fe29Sbellard 223c896fe29Sbellard /* Count total number of arguments and allocate the corresponding 224c896fe29Sbellard space */ 225c896fe29Sbellard total_args = 0; 226c896fe29Sbellard for(op = 0; op < NB_OPS; op++) { 227c896fe29Sbellard def = &tcg_op_defs[op]; 228c896fe29Sbellard n = def->nb_iargs + def->nb_oargs; 229c896fe29Sbellard total_args += n; 230c896fe29Sbellard } 231c896fe29Sbellard 232c896fe29Sbellard args_ct = qemu_malloc(sizeof(TCGArgConstraint) * total_args); 233c896fe29Sbellard sorted_args = qemu_malloc(sizeof(int) * total_args); 234c896fe29Sbellard 235c896fe29Sbellard for(op = 0; op < NB_OPS; op++) { 236c896fe29Sbellard def = &tcg_op_defs[op]; 237c896fe29Sbellard def->args_ct = args_ct; 238c896fe29Sbellard def->sorted_args = sorted_args; 239c896fe29Sbellard n = def->nb_iargs + def->nb_oargs; 240c896fe29Sbellard sorted_args += n; 241c896fe29Sbellard args_ct += n; 242c896fe29Sbellard } 243c896fe29Sbellard 244c896fe29Sbellard tcg_target_init(s); 245b03cce8eSbellard 246b03cce8eSbellard /* init global prologue and epilogue */ 247b03cce8eSbellard s->code_buf = code_gen_prologue; 248b03cce8eSbellard s->code_ptr = s->code_buf; 249b03cce8eSbellard tcg_target_qemu_prologue(s); 250b03cce8eSbellard flush_icache_range((unsigned long)s->code_buf, 251b03cce8eSbellard (unsigned long)s->code_ptr); 252c896fe29Sbellard } 253c896fe29Sbellard 254c896fe29Sbellard void tcg_set_frame(TCGContext *s, int reg, 255c896fe29Sbellard tcg_target_long start, tcg_target_long size) 256c896fe29Sbellard { 257c896fe29Sbellard s->frame_start = start; 258c896fe29Sbellard s->frame_end = start + size; 259c896fe29Sbellard s->frame_reg = reg; 260c896fe29Sbellard } 261c896fe29Sbellard 262c896fe29Sbellard void tcg_set_macro_func(TCGContext *s, TCGMacroFunc *func) 263c896fe29Sbellard { 264c896fe29Sbellard s->macro_func = func; 265c896fe29Sbellard } 266c896fe29Sbellard 267c896fe29Sbellard void tcg_func_start(TCGContext *s) 268c896fe29Sbellard { 269*e8996ee0Sbellard int i; 270c896fe29Sbellard tcg_pool_reset(s); 271c896fe29Sbellard s->nb_temps = s->nb_globals; 272*e8996ee0Sbellard for(i = 0; i < TCG_TYPE_COUNT; i++) 273*e8996ee0Sbellard s->first_free_temp[i] = -1; 274c896fe29Sbellard s->labels = tcg_malloc(sizeof(TCGLabel) * TCG_MAX_LABELS); 275c896fe29Sbellard s->nb_labels = 0; 276c896fe29Sbellard s->current_frame_offset = s->frame_start; 277c896fe29Sbellard 278c896fe29Sbellard gen_opc_ptr = gen_opc_buf; 279c896fe29Sbellard gen_opparam_ptr = gen_opparam_buf; 280c896fe29Sbellard } 281c896fe29Sbellard 282c896fe29Sbellard static inline void tcg_temp_alloc(TCGContext *s, int n) 283c896fe29Sbellard { 284c896fe29Sbellard if (n > TCG_MAX_TEMPS) 285c896fe29Sbellard tcg_abort(); 286c896fe29Sbellard } 287c896fe29Sbellard 288ac56dd48Spbrook TCGv tcg_global_reg_new(TCGType type, int reg, const char *name) 289c896fe29Sbellard { 290c896fe29Sbellard TCGContext *s = &tcg_ctx; 291c896fe29Sbellard TCGTemp *ts; 292c896fe29Sbellard int idx; 293c896fe29Sbellard 294c896fe29Sbellard #if TCG_TARGET_REG_BITS == 32 295c896fe29Sbellard if (type != TCG_TYPE_I32) 296c896fe29Sbellard tcg_abort(); 297c896fe29Sbellard #endif 298c896fe29Sbellard if (tcg_regset_test_reg(s->reserved_regs, reg)) 299c896fe29Sbellard tcg_abort(); 300c896fe29Sbellard idx = s->nb_globals; 301c896fe29Sbellard tcg_temp_alloc(s, s->nb_globals + 1); 302c896fe29Sbellard ts = &s->temps[s->nb_globals]; 303c896fe29Sbellard ts->base_type = type; 304c896fe29Sbellard ts->type = type; 305c896fe29Sbellard ts->fixed_reg = 1; 306c896fe29Sbellard ts->reg = reg; 307c896fe29Sbellard ts->name = name; 308c896fe29Sbellard s->nb_globals++; 309c896fe29Sbellard tcg_regset_set_reg(s->reserved_regs, reg); 310ac56dd48Spbrook return MAKE_TCGV(idx); 311c896fe29Sbellard } 312c896fe29Sbellard 3136a8d7b76Sbellard #if TCG_TARGET_REG_BITS == 32 3146a8d7b76Sbellard /* temporary hack to avoid register shortage for tcg_qemu_st64() */ 3156a8d7b76Sbellard TCGv tcg_global_reg2_new_hack(TCGType type, int reg1, int reg2, 3166a8d7b76Sbellard const char *name) 3176a8d7b76Sbellard { 3186a8d7b76Sbellard TCGContext *s = &tcg_ctx; 3196a8d7b76Sbellard TCGTemp *ts; 3206a8d7b76Sbellard int idx; 3216a8d7b76Sbellard char buf[64]; 3226a8d7b76Sbellard 3236a8d7b76Sbellard if (type != TCG_TYPE_I64) 3246a8d7b76Sbellard tcg_abort(); 3256a8d7b76Sbellard idx = s->nb_globals; 3266a8d7b76Sbellard tcg_temp_alloc(s, s->nb_globals + 2); 3276a8d7b76Sbellard ts = &s->temps[s->nb_globals]; 3286a8d7b76Sbellard ts->base_type = type; 3296a8d7b76Sbellard ts->type = TCG_TYPE_I32; 3306a8d7b76Sbellard ts->fixed_reg = 1; 3316a8d7b76Sbellard ts->reg = reg1; 3326a8d7b76Sbellard pstrcpy(buf, sizeof(buf), name); 3336a8d7b76Sbellard pstrcat(buf, sizeof(buf), "_0"); 3346a8d7b76Sbellard ts->name = strdup(buf); 3356a8d7b76Sbellard 3366a8d7b76Sbellard ts++; 3376a8d7b76Sbellard ts->base_type = type; 3386a8d7b76Sbellard ts->type = TCG_TYPE_I32; 3396a8d7b76Sbellard ts->fixed_reg = 1; 3406a8d7b76Sbellard ts->reg = reg2; 3416a8d7b76Sbellard pstrcpy(buf, sizeof(buf), name); 3426a8d7b76Sbellard pstrcat(buf, sizeof(buf), "_1"); 3436a8d7b76Sbellard ts->name = strdup(buf); 3446a8d7b76Sbellard 3456a8d7b76Sbellard s->nb_globals += 2; 3466a8d7b76Sbellard return MAKE_TCGV(idx); 3476a8d7b76Sbellard } 3486a8d7b76Sbellard #endif 3496a8d7b76Sbellard 350ac56dd48Spbrook TCGv tcg_global_mem_new(TCGType type, int reg, 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]; 361c896fe29Sbellard tcg_temp_alloc(s, s->nb_globals + 1); 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 } 407ac56dd48Spbrook return MAKE_TCGV(idx); 408c896fe29Sbellard } 409c896fe29Sbellard 410ac56dd48Spbrook TCGv tcg_temp_new(TCGType type) 411c896fe29Sbellard { 412c896fe29Sbellard TCGContext *s = &tcg_ctx; 413c896fe29Sbellard TCGTemp *ts; 414c896fe29Sbellard int idx; 415c896fe29Sbellard 416*e8996ee0Sbellard idx = s->first_free_temp[type]; 417*e8996ee0Sbellard if (idx != -1) { 418*e8996ee0Sbellard /* There is already an available temp with the 419*e8996ee0Sbellard right type */ 420*e8996ee0Sbellard ts = &s->temps[idx]; 421*e8996ee0Sbellard s->first_free_temp[type] = ts->next_free_temp; 422*e8996ee0Sbellard ts->temp_allocated = 1; 423*e8996ee0Sbellard } else { 424c896fe29Sbellard idx = s->nb_temps; 425c896fe29Sbellard #if TCG_TARGET_REG_BITS == 32 426c896fe29Sbellard if (type == TCG_TYPE_I64) { 427c896fe29Sbellard tcg_temp_alloc(s, s->nb_temps + 1); 428c896fe29Sbellard ts = &s->temps[s->nb_temps]; 429c896fe29Sbellard ts->base_type = type; 430c896fe29Sbellard ts->type = TCG_TYPE_I32; 431*e8996ee0Sbellard ts->temp_allocated = 1; 432c896fe29Sbellard ts->name = NULL; 433c896fe29Sbellard ts++; 434c896fe29Sbellard ts->base_type = TCG_TYPE_I32; 435c896fe29Sbellard ts->type = TCG_TYPE_I32; 436*e8996ee0Sbellard ts->temp_allocated = 1; 437c896fe29Sbellard ts->name = NULL; 438c896fe29Sbellard s->nb_temps += 2; 439c896fe29Sbellard } else 440c896fe29Sbellard #endif 441c896fe29Sbellard { 442c896fe29Sbellard tcg_temp_alloc(s, s->nb_temps + 1); 443c896fe29Sbellard ts = &s->temps[s->nb_temps]; 444c896fe29Sbellard ts->base_type = type; 445c896fe29Sbellard ts->type = type; 446*e8996ee0Sbellard ts->temp_allocated = 1; 447c896fe29Sbellard ts->name = NULL; 448c896fe29Sbellard s->nb_temps++; 449c896fe29Sbellard } 450*e8996ee0Sbellard } 451ac56dd48Spbrook return MAKE_TCGV(idx); 452c896fe29Sbellard } 453c896fe29Sbellard 454*e8996ee0Sbellard void tcg_temp_free(TCGv arg) 455c896fe29Sbellard { 456c896fe29Sbellard TCGContext *s = &tcg_ctx; 457c896fe29Sbellard TCGTemp *ts; 458*e8996ee0Sbellard int idx = GET_TCGV(arg); 459*e8996ee0Sbellard TCGType type; 460c896fe29Sbellard 461*e8996ee0Sbellard assert(idx >= s->nb_globals && idx < s->nb_temps); 462c896fe29Sbellard ts = &s->temps[idx]; 463*e8996ee0Sbellard assert(ts->temp_allocated != 0); 464*e8996ee0Sbellard ts->temp_allocated = 0; 465*e8996ee0Sbellard type = ts->base_type; 466*e8996ee0Sbellard ts->next_free_temp = s->first_free_temp[type]; 467*e8996ee0Sbellard s->first_free_temp[type] = idx; 468*e8996ee0Sbellard } 469*e8996ee0Sbellard 470*e8996ee0Sbellard 471*e8996ee0Sbellard TCGv tcg_const_i32(int32_t val) 472*e8996ee0Sbellard { 473*e8996ee0Sbellard TCGv t0; 474*e8996ee0Sbellard t0 = tcg_temp_new(TCG_TYPE_I32); 475*e8996ee0Sbellard tcg_gen_movi_i32(t0, val); 476*e8996ee0Sbellard return t0; 477c896fe29Sbellard } 478c896fe29Sbellard 479ac56dd48Spbrook TCGv tcg_const_i64(int64_t val) 480c896fe29Sbellard { 481*e8996ee0Sbellard TCGv t0; 482*e8996ee0Sbellard t0 = tcg_temp_new(TCG_TYPE_I64); 483*e8996ee0Sbellard tcg_gen_movi_i64(t0, val); 484*e8996ee0Sbellard return t0; 485c896fe29Sbellard } 486c896fe29Sbellard 487c896fe29Sbellard void tcg_register_helper(void *func, const char *name) 488c896fe29Sbellard { 489c896fe29Sbellard TCGContext *s = &tcg_ctx; 490c896fe29Sbellard int n; 491c896fe29Sbellard if ((s->nb_helpers + 1) > s->allocated_helpers) { 492c896fe29Sbellard n = s->allocated_helpers; 493c896fe29Sbellard if (n == 0) { 494c896fe29Sbellard n = 4; 495c896fe29Sbellard } else { 496c896fe29Sbellard n *= 2; 497c896fe29Sbellard } 498c896fe29Sbellard s->helpers = realloc(s->helpers, n * sizeof(TCGHelperInfo)); 499c896fe29Sbellard s->allocated_helpers = n; 500c896fe29Sbellard } 5014dc81f28Sbellard s->helpers[s->nb_helpers].func = (tcg_target_ulong)func; 502c896fe29Sbellard s->helpers[s->nb_helpers].name = name; 503c896fe29Sbellard s->nb_helpers++; 504c896fe29Sbellard } 505c896fe29Sbellard 506ac56dd48Spbrook static inline TCGType tcg_get_base_type(TCGContext *s, TCGv arg) 507c896fe29Sbellard { 508ac56dd48Spbrook return s->temps[GET_TCGV(arg)].base_type; 509c896fe29Sbellard } 510c896fe29Sbellard 511ac56dd48Spbrook static void tcg_gen_call_internal(TCGContext *s, TCGv func, 512c896fe29Sbellard unsigned int flags, 513ac56dd48Spbrook unsigned int nb_rets, const TCGv *rets, 514ac56dd48Spbrook unsigned int nb_params, const TCGv *params) 515c896fe29Sbellard { 516c896fe29Sbellard int i; 517c896fe29Sbellard *gen_opc_ptr++ = INDEX_op_call; 518c896fe29Sbellard *gen_opparam_ptr++ = (nb_rets << 16) | (nb_params + 1); 519c896fe29Sbellard for(i = 0; i < nb_rets; i++) { 520ac56dd48Spbrook *gen_opparam_ptr++ = GET_TCGV(rets[i]); 521c896fe29Sbellard } 522c896fe29Sbellard for(i = 0; i < nb_params; i++) { 523ac56dd48Spbrook *gen_opparam_ptr++ = GET_TCGV(params[i]); 524c896fe29Sbellard } 525ac56dd48Spbrook *gen_opparam_ptr++ = GET_TCGV(func); 526c896fe29Sbellard 527c896fe29Sbellard *gen_opparam_ptr++ = flags; 528c896fe29Sbellard /* total parameters, needed to go backward in the instruction stream */ 529c896fe29Sbellard *gen_opparam_ptr++ = 1 + nb_rets + nb_params + 3; 530c896fe29Sbellard } 531c896fe29Sbellard 532c896fe29Sbellard 533c896fe29Sbellard #if TCG_TARGET_REG_BITS < 64 53439cf05d3Sbellard /* Note: we convert the 64 bit args to 32 bit and do some alignment 53539cf05d3Sbellard and endian swap. Maybe it would be better to do the alignment 53639cf05d3Sbellard and endian swap in tcg_reg_alloc_call(). */ 537ac56dd48Spbrook void tcg_gen_call(TCGContext *s, TCGv func, unsigned int flags, 538ac56dd48Spbrook unsigned int nb_rets, const TCGv *rets, 539ac56dd48Spbrook unsigned int nb_params, const TCGv *args1) 540c896fe29Sbellard { 541ac56dd48Spbrook TCGv ret, *args2, rets_2[2], arg; 542c896fe29Sbellard int j, i, call_type; 543c896fe29Sbellard 544c896fe29Sbellard if (nb_rets == 1) { 545c896fe29Sbellard ret = rets[0]; 546c896fe29Sbellard if (tcg_get_base_type(s, ret) == TCG_TYPE_I64) { 547c896fe29Sbellard nb_rets = 2; 54839cf05d3Sbellard #ifdef TCG_TARGET_WORDS_BIGENDIAN 54939cf05d3Sbellard rets_2[0] = TCGV_HIGH(ret); 55039cf05d3Sbellard rets_2[1] = ret; 55139cf05d3Sbellard #else 552c896fe29Sbellard rets_2[0] = ret; 553ac56dd48Spbrook rets_2[1] = TCGV_HIGH(ret); 55439cf05d3Sbellard #endif 555c896fe29Sbellard rets = rets_2; 556c896fe29Sbellard } 557c896fe29Sbellard } 55839cf05d3Sbellard args2 = alloca((nb_params * 3) * sizeof(TCGv)); 559c896fe29Sbellard j = 0; 560c896fe29Sbellard call_type = (flags & TCG_CALL_TYPE_MASK); 561c896fe29Sbellard for(i = 0; i < nb_params; i++) { 562c896fe29Sbellard arg = args1[i]; 563c896fe29Sbellard if (tcg_get_base_type(s, arg) == TCG_TYPE_I64) { 564c896fe29Sbellard #ifdef TCG_TARGET_I386 565c896fe29Sbellard /* REGPARM case: if the third parameter is 64 bit, it is 566c896fe29Sbellard allocated on the stack */ 567c896fe29Sbellard if (j == 2 && call_type == TCG_CALL_TYPE_REGPARM) { 568c896fe29Sbellard call_type = TCG_CALL_TYPE_REGPARM_2; 569c896fe29Sbellard flags = (flags & ~TCG_CALL_TYPE_MASK) | call_type; 570c896fe29Sbellard } 571c896fe29Sbellard args2[j++] = arg; 572ac56dd48Spbrook args2[j++] = TCGV_HIGH(arg); 573c896fe29Sbellard #else 57439cf05d3Sbellard #ifdef TCG_TARGET_CALL_ALIGN_ARGS 57539cf05d3Sbellard /* some targets want aligned 64 bit args */ 57639cf05d3Sbellard if (j & 1) { 57739cf05d3Sbellard args2[j++] = TCG_CALL_DUMMY_ARG; 57839cf05d3Sbellard } 57939cf05d3Sbellard #endif 580c896fe29Sbellard #ifdef TCG_TARGET_WORDS_BIGENDIAN 581a0d69e00Sblueswir1 args2[j++] = TCGV_HIGH(arg); 582c896fe29Sbellard args2[j++] = arg; 583c896fe29Sbellard #else 584c896fe29Sbellard args2[j++] = arg; 585ac56dd48Spbrook args2[j++] = TCGV_HIGH(arg); 586c896fe29Sbellard #endif 587c896fe29Sbellard #endif 588c896fe29Sbellard } else { 589c896fe29Sbellard args2[j++] = arg; 590c896fe29Sbellard } 591c896fe29Sbellard } 592c896fe29Sbellard tcg_gen_call_internal(s, func, flags, 593c896fe29Sbellard nb_rets, rets, j, args2); 594c896fe29Sbellard } 595c896fe29Sbellard #else 596ac56dd48Spbrook void tcg_gen_call(TCGContext *s, TCGv func, unsigned int flags, 597ac56dd48Spbrook unsigned int nb_rets, const TCGv *rets, 598ac56dd48Spbrook unsigned int nb_params, const TCGv *args1) 599c896fe29Sbellard { 600c896fe29Sbellard tcg_gen_call_internal(s, func, flags, 601c896fe29Sbellard nb_rets, rets, nb_params, args1); 602c896fe29Sbellard } 603c896fe29Sbellard #endif 604c896fe29Sbellard 605ac56dd48Spbrook #if TCG_TARGET_REG_BITS == 32 606ac56dd48Spbrook void tcg_gen_shifti_i64(TCGv ret, TCGv arg1, 607c896fe29Sbellard int c, int right, int arith) 608c896fe29Sbellard { 609cf60bce4Sbellard if (c == 0) { 610cf60bce4Sbellard tcg_gen_mov_i32(ret, arg1); 611cf60bce4Sbellard tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1)); 612cf60bce4Sbellard } else if (c >= 32) { 613c896fe29Sbellard c -= 32; 614c896fe29Sbellard if (right) { 615c896fe29Sbellard if (arith) { 616ac56dd48Spbrook tcg_gen_sari_i32(ret, TCGV_HIGH(arg1), c); 617ac56dd48Spbrook tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), 31); 618c896fe29Sbellard } else { 619ac56dd48Spbrook tcg_gen_shri_i32(ret, TCGV_HIGH(arg1), c); 620ac56dd48Spbrook tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 621c896fe29Sbellard } 622c896fe29Sbellard } else { 623ac56dd48Spbrook tcg_gen_shli_i32(TCGV_HIGH(ret), arg1, c); 624c896fe29Sbellard tcg_gen_movi_i32(ret, 0); 625c896fe29Sbellard } 626c896fe29Sbellard } else { 627ac56dd48Spbrook TCGv t0, t1; 628c896fe29Sbellard 629c896fe29Sbellard t0 = tcg_temp_new(TCG_TYPE_I32); 630c896fe29Sbellard t1 = tcg_temp_new(TCG_TYPE_I32); 631c896fe29Sbellard if (right) { 632ac56dd48Spbrook tcg_gen_shli_i32(t0, TCGV_HIGH(arg1), 32 - c); 633c896fe29Sbellard if (arith) 634ac56dd48Spbrook tcg_gen_sari_i32(t1, TCGV_HIGH(arg1), c); 635c896fe29Sbellard else 636ac56dd48Spbrook tcg_gen_shri_i32(t1, TCGV_HIGH(arg1), c); 637c896fe29Sbellard tcg_gen_shri_i32(ret, arg1, c); 638c896fe29Sbellard tcg_gen_or_i32(ret, ret, t0); 639ac56dd48Spbrook tcg_gen_mov_i32(TCGV_HIGH(ret), t1); 640c896fe29Sbellard } else { 641c896fe29Sbellard tcg_gen_shri_i32(t0, arg1, 32 - c); 642c896fe29Sbellard /* Note: ret can be the same as arg1, so we use t1 */ 643c896fe29Sbellard tcg_gen_shli_i32(t1, arg1, c); 644ac56dd48Spbrook tcg_gen_shli_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), c); 645ac56dd48Spbrook tcg_gen_or_i32(TCGV_HIGH(ret), TCGV_HIGH(ret), t0); 646c896fe29Sbellard tcg_gen_mov_i32(ret, t1); 647c896fe29Sbellard } 648*e8996ee0Sbellard tcg_temp_free(t0); 649*e8996ee0Sbellard tcg_temp_free(t1); 650c896fe29Sbellard } 651c896fe29Sbellard } 652ac56dd48Spbrook #endif 653c896fe29Sbellard 654c896fe29Sbellard void tcg_reg_alloc_start(TCGContext *s) 655c896fe29Sbellard { 656c896fe29Sbellard int i; 657c896fe29Sbellard TCGTemp *ts; 658c896fe29Sbellard for(i = 0; i < s->nb_globals; i++) { 659c896fe29Sbellard ts = &s->temps[i]; 660c896fe29Sbellard if (ts->fixed_reg) { 661c896fe29Sbellard ts->val_type = TEMP_VAL_REG; 662c896fe29Sbellard } else { 663c896fe29Sbellard ts->val_type = TEMP_VAL_MEM; 664c896fe29Sbellard } 665c896fe29Sbellard } 666*e8996ee0Sbellard for(i = s->nb_globals; i < s->nb_temps; i++) { 667*e8996ee0Sbellard ts = &s->temps[i]; 668*e8996ee0Sbellard ts->val_type = TEMP_VAL_DEAD; 669*e8996ee0Sbellard ts->mem_allocated = 0; 670*e8996ee0Sbellard ts->fixed_reg = 0; 671*e8996ee0Sbellard } 672c896fe29Sbellard for(i = 0; i < TCG_TARGET_NB_REGS; i++) { 673c896fe29Sbellard s->reg_to_temp[i] = -1; 674c896fe29Sbellard } 675c896fe29Sbellard } 676c896fe29Sbellard 677ac56dd48Spbrook static char *tcg_get_arg_str_idx(TCGContext *s, char *buf, int buf_size, 678ac56dd48Spbrook int idx) 679c896fe29Sbellard { 680c896fe29Sbellard TCGTemp *ts; 681ac56dd48Spbrook 682ac56dd48Spbrook ts = &s->temps[idx]; 683ac56dd48Spbrook if (idx < s->nb_globals) { 684ac56dd48Spbrook pstrcpy(buf, buf_size, ts->name); 685c896fe29Sbellard } else { 686ac56dd48Spbrook snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals); 687c896fe29Sbellard } 688c896fe29Sbellard return buf; 689c896fe29Sbellard } 690c896fe29Sbellard 691ac56dd48Spbrook char *tcg_get_arg_str(TCGContext *s, char *buf, int buf_size, TCGv arg) 692ac56dd48Spbrook { 693ac56dd48Spbrook return tcg_get_arg_str_idx(s, buf, buf_size, GET_TCGV(arg)); 694ac56dd48Spbrook } 695ac56dd48Spbrook 696*e8996ee0Sbellard static int helper_cmp(const void *p1, const void *p2) 697*e8996ee0Sbellard { 698*e8996ee0Sbellard const TCGHelperInfo *th1 = p1; 699*e8996ee0Sbellard const TCGHelperInfo *th2 = p2; 700*e8996ee0Sbellard if (th1->func < th2->func) 701*e8996ee0Sbellard return -1; 702*e8996ee0Sbellard else if (th1->func == th2->func) 703*e8996ee0Sbellard return 0; 704*e8996ee0Sbellard else 705*e8996ee0Sbellard return 1; 706*e8996ee0Sbellard } 707*e8996ee0Sbellard 708*e8996ee0Sbellard /* find helper definition (Note: A hash table would be better) */ 7094dc81f28Sbellard static TCGHelperInfo *tcg_find_helper(TCGContext *s, tcg_target_ulong val) 7104dc81f28Sbellard { 711*e8996ee0Sbellard int m, m_min, m_max; 712*e8996ee0Sbellard TCGHelperInfo *th; 713*e8996ee0Sbellard tcg_target_ulong v; 714*e8996ee0Sbellard 715*e8996ee0Sbellard if (unlikely(!s->helpers_sorted)) { 716*e8996ee0Sbellard qsort(s->helpers, s->nb_helpers, sizeof(TCGHelperInfo), 717*e8996ee0Sbellard helper_cmp); 718*e8996ee0Sbellard s->helpers_sorted = 1; 719*e8996ee0Sbellard } 720*e8996ee0Sbellard 721*e8996ee0Sbellard /* binary search */ 722*e8996ee0Sbellard m_min = 0; 723*e8996ee0Sbellard m_max = s->nb_helpers - 1; 724*e8996ee0Sbellard while (m_min <= m_max) { 725*e8996ee0Sbellard m = (m_min + m_max) >> 1; 726*e8996ee0Sbellard th = &s->helpers[m]; 727*e8996ee0Sbellard v = th->func; 728*e8996ee0Sbellard if (v == val) 729*e8996ee0Sbellard return th; 730*e8996ee0Sbellard else if (val < v) { 731*e8996ee0Sbellard m_max = m - 1; 732*e8996ee0Sbellard } else { 733*e8996ee0Sbellard m_min = m + 1; 734*e8996ee0Sbellard } 7354dc81f28Sbellard } 7364dc81f28Sbellard return NULL; 7374dc81f28Sbellard } 7384dc81f28Sbellard 739c896fe29Sbellard void tcg_dump_ops(TCGContext *s, FILE *outfile) 740c896fe29Sbellard { 741c896fe29Sbellard const uint16_t *opc_ptr; 742c896fe29Sbellard const TCGArg *args; 743c896fe29Sbellard TCGArg arg; 7447e4597d7Sbellard int c, i, k, nb_oargs, nb_iargs, nb_cargs, first_insn; 745c896fe29Sbellard const TCGOpDef *def; 746c896fe29Sbellard char buf[128]; 747c896fe29Sbellard 7487e4597d7Sbellard first_insn = 1; 749c896fe29Sbellard opc_ptr = gen_opc_buf; 750c896fe29Sbellard args = gen_opparam_buf; 751c896fe29Sbellard while (opc_ptr < gen_opc_ptr) { 752c896fe29Sbellard c = *opc_ptr++; 753c896fe29Sbellard def = &tcg_op_defs[c]; 7547e4597d7Sbellard if (c == INDEX_op_debug_insn_start) { 7557e4597d7Sbellard uint64_t pc; 7567e4597d7Sbellard #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS 7577e4597d7Sbellard pc = ((uint64_t)args[1] << 32) | args[0]; 7587e4597d7Sbellard #else 7597e4597d7Sbellard pc = args[0]; 7607e4597d7Sbellard #endif 7617e4597d7Sbellard if (!first_insn) 7627e4597d7Sbellard fprintf(outfile, "\n"); 7637e4597d7Sbellard fprintf(outfile, " ---- 0x%" PRIx64, pc); 7647e4597d7Sbellard first_insn = 0; 7657e4597d7Sbellard nb_oargs = def->nb_oargs; 7667e4597d7Sbellard nb_iargs = def->nb_iargs; 7677e4597d7Sbellard nb_cargs = def->nb_cargs; 7687e4597d7Sbellard } else if (c == INDEX_op_call) { 769c896fe29Sbellard TCGArg arg; 7704dc81f28Sbellard 771c896fe29Sbellard /* variable number of arguments */ 772c896fe29Sbellard arg = *args++; 773c896fe29Sbellard nb_oargs = arg >> 16; 774c896fe29Sbellard nb_iargs = arg & 0xffff; 775c896fe29Sbellard nb_cargs = def->nb_cargs; 776b03cce8eSbellard 7777e4597d7Sbellard fprintf(outfile, " %s ", def->name); 7787e4597d7Sbellard 779b03cce8eSbellard /* function name */ 780b03cce8eSbellard fprintf(outfile, "%s", 781*e8996ee0Sbellard tcg_get_arg_str_idx(s, buf, sizeof(buf), args[nb_oargs + nb_iargs - 1])); 782b03cce8eSbellard /* flags */ 783b03cce8eSbellard fprintf(outfile, ",$0x%" TCG_PRIlx, 784b03cce8eSbellard args[nb_oargs + nb_iargs]); 785b03cce8eSbellard /* nb out args */ 786b03cce8eSbellard fprintf(outfile, ",$%d", nb_oargs); 787b03cce8eSbellard for(i = 0; i < nb_oargs; i++) { 788b03cce8eSbellard fprintf(outfile, ","); 789b03cce8eSbellard fprintf(outfile, "%s", 790b03cce8eSbellard tcg_get_arg_str_idx(s, buf, sizeof(buf), args[i])); 791b03cce8eSbellard } 792b03cce8eSbellard for(i = 0; i < (nb_iargs - 1); i++) { 793b03cce8eSbellard fprintf(outfile, ","); 79439cf05d3Sbellard if (args[nb_oargs + i] == TCG_CALL_DUMMY_ARG) { 79539cf05d3Sbellard fprintf(outfile, "<dummy>"); 79639cf05d3Sbellard } else { 797b03cce8eSbellard fprintf(outfile, "%s", 798b03cce8eSbellard tcg_get_arg_str_idx(s, buf, sizeof(buf), args[nb_oargs + i])); 799b03cce8eSbellard } 80039cf05d3Sbellard } 801*e8996ee0Sbellard } else if (c == INDEX_op_movi_i32 802*e8996ee0Sbellard #if TCG_TARGET_REG_BITS == 64 803*e8996ee0Sbellard || c == INDEX_op_movi_i64 804*e8996ee0Sbellard #endif 805*e8996ee0Sbellard ) { 806*e8996ee0Sbellard tcg_target_ulong val; 807*e8996ee0Sbellard TCGHelperInfo *th; 808*e8996ee0Sbellard 809*e8996ee0Sbellard nb_oargs = def->nb_oargs; 810*e8996ee0Sbellard nb_iargs = def->nb_iargs; 811*e8996ee0Sbellard nb_cargs = def->nb_cargs; 812*e8996ee0Sbellard fprintf(outfile, " %s %s,$", def->name, 813*e8996ee0Sbellard tcg_get_arg_str_idx(s, buf, sizeof(buf), args[0])); 814*e8996ee0Sbellard val = args[1]; 815*e8996ee0Sbellard th = tcg_find_helper(s, val); 816*e8996ee0Sbellard if (th) { 817*e8996ee0Sbellard fprintf(outfile, th->name); 818*e8996ee0Sbellard } else { 819*e8996ee0Sbellard if (c == INDEX_op_movi_i32) 820*e8996ee0Sbellard fprintf(outfile, "0x%x", (uint32_t)val); 821*e8996ee0Sbellard else 822*e8996ee0Sbellard fprintf(outfile, "0x%" PRIx64 , (uint64_t)val); 823*e8996ee0Sbellard } 824b03cce8eSbellard } else { 8257e4597d7Sbellard fprintf(outfile, " %s ", def->name); 826b03cce8eSbellard if (c == INDEX_op_nopn) { 827c896fe29Sbellard /* variable number of arguments */ 828c896fe29Sbellard nb_cargs = *args; 829c896fe29Sbellard nb_oargs = 0; 830c896fe29Sbellard nb_iargs = 0; 831c896fe29Sbellard } else { 832c896fe29Sbellard nb_oargs = def->nb_oargs; 833c896fe29Sbellard nb_iargs = def->nb_iargs; 834c896fe29Sbellard nb_cargs = def->nb_cargs; 835c896fe29Sbellard } 836c896fe29Sbellard 837c896fe29Sbellard k = 0; 838c896fe29Sbellard for(i = 0; i < nb_oargs; i++) { 839c896fe29Sbellard if (k != 0) 840c896fe29Sbellard fprintf(outfile, ","); 841ac56dd48Spbrook fprintf(outfile, "%s", 842ac56dd48Spbrook tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++])); 843c896fe29Sbellard } 844c896fe29Sbellard for(i = 0; i < nb_iargs; i++) { 845c896fe29Sbellard if (k != 0) 846c896fe29Sbellard fprintf(outfile, ","); 847ac56dd48Spbrook fprintf(outfile, "%s", 848ac56dd48Spbrook tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++])); 849c896fe29Sbellard } 850c896fe29Sbellard for(i = 0; i < nb_cargs; i++) { 851c896fe29Sbellard if (k != 0) 852c896fe29Sbellard fprintf(outfile, ","); 853c896fe29Sbellard arg = args[k++]; 854c896fe29Sbellard fprintf(outfile, "$0x%" TCG_PRIlx, arg); 855c896fe29Sbellard } 856b03cce8eSbellard } 857c896fe29Sbellard fprintf(outfile, "\n"); 858c896fe29Sbellard args += nb_iargs + nb_oargs + nb_cargs; 859c896fe29Sbellard } 860c896fe29Sbellard } 861c896fe29Sbellard 862c896fe29Sbellard /* we give more priority to constraints with less registers */ 863c896fe29Sbellard static int get_constraint_priority(const TCGOpDef *def, int k) 864c896fe29Sbellard { 865c896fe29Sbellard const TCGArgConstraint *arg_ct; 866c896fe29Sbellard 867c896fe29Sbellard int i, n; 868c896fe29Sbellard arg_ct = &def->args_ct[k]; 869c896fe29Sbellard if (arg_ct->ct & TCG_CT_ALIAS) { 870c896fe29Sbellard /* an alias is equivalent to a single register */ 871c896fe29Sbellard n = 1; 872c896fe29Sbellard } else { 873c896fe29Sbellard if (!(arg_ct->ct & TCG_CT_REG)) 874c896fe29Sbellard return 0; 875c896fe29Sbellard n = 0; 876c896fe29Sbellard for(i = 0; i < TCG_TARGET_NB_REGS; i++) { 877c896fe29Sbellard if (tcg_regset_test_reg(arg_ct->u.regs, i)) 878c896fe29Sbellard n++; 879c896fe29Sbellard } 880c896fe29Sbellard } 881c896fe29Sbellard return TCG_TARGET_NB_REGS - n + 1; 882c896fe29Sbellard } 883c896fe29Sbellard 884c896fe29Sbellard /* sort from highest priority to lowest */ 885c896fe29Sbellard static void sort_constraints(TCGOpDef *def, int start, int n) 886c896fe29Sbellard { 887c896fe29Sbellard int i, j, p1, p2, tmp; 888c896fe29Sbellard 889c896fe29Sbellard for(i = 0; i < n; i++) 890c896fe29Sbellard def->sorted_args[start + i] = start + i; 891c896fe29Sbellard if (n <= 1) 892c896fe29Sbellard return; 893c896fe29Sbellard for(i = 0; i < n - 1; i++) { 894c896fe29Sbellard for(j = i + 1; j < n; j++) { 895c896fe29Sbellard p1 = get_constraint_priority(def, def->sorted_args[start + i]); 896c896fe29Sbellard p2 = get_constraint_priority(def, def->sorted_args[start + j]); 897c896fe29Sbellard if (p1 < p2) { 898c896fe29Sbellard tmp = def->sorted_args[start + i]; 899c896fe29Sbellard def->sorted_args[start + i] = def->sorted_args[start + j]; 900c896fe29Sbellard def->sorted_args[start + j] = tmp; 901c896fe29Sbellard } 902c896fe29Sbellard } 903c896fe29Sbellard } 904c896fe29Sbellard } 905c896fe29Sbellard 906c896fe29Sbellard void tcg_add_target_add_op_defs(const TCGTargetOpDef *tdefs) 907c896fe29Sbellard { 908c896fe29Sbellard int op; 909c896fe29Sbellard TCGOpDef *def; 910c896fe29Sbellard const char *ct_str; 911c896fe29Sbellard int i, nb_args; 912c896fe29Sbellard 913c896fe29Sbellard for(;;) { 914c896fe29Sbellard if (tdefs->op < 0) 915c896fe29Sbellard break; 916c896fe29Sbellard op = tdefs->op; 917c896fe29Sbellard assert(op >= 0 && op < NB_OPS); 918c896fe29Sbellard def = &tcg_op_defs[op]; 919c896fe29Sbellard nb_args = def->nb_iargs + def->nb_oargs; 920c896fe29Sbellard for(i = 0; i < nb_args; i++) { 921c896fe29Sbellard ct_str = tdefs->args_ct_str[i]; 922c896fe29Sbellard tcg_regset_clear(def->args_ct[i].u.regs); 923c896fe29Sbellard def->args_ct[i].ct = 0; 924c896fe29Sbellard if (ct_str[0] >= '0' && ct_str[0] <= '9') { 925c896fe29Sbellard int oarg; 926c896fe29Sbellard oarg = ct_str[0] - '0'; 927c896fe29Sbellard assert(oarg < def->nb_oargs); 928c896fe29Sbellard assert(def->args_ct[oarg].ct & TCG_CT_REG); 929c896fe29Sbellard /* TCG_CT_ALIAS is for the output arguments. The input 9305ff9d6a4Sbellard argument is tagged with TCG_CT_IALIAS. */ 931c896fe29Sbellard def->args_ct[i] = def->args_ct[oarg]; 9325ff9d6a4Sbellard def->args_ct[oarg].ct = TCG_CT_ALIAS; 9335ff9d6a4Sbellard def->args_ct[oarg].alias_index = i; 934c896fe29Sbellard def->args_ct[i].ct |= TCG_CT_IALIAS; 9355ff9d6a4Sbellard def->args_ct[i].alias_index = oarg; 936c896fe29Sbellard } else { 937c896fe29Sbellard for(;;) { 938c896fe29Sbellard if (*ct_str == '\0') 939c896fe29Sbellard break; 940c896fe29Sbellard switch(*ct_str) { 941c896fe29Sbellard case 'i': 942c896fe29Sbellard def->args_ct[i].ct |= TCG_CT_CONST; 943c896fe29Sbellard ct_str++; 944c896fe29Sbellard break; 945c896fe29Sbellard default: 946c896fe29Sbellard if (target_parse_constraint(&def->args_ct[i], &ct_str) < 0) { 947c896fe29Sbellard fprintf(stderr, "Invalid constraint '%s' for arg %d of operation '%s'\n", 948c896fe29Sbellard ct_str, i, def->name); 949c896fe29Sbellard exit(1); 950c896fe29Sbellard } 951c896fe29Sbellard } 952c896fe29Sbellard } 953c896fe29Sbellard } 954c896fe29Sbellard } 955c896fe29Sbellard 956c896fe29Sbellard /* sort the constraints (XXX: this is just an heuristic) */ 957c896fe29Sbellard sort_constraints(def, 0, def->nb_oargs); 958c896fe29Sbellard sort_constraints(def, def->nb_oargs, def->nb_iargs); 959c896fe29Sbellard 960c896fe29Sbellard #if 0 961c896fe29Sbellard { 962c896fe29Sbellard int i; 963c896fe29Sbellard 964c896fe29Sbellard printf("%s: sorted=", def->name); 965c896fe29Sbellard for(i = 0; i < def->nb_oargs + def->nb_iargs; i++) 966c896fe29Sbellard printf(" %d", def->sorted_args[i]); 967c896fe29Sbellard printf("\n"); 968c896fe29Sbellard } 969c896fe29Sbellard #endif 970c896fe29Sbellard tdefs++; 971c896fe29Sbellard } 972c896fe29Sbellard 973c896fe29Sbellard } 974c896fe29Sbellard 975c896fe29Sbellard #ifdef USE_LIVENESS_ANALYSIS 976c896fe29Sbellard 977c896fe29Sbellard /* set a nop for an operation using 'nb_args' */ 978c896fe29Sbellard static inline void tcg_set_nop(TCGContext *s, uint16_t *opc_ptr, 979c896fe29Sbellard TCGArg *args, int nb_args) 980c896fe29Sbellard { 981c896fe29Sbellard if (nb_args == 0) { 982c896fe29Sbellard *opc_ptr = INDEX_op_nop; 983c896fe29Sbellard } else { 984c896fe29Sbellard *opc_ptr = INDEX_op_nopn; 985c896fe29Sbellard args[0] = nb_args; 986c896fe29Sbellard args[nb_args - 1] = nb_args; 987c896fe29Sbellard } 988c896fe29Sbellard } 989c896fe29Sbellard 990c896fe29Sbellard /* liveness analysis: end of basic block: globals are live, temps are dead */ 991c896fe29Sbellard static inline void tcg_la_bb_end(TCGContext *s, uint8_t *dead_temps) 992c896fe29Sbellard { 993c896fe29Sbellard memset(dead_temps, 0, s->nb_globals); 994c896fe29Sbellard memset(dead_temps + s->nb_globals, 1, s->nb_temps - s->nb_globals); 995c896fe29Sbellard } 996c896fe29Sbellard 997c896fe29Sbellard /* Liveness analysis : update the opc_dead_iargs array to tell if a 998c896fe29Sbellard given input arguments is dead. Instructions updating dead 999c896fe29Sbellard temporaries are removed. */ 1000c896fe29Sbellard void tcg_liveness_analysis(TCGContext *s) 1001c896fe29Sbellard { 1002c896fe29Sbellard int i, op_index, op, nb_args, nb_iargs, nb_oargs, arg, nb_ops; 1003c896fe29Sbellard TCGArg *args; 1004c896fe29Sbellard const TCGOpDef *def; 1005c896fe29Sbellard uint8_t *dead_temps; 1006c896fe29Sbellard unsigned int dead_iargs; 1007c896fe29Sbellard 1008c896fe29Sbellard gen_opc_ptr++; /* skip end */ 1009c896fe29Sbellard 1010c896fe29Sbellard nb_ops = gen_opc_ptr - gen_opc_buf; 1011c896fe29Sbellard 1012c896fe29Sbellard /* XXX: make it really dynamic */ 1013c896fe29Sbellard s->op_dead_iargs = tcg_malloc(OPC_BUF_SIZE * sizeof(uint16_t)); 1014c896fe29Sbellard 1015c896fe29Sbellard dead_temps = tcg_malloc(s->nb_temps); 1016c896fe29Sbellard memset(dead_temps, 1, s->nb_temps); 1017c896fe29Sbellard 1018c896fe29Sbellard args = gen_opparam_ptr; 1019c896fe29Sbellard op_index = nb_ops - 1; 1020c896fe29Sbellard while (op_index >= 0) { 1021c896fe29Sbellard op = gen_opc_buf[op_index]; 1022c896fe29Sbellard def = &tcg_op_defs[op]; 1023c896fe29Sbellard switch(op) { 1024c896fe29Sbellard case INDEX_op_call: 1025c6e113f5Sbellard { 1026c6e113f5Sbellard int call_flags; 1027c6e113f5Sbellard 1028c896fe29Sbellard nb_args = args[-1]; 1029c896fe29Sbellard args -= nb_args; 1030c896fe29Sbellard nb_iargs = args[0] & 0xffff; 1031c896fe29Sbellard nb_oargs = args[0] >> 16; 1032c896fe29Sbellard args++; 1033c6e113f5Sbellard call_flags = args[nb_oargs + nb_iargs]; 1034c6e113f5Sbellard 1035c6e113f5Sbellard /* pure functions can be removed if their result is not 1036c6e113f5Sbellard used */ 1037c6e113f5Sbellard if (call_flags & TCG_CALL_PURE) { 1038c6e113f5Sbellard for(i = 0; i < nb_oargs; i++) { 1039c6e113f5Sbellard arg = args[i]; 1040c6e113f5Sbellard if (!dead_temps[arg]) 1041c6e113f5Sbellard goto do_not_remove_call; 1042c6e113f5Sbellard } 1043c6e113f5Sbellard tcg_set_nop(s, gen_opc_buf + op_index, 1044c6e113f5Sbellard args - 1, nb_args); 1045c6e113f5Sbellard } else { 1046c6e113f5Sbellard do_not_remove_call: 1047c896fe29Sbellard 1048c896fe29Sbellard /* output args are dead */ 1049c896fe29Sbellard for(i = 0; i < nb_oargs; i++) { 1050c896fe29Sbellard arg = args[i]; 1051c896fe29Sbellard dead_temps[arg] = 1; 1052c896fe29Sbellard } 1053c896fe29Sbellard 1054c896fe29Sbellard /* globals are live (they may be used by the call) */ 1055c896fe29Sbellard memset(dead_temps, 0, s->nb_globals); 1056c896fe29Sbellard 1057c896fe29Sbellard /* input args are live */ 1058c896fe29Sbellard dead_iargs = 0; 1059c896fe29Sbellard for(i = 0; i < nb_iargs; i++) { 1060c896fe29Sbellard arg = args[i + nb_oargs]; 106139cf05d3Sbellard if (arg != TCG_CALL_DUMMY_ARG) { 1062c896fe29Sbellard if (dead_temps[arg]) { 1063c896fe29Sbellard dead_iargs |= (1 << i); 1064c896fe29Sbellard } 1065c896fe29Sbellard dead_temps[arg] = 0; 1066c896fe29Sbellard } 106739cf05d3Sbellard } 1068c896fe29Sbellard s->op_dead_iargs[op_index] = dead_iargs; 1069c6e113f5Sbellard } 1070c896fe29Sbellard args--; 1071c6e113f5Sbellard } 1072c896fe29Sbellard break; 1073c896fe29Sbellard case INDEX_op_set_label: 1074c896fe29Sbellard args--; 1075c896fe29Sbellard /* mark end of basic block */ 1076c896fe29Sbellard tcg_la_bb_end(s, dead_temps); 1077c896fe29Sbellard break; 10787e4597d7Sbellard case INDEX_op_debug_insn_start: 10797e4597d7Sbellard args -= def->nb_args; 10807e4597d7Sbellard break; 1081c896fe29Sbellard case INDEX_op_nopn: 1082c896fe29Sbellard nb_args = args[-1]; 1083c896fe29Sbellard args -= nb_args; 1084c896fe29Sbellard break; 10855ff9d6a4Sbellard case INDEX_op_discard: 10865ff9d6a4Sbellard args--; 10875ff9d6a4Sbellard /* mark the temporary as dead */ 10885ff9d6a4Sbellard dead_temps[args[0]] = 1; 10895ff9d6a4Sbellard break; 1090c896fe29Sbellard case INDEX_op_macro_2: 1091c896fe29Sbellard { 1092c896fe29Sbellard int dead_args[2], macro_id; 1093c896fe29Sbellard int saved_op_index, saved_arg_index; 1094c896fe29Sbellard int macro_op_index, macro_arg_index; 1095c896fe29Sbellard int macro_end_op_index, macro_end_arg_index; 1096c896fe29Sbellard int last_nb_temps; 1097c896fe29Sbellard 1098c896fe29Sbellard nb_args = 3; 1099c896fe29Sbellard args -= nb_args; 1100c896fe29Sbellard dead_args[0] = dead_temps[args[0]]; 1101c896fe29Sbellard dead_args[1] = dead_temps[args[1]]; 1102c896fe29Sbellard macro_id = args[2]; 1103c896fe29Sbellard 1104c896fe29Sbellard /* call the macro function which generate code 1105c896fe29Sbellard depending on the live outputs */ 1106c896fe29Sbellard saved_op_index = op_index; 1107c896fe29Sbellard saved_arg_index = args - gen_opparam_buf; 1108c896fe29Sbellard 1109c896fe29Sbellard /* add a macro start instruction */ 1110c896fe29Sbellard *gen_opc_ptr++ = INDEX_op_macro_start; 1111c896fe29Sbellard *gen_opparam_ptr++ = saved_op_index; 1112c896fe29Sbellard *gen_opparam_ptr++ = saved_arg_index; 1113c896fe29Sbellard 1114c896fe29Sbellard macro_op_index = gen_opc_ptr - gen_opc_buf; 1115c896fe29Sbellard macro_arg_index = gen_opparam_ptr - gen_opparam_buf; 1116c896fe29Sbellard 1117c896fe29Sbellard last_nb_temps = s->nb_temps; 1118c896fe29Sbellard 1119c896fe29Sbellard s->macro_func(s, macro_id, dead_args); 1120c896fe29Sbellard 1121c896fe29Sbellard /* realloc temp info (XXX: make it faster) */ 1122c896fe29Sbellard if (s->nb_temps > last_nb_temps) { 1123c896fe29Sbellard uint8_t *new_dead_temps; 1124c896fe29Sbellard 1125c896fe29Sbellard new_dead_temps = tcg_malloc(s->nb_temps); 1126c896fe29Sbellard memcpy(new_dead_temps, dead_temps, last_nb_temps); 1127c896fe29Sbellard memset(new_dead_temps + last_nb_temps, 1, 1128c896fe29Sbellard s->nb_temps - last_nb_temps); 1129c896fe29Sbellard dead_temps = new_dead_temps; 1130c896fe29Sbellard } 1131c896fe29Sbellard 1132c896fe29Sbellard macro_end_op_index = gen_opc_ptr - gen_opc_buf; 1133c896fe29Sbellard macro_end_arg_index = gen_opparam_ptr - gen_opparam_buf; 1134c896fe29Sbellard 1135c896fe29Sbellard /* end of macro: add a goto to the next instruction */ 1136c896fe29Sbellard *gen_opc_ptr++ = INDEX_op_macro_end; 1137c896fe29Sbellard *gen_opparam_ptr++ = op_index + 1; 1138c896fe29Sbellard *gen_opparam_ptr++ = saved_arg_index + nb_args; 1139c896fe29Sbellard 1140c896fe29Sbellard /* modify the macro operation to be a macro_goto */ 1141c896fe29Sbellard gen_opc_buf[op_index] = INDEX_op_macro_goto; 1142c896fe29Sbellard args[0] = macro_op_index; 1143c896fe29Sbellard args[1] = macro_arg_index; 1144c896fe29Sbellard args[2] = 0; /* dummy third arg to match the 1145c896fe29Sbellard macro parameters */ 1146c896fe29Sbellard 1147c896fe29Sbellard /* set the next instruction to the end of the macro */ 1148c896fe29Sbellard op_index = macro_end_op_index; 1149c896fe29Sbellard args = macro_end_arg_index + gen_opparam_buf; 1150c896fe29Sbellard } 1151c896fe29Sbellard break; 1152c896fe29Sbellard case INDEX_op_macro_start: 1153c896fe29Sbellard args -= 2; 1154c896fe29Sbellard op_index = args[0]; 1155c896fe29Sbellard args = gen_opparam_buf + args[1]; 1156c896fe29Sbellard break; 1157c896fe29Sbellard case INDEX_op_macro_goto: 1158c896fe29Sbellard case INDEX_op_macro_end: 1159c896fe29Sbellard tcg_abort(); /* should never happen in liveness analysis */ 1160c896fe29Sbellard case INDEX_op_end: 1161c896fe29Sbellard break; 1162c896fe29Sbellard /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */ 1163c896fe29Sbellard default: 1164c896fe29Sbellard if (op > INDEX_op_end) { 1165c896fe29Sbellard args -= def->nb_args; 1166c896fe29Sbellard nb_iargs = def->nb_iargs; 1167c896fe29Sbellard nb_oargs = def->nb_oargs; 1168c896fe29Sbellard 1169c896fe29Sbellard /* Test if the operation can be removed because all 11705ff9d6a4Sbellard its outputs are dead. We assume that nb_oargs == 0 11715ff9d6a4Sbellard implies side effects */ 11725ff9d6a4Sbellard if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) { 1173c896fe29Sbellard for(i = 0; i < nb_oargs; i++) { 1174c896fe29Sbellard arg = args[i]; 1175c896fe29Sbellard if (!dead_temps[arg]) 1176c896fe29Sbellard goto do_not_remove; 1177c896fe29Sbellard } 1178c896fe29Sbellard tcg_set_nop(s, gen_opc_buf + op_index, args, def->nb_args); 1179c896fe29Sbellard #ifdef CONFIG_PROFILER 1180a23a9ec6Sbellard s->del_op_count++; 1181c896fe29Sbellard #endif 1182c896fe29Sbellard } else { 1183c896fe29Sbellard do_not_remove: 1184c896fe29Sbellard 1185c896fe29Sbellard /* output args are dead */ 1186c896fe29Sbellard for(i = 0; i < nb_oargs; i++) { 1187c896fe29Sbellard arg = args[i]; 1188c896fe29Sbellard dead_temps[arg] = 1; 1189c896fe29Sbellard } 1190c896fe29Sbellard 1191c896fe29Sbellard /* if end of basic block, update */ 1192c896fe29Sbellard if (def->flags & TCG_OPF_BB_END) { 1193c896fe29Sbellard tcg_la_bb_end(s, dead_temps); 1194b03cce8eSbellard } else if (def->flags & TCG_OPF_CALL_CLOBBER) { 1195b03cce8eSbellard /* globals are live */ 1196b03cce8eSbellard memset(dead_temps, 0, s->nb_globals); 1197c896fe29Sbellard } 1198c896fe29Sbellard 1199c896fe29Sbellard /* input args are live */ 1200c896fe29Sbellard dead_iargs = 0; 1201c896fe29Sbellard for(i = 0; i < nb_iargs; i++) { 1202c896fe29Sbellard arg = args[i + nb_oargs]; 1203c896fe29Sbellard if (dead_temps[arg]) { 1204c896fe29Sbellard dead_iargs |= (1 << i); 1205c896fe29Sbellard } 1206c896fe29Sbellard dead_temps[arg] = 0; 1207c896fe29Sbellard } 1208c896fe29Sbellard s->op_dead_iargs[op_index] = dead_iargs; 1209c896fe29Sbellard } 1210c896fe29Sbellard } else { 1211c896fe29Sbellard /* legacy dyngen operations */ 1212c896fe29Sbellard args -= def->nb_args; 1213c896fe29Sbellard /* mark end of basic block */ 1214c896fe29Sbellard tcg_la_bb_end(s, dead_temps); 1215c896fe29Sbellard } 1216c896fe29Sbellard break; 1217c896fe29Sbellard } 1218c896fe29Sbellard op_index--; 1219c896fe29Sbellard } 1220c896fe29Sbellard 1221c896fe29Sbellard if (args != gen_opparam_buf) 1222c896fe29Sbellard tcg_abort(); 1223c896fe29Sbellard } 1224c896fe29Sbellard #else 1225c896fe29Sbellard /* dummy liveness analysis */ 1226c896fe29Sbellard void tcg_liveness_analysis(TCGContext *s) 1227c896fe29Sbellard { 1228c896fe29Sbellard int nb_ops; 1229c896fe29Sbellard nb_ops = gen_opc_ptr - gen_opc_buf; 1230c896fe29Sbellard 1231c896fe29Sbellard s->op_dead_iargs = tcg_malloc(nb_ops * sizeof(uint16_t)); 1232c896fe29Sbellard memset(s->op_dead_iargs, 0, nb_ops * sizeof(uint16_t)); 1233c896fe29Sbellard } 1234c896fe29Sbellard #endif 1235c896fe29Sbellard 1236c896fe29Sbellard #ifndef NDEBUG 1237c896fe29Sbellard static void dump_regs(TCGContext *s) 1238c896fe29Sbellard { 1239c896fe29Sbellard TCGTemp *ts; 1240c896fe29Sbellard int i; 1241c896fe29Sbellard char buf[64]; 1242c896fe29Sbellard 1243c896fe29Sbellard for(i = 0; i < s->nb_temps; i++) { 1244c896fe29Sbellard ts = &s->temps[i]; 1245ac56dd48Spbrook printf(" %10s: ", tcg_get_arg_str_idx(s, buf, sizeof(buf), i)); 1246c896fe29Sbellard switch(ts->val_type) { 1247c896fe29Sbellard case TEMP_VAL_REG: 1248c896fe29Sbellard printf("%s", tcg_target_reg_names[ts->reg]); 1249c896fe29Sbellard break; 1250c896fe29Sbellard case TEMP_VAL_MEM: 1251c896fe29Sbellard printf("%d(%s)", (int)ts->mem_offset, tcg_target_reg_names[ts->mem_reg]); 1252c896fe29Sbellard break; 1253c896fe29Sbellard case TEMP_VAL_CONST: 1254c896fe29Sbellard printf("$0x%" TCG_PRIlx, ts->val); 1255c896fe29Sbellard break; 1256c896fe29Sbellard case TEMP_VAL_DEAD: 1257c896fe29Sbellard printf("D"); 1258c896fe29Sbellard break; 1259c896fe29Sbellard default: 1260c896fe29Sbellard printf("???"); 1261c896fe29Sbellard break; 1262c896fe29Sbellard } 1263c896fe29Sbellard printf("\n"); 1264c896fe29Sbellard } 1265c896fe29Sbellard 1266c896fe29Sbellard for(i = 0; i < TCG_TARGET_NB_REGS; i++) { 1267c896fe29Sbellard if (s->reg_to_temp[i] >= 0) { 1268c896fe29Sbellard printf("%s: %s\n", 1269c896fe29Sbellard tcg_target_reg_names[i], 1270ac56dd48Spbrook tcg_get_arg_str_idx(s, buf, sizeof(buf), s->reg_to_temp[i])); 1271c896fe29Sbellard } 1272c896fe29Sbellard } 1273c896fe29Sbellard } 1274c896fe29Sbellard 1275c896fe29Sbellard static void check_regs(TCGContext *s) 1276c896fe29Sbellard { 1277c896fe29Sbellard int reg, k; 1278c896fe29Sbellard TCGTemp *ts; 1279c896fe29Sbellard char buf[64]; 1280c896fe29Sbellard 1281c896fe29Sbellard for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) { 1282c896fe29Sbellard k = s->reg_to_temp[reg]; 1283c896fe29Sbellard if (k >= 0) { 1284c896fe29Sbellard ts = &s->temps[k]; 1285c896fe29Sbellard if (ts->val_type != TEMP_VAL_REG || 1286c896fe29Sbellard ts->reg != reg) { 1287c896fe29Sbellard printf("Inconsistency for register %s:\n", 1288c896fe29Sbellard tcg_target_reg_names[reg]); 1289b03cce8eSbellard goto fail; 1290c896fe29Sbellard } 1291c896fe29Sbellard } 1292c896fe29Sbellard } 1293c896fe29Sbellard for(k = 0; k < s->nb_temps; k++) { 1294c896fe29Sbellard ts = &s->temps[k]; 1295c896fe29Sbellard if (ts->val_type == TEMP_VAL_REG && 1296c896fe29Sbellard !ts->fixed_reg && 1297c896fe29Sbellard s->reg_to_temp[ts->reg] != k) { 1298c896fe29Sbellard printf("Inconsistency for temp %s:\n", 1299ac56dd48Spbrook tcg_get_arg_str_idx(s, buf, sizeof(buf), k)); 1300b03cce8eSbellard fail: 1301c896fe29Sbellard printf("reg state:\n"); 1302c896fe29Sbellard dump_regs(s); 1303c896fe29Sbellard tcg_abort(); 1304c896fe29Sbellard } 1305c896fe29Sbellard } 1306c896fe29Sbellard } 1307c896fe29Sbellard #endif 1308c896fe29Sbellard 1309c896fe29Sbellard static void temp_allocate_frame(TCGContext *s, int temp) 1310c896fe29Sbellard { 1311c896fe29Sbellard TCGTemp *ts; 1312c896fe29Sbellard ts = &s->temps[temp]; 1313c896fe29Sbellard s->current_frame_offset = (s->current_frame_offset + sizeof(tcg_target_long) - 1) & ~(sizeof(tcg_target_long) - 1); 1314c896fe29Sbellard if (s->current_frame_offset + sizeof(tcg_target_long) > s->frame_end) 13155ff9d6a4Sbellard tcg_abort(); 1316c896fe29Sbellard ts->mem_offset = s->current_frame_offset; 1317c896fe29Sbellard ts->mem_reg = s->frame_reg; 1318c896fe29Sbellard ts->mem_allocated = 1; 1319c896fe29Sbellard s->current_frame_offset += sizeof(tcg_target_long); 1320c896fe29Sbellard } 1321c896fe29Sbellard 1322c896fe29Sbellard /* free register 'reg' by spilling the corresponding temporary if necessary */ 1323c896fe29Sbellard static void tcg_reg_free(TCGContext *s, int reg) 1324c896fe29Sbellard { 1325c896fe29Sbellard TCGTemp *ts; 1326c896fe29Sbellard int temp; 1327c896fe29Sbellard 1328c896fe29Sbellard temp = s->reg_to_temp[reg]; 1329c896fe29Sbellard if (temp != -1) { 1330c896fe29Sbellard ts = &s->temps[temp]; 1331c896fe29Sbellard assert(ts->val_type == TEMP_VAL_REG); 1332c896fe29Sbellard if (!ts->mem_coherent) { 1333c896fe29Sbellard if (!ts->mem_allocated) 1334c896fe29Sbellard temp_allocate_frame(s, temp); 1335e4d5434cSblueswir1 tcg_out_st(s, ts->type, reg, ts->mem_reg, ts->mem_offset); 1336c896fe29Sbellard } 1337c896fe29Sbellard ts->val_type = TEMP_VAL_MEM; 1338c896fe29Sbellard s->reg_to_temp[reg] = -1; 1339c896fe29Sbellard } 1340c896fe29Sbellard } 1341c896fe29Sbellard 1342c896fe29Sbellard /* Allocate a register belonging to reg1 & ~reg2 */ 1343c896fe29Sbellard static int tcg_reg_alloc(TCGContext *s, TCGRegSet reg1, TCGRegSet reg2) 1344c896fe29Sbellard { 1345c896fe29Sbellard int i, reg; 1346c896fe29Sbellard TCGRegSet reg_ct; 1347c896fe29Sbellard 1348c896fe29Sbellard tcg_regset_andnot(reg_ct, reg1, reg2); 1349c896fe29Sbellard 1350c896fe29Sbellard /* first try free registers */ 13510954d0d9Sblueswir1 for(i = 0; i < ARRAY_SIZE(tcg_target_reg_alloc_order); i++) { 1352c896fe29Sbellard reg = tcg_target_reg_alloc_order[i]; 1353c896fe29Sbellard if (tcg_regset_test_reg(reg_ct, reg) && s->reg_to_temp[reg] == -1) 1354c896fe29Sbellard return reg; 1355c896fe29Sbellard } 1356c896fe29Sbellard 1357c896fe29Sbellard /* XXX: do better spill choice */ 13580954d0d9Sblueswir1 for(i = 0; i < ARRAY_SIZE(tcg_target_reg_alloc_order); i++) { 1359c896fe29Sbellard reg = tcg_target_reg_alloc_order[i]; 1360c896fe29Sbellard if (tcg_regset_test_reg(reg_ct, reg)) { 1361c896fe29Sbellard tcg_reg_free(s, reg); 1362c896fe29Sbellard return reg; 1363c896fe29Sbellard } 1364c896fe29Sbellard } 1365c896fe29Sbellard 1366c896fe29Sbellard tcg_abort(); 1367c896fe29Sbellard } 1368c896fe29Sbellard 1369e5097dc8Sbellard /* save globals to their cannonical location and assume they can be 1370*e8996ee0Sbellard modified be the following code. 'allocated_regs' is used in case a 1371*e8996ee0Sbellard temporary registers needs to be allocated to store a constant. */ 1372*e8996ee0Sbellard static void save_globals(TCGContext *s, TCGRegSet allocated_regs) 1373c896fe29Sbellard { 1374c896fe29Sbellard TCGTemp *ts; 1375*e8996ee0Sbellard int i, reg; 1376c896fe29Sbellard 1377c896fe29Sbellard for(i = 0; i < s->nb_globals; i++) { 1378c896fe29Sbellard ts = &s->temps[i]; 1379c896fe29Sbellard if (!ts->fixed_reg) { 1380*e8996ee0Sbellard switch(ts->val_type) { 1381*e8996ee0Sbellard case TEMP_VAL_REG: 1382c896fe29Sbellard tcg_reg_free(s, ts->reg); 1383*e8996ee0Sbellard break; 1384*e8996ee0Sbellard case TEMP_VAL_DEAD: 1385e5097dc8Sbellard ts->val_type = TEMP_VAL_MEM; 1386*e8996ee0Sbellard break; 1387*e8996ee0Sbellard case TEMP_VAL_CONST: 1388*e8996ee0Sbellard reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type], 1389*e8996ee0Sbellard allocated_regs); 1390*e8996ee0Sbellard tcg_out_movi(s, ts->type, reg, ts->val); 1391*e8996ee0Sbellard tcg_out_st(s, ts->type, reg, ts->mem_reg, ts->mem_offset); 1392*e8996ee0Sbellard ts->val_type = TEMP_VAL_MEM; 1393*e8996ee0Sbellard break; 1394*e8996ee0Sbellard case TEMP_VAL_MEM: 1395*e8996ee0Sbellard break; 1396*e8996ee0Sbellard default: 1397*e8996ee0Sbellard tcg_abort(); 1398c896fe29Sbellard } 1399c896fe29Sbellard } 1400c896fe29Sbellard } 1401e5097dc8Sbellard } 1402e5097dc8Sbellard 1403e5097dc8Sbellard /* at the end of a basic block, we assume all temporaries are dead and 1404*e8996ee0Sbellard all globals are stored at their canonical location. */ 1405*e8996ee0Sbellard static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs) 1406e5097dc8Sbellard { 1407e5097dc8Sbellard TCGTemp *ts; 1408e5097dc8Sbellard int i; 1409e5097dc8Sbellard 1410c896fe29Sbellard for(i = s->nb_globals; i < s->nb_temps; i++) { 1411c896fe29Sbellard ts = &s->temps[i]; 1412c896fe29Sbellard if (ts->val_type == TEMP_VAL_REG) { 1413c896fe29Sbellard s->reg_to_temp[ts->reg] = -1; 1414c896fe29Sbellard } 1415c896fe29Sbellard ts->val_type = TEMP_VAL_DEAD; 1416c896fe29Sbellard } 1417*e8996ee0Sbellard 1418*e8996ee0Sbellard save_globals(s, allocated_regs); 1419c896fe29Sbellard } 1420c896fe29Sbellard 1421c896fe29Sbellard #define IS_DEAD_IARG(n) ((dead_iargs >> (n)) & 1) 1422c896fe29Sbellard 1423*e8996ee0Sbellard static void tcg_reg_alloc_movi(TCGContext *s, const TCGArg *args) 1424*e8996ee0Sbellard { 1425*e8996ee0Sbellard TCGTemp *ots; 1426*e8996ee0Sbellard tcg_target_ulong val; 1427*e8996ee0Sbellard 1428*e8996ee0Sbellard ots = &s->temps[args[0]]; 1429*e8996ee0Sbellard val = args[1]; 1430*e8996ee0Sbellard 1431*e8996ee0Sbellard if (ots->fixed_reg) { 1432*e8996ee0Sbellard /* for fixed registers, we do not do any constant 1433*e8996ee0Sbellard propagation */ 1434*e8996ee0Sbellard tcg_out_movi(s, ots->type, ots->reg, val); 1435*e8996ee0Sbellard } else { 1436*e8996ee0Sbellard /* The movi is not explicitely generated here */ 1437*e8996ee0Sbellard if (ots->val_type == TEMP_VAL_REG) 1438*e8996ee0Sbellard s->reg_to_temp[ots->reg] = -1; 1439*e8996ee0Sbellard ots->val_type = TEMP_VAL_CONST; 1440*e8996ee0Sbellard ots->val = val; 1441*e8996ee0Sbellard } 1442*e8996ee0Sbellard } 1443*e8996ee0Sbellard 1444c896fe29Sbellard static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def, 1445c896fe29Sbellard const TCGArg *args, 1446c896fe29Sbellard unsigned int dead_iargs) 1447c896fe29Sbellard { 1448c896fe29Sbellard TCGTemp *ts, *ots; 1449c896fe29Sbellard int reg; 1450c896fe29Sbellard const TCGArgConstraint *arg_ct; 1451c896fe29Sbellard 1452c896fe29Sbellard ots = &s->temps[args[0]]; 1453c896fe29Sbellard ts = &s->temps[args[1]]; 1454c896fe29Sbellard arg_ct = &def->args_ct[0]; 1455c896fe29Sbellard 1456*e8996ee0Sbellard /* XXX: always mark arg dead if IS_DEAD_IARG(0) */ 1457c896fe29Sbellard if (ts->val_type == TEMP_VAL_REG) { 1458c896fe29Sbellard if (IS_DEAD_IARG(0) && !ts->fixed_reg && !ots->fixed_reg) { 1459c896fe29Sbellard /* the mov can be suppressed */ 1460c896fe29Sbellard if (ots->val_type == TEMP_VAL_REG) 1461c896fe29Sbellard s->reg_to_temp[ots->reg] = -1; 1462c896fe29Sbellard reg = ts->reg; 1463c896fe29Sbellard s->reg_to_temp[reg] = -1; 1464c896fe29Sbellard ts->val_type = TEMP_VAL_DEAD; 1465c896fe29Sbellard } else { 1466c896fe29Sbellard if (ots->val_type == TEMP_VAL_REG) { 1467c896fe29Sbellard reg = ots->reg; 1468c896fe29Sbellard } else { 1469c896fe29Sbellard reg = tcg_reg_alloc(s, arg_ct->u.regs, s->reserved_regs); 1470c896fe29Sbellard } 1471c896fe29Sbellard if (ts->reg != reg) { 1472c896fe29Sbellard tcg_out_mov(s, reg, ts->reg); 1473c896fe29Sbellard } 1474c896fe29Sbellard } 1475c896fe29Sbellard } else if (ts->val_type == TEMP_VAL_MEM) { 1476c896fe29Sbellard if (ots->val_type == TEMP_VAL_REG) { 1477c896fe29Sbellard reg = ots->reg; 1478c896fe29Sbellard } else { 1479c896fe29Sbellard reg = tcg_reg_alloc(s, arg_ct->u.regs, s->reserved_regs); 1480c896fe29Sbellard } 1481e4d5434cSblueswir1 tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset); 1482c896fe29Sbellard } else if (ts->val_type == TEMP_VAL_CONST) { 1483*e8996ee0Sbellard if (ots->fixed_reg) { 1484c896fe29Sbellard reg = ots->reg; 1485c896fe29Sbellard tcg_out_movi(s, ots->type, reg, ts->val); 1486c896fe29Sbellard } else { 1487*e8996ee0Sbellard /* propagate constant */ 1488*e8996ee0Sbellard if (ots->val_type == TEMP_VAL_REG) 1489*e8996ee0Sbellard s->reg_to_temp[ots->reg] = -1; 1490*e8996ee0Sbellard ots->val_type = TEMP_VAL_CONST; 1491*e8996ee0Sbellard ots->val = ts->val; 1492*e8996ee0Sbellard return; 1493*e8996ee0Sbellard } 1494*e8996ee0Sbellard } else { 1495c896fe29Sbellard tcg_abort(); 1496c896fe29Sbellard } 1497c896fe29Sbellard s->reg_to_temp[reg] = args[0]; 1498c896fe29Sbellard ots->reg = reg; 1499c896fe29Sbellard ots->val_type = TEMP_VAL_REG; 1500c896fe29Sbellard ots->mem_coherent = 0; 1501c896fe29Sbellard } 1502c896fe29Sbellard 1503c896fe29Sbellard static void tcg_reg_alloc_op(TCGContext *s, 1504c896fe29Sbellard const TCGOpDef *def, int opc, 1505c896fe29Sbellard const TCGArg *args, 1506c896fe29Sbellard unsigned int dead_iargs) 1507c896fe29Sbellard { 1508c896fe29Sbellard TCGRegSet allocated_regs; 1509c896fe29Sbellard int i, k, nb_iargs, nb_oargs, reg; 1510c896fe29Sbellard TCGArg arg; 1511c896fe29Sbellard const TCGArgConstraint *arg_ct; 1512c896fe29Sbellard TCGTemp *ts; 1513c896fe29Sbellard TCGArg new_args[TCG_MAX_OP_ARGS]; 1514c896fe29Sbellard int const_args[TCG_MAX_OP_ARGS]; 1515c896fe29Sbellard 1516c896fe29Sbellard nb_oargs = def->nb_oargs; 1517c896fe29Sbellard nb_iargs = def->nb_iargs; 1518c896fe29Sbellard 1519c896fe29Sbellard /* copy constants */ 1520c896fe29Sbellard memcpy(new_args + nb_oargs + nb_iargs, 1521c896fe29Sbellard args + nb_oargs + nb_iargs, 1522c896fe29Sbellard sizeof(TCGArg) * def->nb_cargs); 1523c896fe29Sbellard 1524c896fe29Sbellard /* satisfy input constraints */ 1525c896fe29Sbellard tcg_regset_set(allocated_regs, s->reserved_regs); 1526c896fe29Sbellard for(k = 0; k < nb_iargs; k++) { 1527c896fe29Sbellard i = def->sorted_args[nb_oargs + k]; 1528c896fe29Sbellard arg = args[i]; 1529c896fe29Sbellard arg_ct = &def->args_ct[i]; 1530c896fe29Sbellard ts = &s->temps[arg]; 1531c896fe29Sbellard if (ts->val_type == TEMP_VAL_MEM) { 1532c896fe29Sbellard reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); 1533e4d5434cSblueswir1 tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset); 1534c896fe29Sbellard ts->val_type = TEMP_VAL_REG; 1535c896fe29Sbellard ts->reg = reg; 1536c896fe29Sbellard ts->mem_coherent = 1; 1537c896fe29Sbellard s->reg_to_temp[reg] = arg; 1538c896fe29Sbellard } else if (ts->val_type == TEMP_VAL_CONST) { 1539c896fe29Sbellard if (tcg_target_const_match(ts->val, arg_ct)) { 1540c896fe29Sbellard /* constant is OK for instruction */ 1541c896fe29Sbellard const_args[i] = 1; 1542c896fe29Sbellard new_args[i] = ts->val; 1543c896fe29Sbellard goto iarg_end; 1544c896fe29Sbellard } else { 1545c896fe29Sbellard /* need to move to a register */ 1546c896fe29Sbellard reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); 1547c896fe29Sbellard tcg_out_movi(s, ts->type, reg, ts->val); 1548*e8996ee0Sbellard ts->val_type = TEMP_VAL_REG; 1549*e8996ee0Sbellard ts->reg = reg; 1550*e8996ee0Sbellard ts->mem_coherent = 0; 1551*e8996ee0Sbellard s->reg_to_temp[reg] = arg; 1552c896fe29Sbellard } 1553c896fe29Sbellard } 1554c896fe29Sbellard assert(ts->val_type == TEMP_VAL_REG); 15555ff9d6a4Sbellard if (arg_ct->ct & TCG_CT_IALIAS) { 15565ff9d6a4Sbellard if (ts->fixed_reg) { 15575ff9d6a4Sbellard /* if fixed register, we must allocate a new register 15585ff9d6a4Sbellard if the alias is not the same register */ 15595ff9d6a4Sbellard if (arg != args[arg_ct->alias_index]) 15605ff9d6a4Sbellard goto allocate_in_reg; 15615ff9d6a4Sbellard } else { 1562c896fe29Sbellard /* if the input is aliased to an output and if it is 1563c896fe29Sbellard not dead after the instruction, we must allocate 1564c896fe29Sbellard a new register and move it */ 15655ff9d6a4Sbellard if (!IS_DEAD_IARG(i - nb_oargs)) 1566c896fe29Sbellard goto allocate_in_reg; 1567c896fe29Sbellard } 15685ff9d6a4Sbellard } 1569c896fe29Sbellard reg = ts->reg; 1570c896fe29Sbellard if (tcg_regset_test_reg(arg_ct->u.regs, reg)) { 1571c896fe29Sbellard /* nothing to do : the constraint is satisfied */ 1572c896fe29Sbellard } else { 1573c896fe29Sbellard allocate_in_reg: 1574c896fe29Sbellard /* allocate a new register matching the constraint 1575c896fe29Sbellard and move the temporary register into it */ 1576c896fe29Sbellard reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); 1577c896fe29Sbellard tcg_out_mov(s, reg, ts->reg); 1578c896fe29Sbellard } 1579c896fe29Sbellard new_args[i] = reg; 1580c896fe29Sbellard const_args[i] = 0; 1581c896fe29Sbellard tcg_regset_set_reg(allocated_regs, reg); 1582c896fe29Sbellard iarg_end: ; 1583c896fe29Sbellard } 1584c896fe29Sbellard 1585*e8996ee0Sbellard if (def->flags & TCG_OPF_BB_END) { 1586*e8996ee0Sbellard tcg_reg_alloc_bb_end(s, allocated_regs); 1587*e8996ee0Sbellard } else { 1588c896fe29Sbellard /* mark dead temporaries and free the associated registers */ 1589c896fe29Sbellard for(i = 0; i < nb_iargs; i++) { 1590c896fe29Sbellard arg = args[nb_oargs + i]; 1591c896fe29Sbellard if (IS_DEAD_IARG(i)) { 1592c896fe29Sbellard ts = &s->temps[arg]; 1593*e8996ee0Sbellard if (!ts->fixed_reg) { 1594c896fe29Sbellard if (ts->val_type == TEMP_VAL_REG) 1595c896fe29Sbellard s->reg_to_temp[ts->reg] = -1; 1596c896fe29Sbellard ts->val_type = TEMP_VAL_DEAD; 1597c896fe29Sbellard } 1598c896fe29Sbellard } 1599c896fe29Sbellard } 1600c896fe29Sbellard 1601c896fe29Sbellard if (def->flags & TCG_OPF_CALL_CLOBBER) { 1602b03cce8eSbellard /* XXX: permit generic clobber register list ? */ 1603c896fe29Sbellard for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) { 1604c896fe29Sbellard if (tcg_regset_test_reg(tcg_target_call_clobber_regs, reg)) { 1605c896fe29Sbellard tcg_reg_free(s, reg); 1606c896fe29Sbellard } 1607c896fe29Sbellard } 1608b03cce8eSbellard /* XXX: for load/store we could do that only for the slow path 1609b03cce8eSbellard (i.e. when a memory callback is called) */ 1610b03cce8eSbellard 1611b03cce8eSbellard /* store globals and free associated registers (we assume the insn 1612b03cce8eSbellard can modify any global. */ 1613*e8996ee0Sbellard save_globals(s, allocated_regs); 1614c896fe29Sbellard } 1615c896fe29Sbellard 1616c896fe29Sbellard /* satisfy the output constraints */ 1617c896fe29Sbellard tcg_regset_set(allocated_regs, s->reserved_regs); 1618c896fe29Sbellard for(k = 0; k < nb_oargs; k++) { 1619c896fe29Sbellard i = def->sorted_args[k]; 1620c896fe29Sbellard arg = args[i]; 1621c896fe29Sbellard arg_ct = &def->args_ct[i]; 1622c896fe29Sbellard ts = &s->temps[arg]; 1623c896fe29Sbellard if (arg_ct->ct & TCG_CT_ALIAS) { 16245ff9d6a4Sbellard reg = new_args[arg_ct->alias_index]; 1625c896fe29Sbellard } else { 1626c896fe29Sbellard /* if fixed register, we try to use it */ 1627c896fe29Sbellard reg = ts->reg; 1628c896fe29Sbellard if (ts->fixed_reg && 1629c896fe29Sbellard tcg_regset_test_reg(arg_ct->u.regs, reg)) { 1630c896fe29Sbellard goto oarg_end; 1631c896fe29Sbellard } 1632c896fe29Sbellard reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); 1633c896fe29Sbellard } 1634c896fe29Sbellard tcg_regset_set_reg(allocated_regs, reg); 1635c896fe29Sbellard /* if a fixed register is used, then a move will be done afterwards */ 1636c896fe29Sbellard if (!ts->fixed_reg) { 1637c896fe29Sbellard if (ts->val_type == TEMP_VAL_REG) 1638c896fe29Sbellard s->reg_to_temp[ts->reg] = -1; 1639c896fe29Sbellard ts->val_type = TEMP_VAL_REG; 1640c896fe29Sbellard ts->reg = reg; 1641c896fe29Sbellard /* temp value is modified, so the value kept in memory is 1642c896fe29Sbellard potentially not the same */ 1643c896fe29Sbellard ts->mem_coherent = 0; 1644c896fe29Sbellard s->reg_to_temp[reg] = arg; 1645c896fe29Sbellard } 1646c896fe29Sbellard oarg_end: 1647c896fe29Sbellard new_args[i] = reg; 1648c896fe29Sbellard } 1649*e8996ee0Sbellard } 1650c896fe29Sbellard 1651c896fe29Sbellard /* emit instruction */ 1652c896fe29Sbellard tcg_out_op(s, opc, new_args, const_args); 1653c896fe29Sbellard 1654c896fe29Sbellard /* move the outputs in the correct register if needed */ 1655c896fe29Sbellard for(i = 0; i < nb_oargs; i++) { 1656c896fe29Sbellard ts = &s->temps[args[i]]; 1657c896fe29Sbellard reg = new_args[i]; 1658c896fe29Sbellard if (ts->fixed_reg && ts->reg != reg) { 1659c896fe29Sbellard tcg_out_mov(s, ts->reg, reg); 1660c896fe29Sbellard } 1661c896fe29Sbellard } 1662c896fe29Sbellard } 1663c896fe29Sbellard 1664b03cce8eSbellard #ifdef TCG_TARGET_STACK_GROWSUP 1665b03cce8eSbellard #define STACK_DIR(x) (-(x)) 1666b03cce8eSbellard #else 1667b03cce8eSbellard #define STACK_DIR(x) (x) 1668b03cce8eSbellard #endif 1669b03cce8eSbellard 1670c896fe29Sbellard static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def, 1671c896fe29Sbellard int opc, const TCGArg *args, 1672c896fe29Sbellard unsigned int dead_iargs) 1673c896fe29Sbellard { 1674c896fe29Sbellard int nb_iargs, nb_oargs, flags, nb_regs, i, reg, nb_params; 1675c896fe29Sbellard TCGArg arg, func_arg; 1676c896fe29Sbellard TCGTemp *ts; 1677f54b3f92Saurel32 tcg_target_long stack_offset, call_stack_size, func_addr; 1678b03cce8eSbellard int const_func_arg, allocate_args; 1679c896fe29Sbellard TCGRegSet allocated_regs; 1680c896fe29Sbellard const TCGArgConstraint *arg_ct; 1681c896fe29Sbellard 1682c896fe29Sbellard arg = *args++; 1683c896fe29Sbellard 1684c896fe29Sbellard nb_oargs = arg >> 16; 1685c896fe29Sbellard nb_iargs = arg & 0xffff; 1686c896fe29Sbellard nb_params = nb_iargs - 1; 1687c896fe29Sbellard 1688c896fe29Sbellard flags = args[nb_oargs + nb_iargs]; 1689c896fe29Sbellard 1690c896fe29Sbellard nb_regs = tcg_target_get_call_iarg_regs_count(flags); 1691c896fe29Sbellard if (nb_regs > nb_params) 1692c896fe29Sbellard nb_regs = nb_params; 1693c896fe29Sbellard 1694c896fe29Sbellard /* assign stack slots first */ 1695c896fe29Sbellard /* XXX: preallocate call stack */ 1696c896fe29Sbellard call_stack_size = (nb_params - nb_regs) * sizeof(tcg_target_long); 1697c896fe29Sbellard call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) & 1698c896fe29Sbellard ~(TCG_TARGET_STACK_ALIGN - 1); 1699b03cce8eSbellard allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE); 1700b03cce8eSbellard if (allocate_args) { 1701b03cce8eSbellard tcg_out_addi(s, TCG_REG_CALL_STACK, -STACK_DIR(call_stack_size)); 1702b03cce8eSbellard } 170339cf05d3Sbellard 170439cf05d3Sbellard stack_offset = TCG_TARGET_CALL_STACK_OFFSET; 1705c896fe29Sbellard for(i = nb_regs; i < nb_params; i++) { 1706c896fe29Sbellard arg = args[nb_oargs + i]; 170739cf05d3Sbellard #ifdef TCG_TARGET_STACK_GROWSUP 170839cf05d3Sbellard stack_offset -= sizeof(tcg_target_long); 170939cf05d3Sbellard #endif 171039cf05d3Sbellard if (arg != TCG_CALL_DUMMY_ARG) { 1711c896fe29Sbellard ts = &s->temps[arg]; 1712c896fe29Sbellard if (ts->val_type == TEMP_VAL_REG) { 1713e4d5434cSblueswir1 tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, stack_offset); 1714c896fe29Sbellard } else if (ts->val_type == TEMP_VAL_MEM) { 1715c896fe29Sbellard reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type], 1716c896fe29Sbellard s->reserved_regs); 1717c896fe29Sbellard /* XXX: not correct if reading values from the stack */ 1718e4d5434cSblueswir1 tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset); 1719e4d5434cSblueswir1 tcg_out_st(s, ts->type, reg, TCG_REG_CALL_STACK, stack_offset); 1720c896fe29Sbellard } else if (ts->val_type == TEMP_VAL_CONST) { 1721c896fe29Sbellard reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type], 1722c896fe29Sbellard s->reserved_regs); 1723c896fe29Sbellard /* XXX: sign extend may be needed on some targets */ 1724c896fe29Sbellard tcg_out_movi(s, ts->type, reg, ts->val); 1725e4d5434cSblueswir1 tcg_out_st(s, ts->type, reg, TCG_REG_CALL_STACK, stack_offset); 1726c896fe29Sbellard } else { 1727c896fe29Sbellard tcg_abort(); 1728c896fe29Sbellard } 172939cf05d3Sbellard } 173039cf05d3Sbellard #ifndef TCG_TARGET_STACK_GROWSUP 173139cf05d3Sbellard stack_offset += sizeof(tcg_target_long); 173239cf05d3Sbellard #endif 1733c896fe29Sbellard } 1734c896fe29Sbellard 1735c896fe29Sbellard /* assign input registers */ 1736c896fe29Sbellard tcg_regset_set(allocated_regs, s->reserved_regs); 1737c896fe29Sbellard for(i = 0; i < nb_regs; i++) { 1738c896fe29Sbellard arg = args[nb_oargs + i]; 173939cf05d3Sbellard if (arg != TCG_CALL_DUMMY_ARG) { 1740c896fe29Sbellard ts = &s->temps[arg]; 1741c896fe29Sbellard reg = tcg_target_call_iarg_regs[i]; 1742c896fe29Sbellard tcg_reg_free(s, reg); 1743c896fe29Sbellard if (ts->val_type == TEMP_VAL_REG) { 1744c896fe29Sbellard if (ts->reg != reg) { 1745c896fe29Sbellard tcg_out_mov(s, reg, ts->reg); 1746c896fe29Sbellard } 1747c896fe29Sbellard } else if (ts->val_type == TEMP_VAL_MEM) { 1748e4d5434cSblueswir1 tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset); 1749c896fe29Sbellard } else if (ts->val_type == TEMP_VAL_CONST) { 1750c896fe29Sbellard /* XXX: sign extend ? */ 1751c896fe29Sbellard tcg_out_movi(s, ts->type, reg, ts->val); 1752c896fe29Sbellard } else { 1753c896fe29Sbellard tcg_abort(); 1754c896fe29Sbellard } 1755c896fe29Sbellard tcg_regset_set_reg(allocated_regs, reg); 1756c896fe29Sbellard } 175739cf05d3Sbellard } 1758c896fe29Sbellard 1759c896fe29Sbellard /* assign function address */ 1760c896fe29Sbellard func_arg = args[nb_oargs + nb_iargs - 1]; 1761c896fe29Sbellard arg_ct = &def->args_ct[0]; 1762c896fe29Sbellard ts = &s->temps[func_arg]; 1763f54b3f92Saurel32 func_addr = ts->val; 1764c896fe29Sbellard const_func_arg = 0; 1765c896fe29Sbellard if (ts->val_type == TEMP_VAL_MEM) { 1766c896fe29Sbellard reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); 1767e4d5434cSblueswir1 tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset); 1768c896fe29Sbellard func_arg = reg; 1769*e8996ee0Sbellard tcg_regset_set_reg(allocated_regs, reg); 1770c896fe29Sbellard } else if (ts->val_type == TEMP_VAL_REG) { 1771c896fe29Sbellard reg = ts->reg; 1772c896fe29Sbellard if (!tcg_regset_test_reg(arg_ct->u.regs, reg)) { 1773c896fe29Sbellard reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); 1774c896fe29Sbellard tcg_out_mov(s, reg, ts->reg); 1775c896fe29Sbellard } 1776c896fe29Sbellard func_arg = reg; 1777*e8996ee0Sbellard tcg_regset_set_reg(allocated_regs, reg); 1778c896fe29Sbellard } else if (ts->val_type == TEMP_VAL_CONST) { 1779f54b3f92Saurel32 if (tcg_target_const_match(func_addr, arg_ct)) { 1780c896fe29Sbellard const_func_arg = 1; 1781f54b3f92Saurel32 func_arg = func_addr; 1782c896fe29Sbellard } else { 1783c896fe29Sbellard reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); 1784f54b3f92Saurel32 tcg_out_movi(s, ts->type, reg, func_addr); 1785c896fe29Sbellard func_arg = reg; 1786*e8996ee0Sbellard tcg_regset_set_reg(allocated_regs, reg); 1787c896fe29Sbellard } 1788c896fe29Sbellard } else { 1789c896fe29Sbellard tcg_abort(); 1790c896fe29Sbellard } 1791c896fe29Sbellard 1792*e8996ee0Sbellard 1793c896fe29Sbellard /* mark dead temporaries and free the associated registers */ 1794c6e113f5Sbellard for(i = 0; i < nb_iargs; i++) { 1795c896fe29Sbellard arg = args[nb_oargs + i]; 1796c896fe29Sbellard if (IS_DEAD_IARG(i)) { 1797c896fe29Sbellard ts = &s->temps[arg]; 1798*e8996ee0Sbellard if (!ts->fixed_reg) { 1799c896fe29Sbellard if (ts->val_type == TEMP_VAL_REG) 1800c896fe29Sbellard s->reg_to_temp[ts->reg] = -1; 1801c896fe29Sbellard ts->val_type = TEMP_VAL_DEAD; 1802c896fe29Sbellard } 1803c896fe29Sbellard } 1804c896fe29Sbellard } 1805c896fe29Sbellard 1806c896fe29Sbellard /* clobber call registers */ 1807c896fe29Sbellard for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) { 1808c896fe29Sbellard if (tcg_regset_test_reg(tcg_target_call_clobber_regs, reg)) { 1809c896fe29Sbellard tcg_reg_free(s, reg); 1810c896fe29Sbellard } 1811c896fe29Sbellard } 1812c896fe29Sbellard 1813c896fe29Sbellard /* store globals and free associated registers (we assume the call 1814c896fe29Sbellard can modify any global. */ 1815*e8996ee0Sbellard save_globals(s, allocated_regs); 1816c896fe29Sbellard 1817c896fe29Sbellard tcg_out_op(s, opc, &func_arg, &const_func_arg); 1818c896fe29Sbellard 1819b03cce8eSbellard if (allocate_args) { 1820b03cce8eSbellard tcg_out_addi(s, TCG_REG_CALL_STACK, STACK_DIR(call_stack_size)); 1821b03cce8eSbellard } 1822c896fe29Sbellard 1823c896fe29Sbellard /* assign output registers and emit moves if needed */ 1824c896fe29Sbellard for(i = 0; i < nb_oargs; i++) { 1825c896fe29Sbellard arg = args[i]; 1826c896fe29Sbellard ts = &s->temps[arg]; 1827c896fe29Sbellard reg = tcg_target_call_oarg_regs[i]; 1828*e8996ee0Sbellard assert(s->reg_to_temp[reg] == -1); 1829c896fe29Sbellard if (ts->fixed_reg) { 1830c896fe29Sbellard if (ts->reg != reg) { 1831c896fe29Sbellard tcg_out_mov(s, ts->reg, reg); 1832c896fe29Sbellard } 1833c896fe29Sbellard } else { 1834c896fe29Sbellard if (ts->val_type == TEMP_VAL_REG) 1835c896fe29Sbellard s->reg_to_temp[ts->reg] = -1; 1836c896fe29Sbellard ts->val_type = TEMP_VAL_REG; 1837c896fe29Sbellard ts->reg = reg; 1838c896fe29Sbellard ts->mem_coherent = 0; 1839c896fe29Sbellard s->reg_to_temp[reg] = arg; 1840c896fe29Sbellard } 1841c896fe29Sbellard } 1842c896fe29Sbellard 1843c896fe29Sbellard return nb_iargs + nb_oargs + def->nb_cargs + 1; 1844c896fe29Sbellard } 1845c896fe29Sbellard 1846c896fe29Sbellard #ifdef CONFIG_PROFILER 1847c896fe29Sbellard 1848c896fe29Sbellard static int64_t dyngen_table_op_count[NB_OPS]; 1849c896fe29Sbellard 1850c896fe29Sbellard void dump_op_count(void) 1851c896fe29Sbellard { 1852c896fe29Sbellard int i; 1853c896fe29Sbellard FILE *f; 1854c896fe29Sbellard f = fopen("/tmp/op1.log", "w"); 1855c896fe29Sbellard for(i = 0; i < INDEX_op_end; i++) { 1856c896fe29Sbellard fprintf(f, "%s %" PRId64 "\n", tcg_op_defs[i].name, dyngen_table_op_count[i]); 1857c896fe29Sbellard } 1858c896fe29Sbellard fclose(f); 1859c896fe29Sbellard f = fopen("/tmp/op2.log", "w"); 1860c896fe29Sbellard for(i = INDEX_op_end; i < NB_OPS; i++) { 1861c896fe29Sbellard fprintf(f, "%s %" PRId64 "\n", tcg_op_defs[i].name, dyngen_table_op_count[i]); 1862c896fe29Sbellard } 1863c896fe29Sbellard fclose(f); 1864c896fe29Sbellard } 1865c896fe29Sbellard #endif 1866c896fe29Sbellard 1867c896fe29Sbellard 1868c896fe29Sbellard static inline int tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf, 18692ba1eeb6Spbrook long search_pc) 1870c896fe29Sbellard { 1871c896fe29Sbellard int opc, op_index, macro_op_index; 1872c896fe29Sbellard const TCGOpDef *def; 1873c896fe29Sbellard unsigned int dead_iargs; 1874c896fe29Sbellard const TCGArg *args; 1875c896fe29Sbellard 1876c896fe29Sbellard #ifdef DEBUG_DISAS 1877c896fe29Sbellard if (unlikely(loglevel & CPU_LOG_TB_OP)) { 1878c896fe29Sbellard fprintf(logfile, "OP:\n"); 1879c896fe29Sbellard tcg_dump_ops(s, logfile); 1880c896fe29Sbellard fprintf(logfile, "\n"); 1881c896fe29Sbellard } 1882c896fe29Sbellard #endif 1883c896fe29Sbellard 1884a23a9ec6Sbellard #ifdef CONFIG_PROFILER 1885a23a9ec6Sbellard s->la_time -= profile_getclock(); 1886a23a9ec6Sbellard #endif 1887c896fe29Sbellard tcg_liveness_analysis(s); 1888a23a9ec6Sbellard #ifdef CONFIG_PROFILER 1889a23a9ec6Sbellard s->la_time += profile_getclock(); 1890a23a9ec6Sbellard #endif 1891c896fe29Sbellard 1892c896fe29Sbellard #ifdef DEBUG_DISAS 1893c896fe29Sbellard if (unlikely(loglevel & CPU_LOG_TB_OP_OPT)) { 1894c896fe29Sbellard fprintf(logfile, "OP after la:\n"); 1895c896fe29Sbellard tcg_dump_ops(s, logfile); 1896c896fe29Sbellard fprintf(logfile, "\n"); 1897c896fe29Sbellard } 1898c896fe29Sbellard #endif 1899c896fe29Sbellard 1900c896fe29Sbellard tcg_reg_alloc_start(s); 1901c896fe29Sbellard 1902c896fe29Sbellard s->code_buf = gen_code_buf; 1903c896fe29Sbellard s->code_ptr = gen_code_buf; 1904c896fe29Sbellard 1905c896fe29Sbellard macro_op_index = -1; 1906c896fe29Sbellard args = gen_opparam_buf; 1907c896fe29Sbellard op_index = 0; 1908b3db8758Sblueswir1 1909c896fe29Sbellard for(;;) { 1910c896fe29Sbellard opc = gen_opc_buf[op_index]; 1911c896fe29Sbellard #ifdef CONFIG_PROFILER 1912c896fe29Sbellard dyngen_table_op_count[opc]++; 1913c896fe29Sbellard #endif 1914c896fe29Sbellard def = &tcg_op_defs[opc]; 1915c896fe29Sbellard #if 0 1916c896fe29Sbellard printf("%s: %d %d %d\n", def->name, 1917c896fe29Sbellard def->nb_oargs, def->nb_iargs, def->nb_cargs); 1918c896fe29Sbellard // dump_regs(s); 1919c896fe29Sbellard #endif 1920c896fe29Sbellard switch(opc) { 1921c896fe29Sbellard case INDEX_op_mov_i32: 1922c896fe29Sbellard #if TCG_TARGET_REG_BITS == 64 1923c896fe29Sbellard case INDEX_op_mov_i64: 1924c896fe29Sbellard #endif 1925c896fe29Sbellard dead_iargs = s->op_dead_iargs[op_index]; 1926c896fe29Sbellard tcg_reg_alloc_mov(s, def, args, dead_iargs); 1927c896fe29Sbellard break; 1928*e8996ee0Sbellard case INDEX_op_movi_i32: 1929*e8996ee0Sbellard #if TCG_TARGET_REG_BITS == 64 1930*e8996ee0Sbellard case INDEX_op_movi_i64: 1931*e8996ee0Sbellard #endif 1932*e8996ee0Sbellard tcg_reg_alloc_movi(s, args); 1933*e8996ee0Sbellard break; 19347e4597d7Sbellard case INDEX_op_debug_insn_start: 19357e4597d7Sbellard /* debug instruction */ 19367e4597d7Sbellard break; 1937c896fe29Sbellard case INDEX_op_nop: 1938c896fe29Sbellard case INDEX_op_nop1: 1939c896fe29Sbellard case INDEX_op_nop2: 1940c896fe29Sbellard case INDEX_op_nop3: 1941c896fe29Sbellard break; 1942c896fe29Sbellard case INDEX_op_nopn: 1943c896fe29Sbellard args += args[0]; 1944c896fe29Sbellard goto next; 19455ff9d6a4Sbellard case INDEX_op_discard: 19465ff9d6a4Sbellard { 19475ff9d6a4Sbellard TCGTemp *ts; 19485ff9d6a4Sbellard ts = &s->temps[args[0]]; 19495ff9d6a4Sbellard /* mark the temporary as dead */ 1950*e8996ee0Sbellard if (!ts->fixed_reg) { 19515ff9d6a4Sbellard if (ts->val_type == TEMP_VAL_REG) 19525ff9d6a4Sbellard s->reg_to_temp[ts->reg] = -1; 19535ff9d6a4Sbellard ts->val_type = TEMP_VAL_DEAD; 19545ff9d6a4Sbellard } 19555ff9d6a4Sbellard } 19565ff9d6a4Sbellard break; 1957c896fe29Sbellard case INDEX_op_macro_goto: 1958c896fe29Sbellard macro_op_index = op_index; /* only used for exceptions */ 1959c896fe29Sbellard op_index = args[0] - 1; 1960c896fe29Sbellard args = gen_opparam_buf + args[1]; 1961c896fe29Sbellard goto next; 1962c896fe29Sbellard case INDEX_op_macro_end: 1963c896fe29Sbellard macro_op_index = -1; /* only used for exceptions */ 1964c896fe29Sbellard op_index = args[0] - 1; 1965c896fe29Sbellard args = gen_opparam_buf + args[1]; 1966c896fe29Sbellard goto next; 1967c896fe29Sbellard case INDEX_op_macro_start: 1968c896fe29Sbellard /* must never happen here */ 1969c896fe29Sbellard tcg_abort(); 1970c896fe29Sbellard case INDEX_op_set_label: 1971*e8996ee0Sbellard tcg_reg_alloc_bb_end(s, s->reserved_regs); 1972c896fe29Sbellard tcg_out_label(s, args[0], (long)s->code_ptr); 1973c896fe29Sbellard break; 1974c896fe29Sbellard case INDEX_op_call: 1975c896fe29Sbellard dead_iargs = s->op_dead_iargs[op_index]; 1976c896fe29Sbellard args += tcg_reg_alloc_call(s, def, opc, args, dead_iargs); 1977c896fe29Sbellard goto next; 1978c896fe29Sbellard case INDEX_op_end: 1979c896fe29Sbellard goto the_end; 1980cf2be984Sblueswir1 1981bf6247fbSblueswir1 #ifdef CONFIG_DYNGEN_OP 1982c896fe29Sbellard case 0 ... INDEX_op_end - 1: 1983c896fe29Sbellard /* legacy dyngen ops */ 1984c896fe29Sbellard #ifdef CONFIG_PROFILER 1985a23a9ec6Sbellard s->old_op_count++; 1986c896fe29Sbellard #endif 1987*e8996ee0Sbellard tcg_reg_alloc_bb_end(s, s->reserved_regs); 19882ba1eeb6Spbrook if (search_pc >= 0) { 1989c896fe29Sbellard s->code_ptr += def->copy_size; 1990c896fe29Sbellard args += def->nb_args; 1991c896fe29Sbellard } else { 1992c896fe29Sbellard args = dyngen_op(s, opc, args); 1993c896fe29Sbellard } 1994c896fe29Sbellard goto next; 1995cf2be984Sblueswir1 #endif 1996c896fe29Sbellard default: 1997c896fe29Sbellard /* Note: in order to speed up the code, it would be much 1998c896fe29Sbellard faster to have specialized register allocator functions for 1999c896fe29Sbellard some common argument patterns */ 2000c896fe29Sbellard dead_iargs = s->op_dead_iargs[op_index]; 2001c896fe29Sbellard tcg_reg_alloc_op(s, def, opc, args, dead_iargs); 2002c896fe29Sbellard break; 2003c896fe29Sbellard } 2004c896fe29Sbellard args += def->nb_args; 2005c896fe29Sbellard next: ; 20062ba1eeb6Spbrook if (search_pc >= 0 && search_pc < s->code_ptr - gen_code_buf) { 2007c896fe29Sbellard if (macro_op_index >= 0) 2008c896fe29Sbellard return macro_op_index; 2009c896fe29Sbellard else 2010c896fe29Sbellard return op_index; 2011c896fe29Sbellard } 2012c896fe29Sbellard op_index++; 2013c896fe29Sbellard #ifndef NDEBUG 2014c896fe29Sbellard check_regs(s); 2015c896fe29Sbellard #endif 2016c896fe29Sbellard } 2017c896fe29Sbellard the_end: 2018c896fe29Sbellard return -1; 2019c896fe29Sbellard } 2020c896fe29Sbellard 2021c896fe29Sbellard int dyngen_code(TCGContext *s, uint8_t *gen_code_buf) 2022c896fe29Sbellard { 2023c896fe29Sbellard #ifdef CONFIG_PROFILER 2024c896fe29Sbellard { 2025c896fe29Sbellard int n; 2026c896fe29Sbellard n = (gen_opc_ptr - gen_opc_buf); 2027a23a9ec6Sbellard s->op_count += n; 2028a23a9ec6Sbellard if (n > s->op_count_max) 2029a23a9ec6Sbellard s->op_count_max = n; 2030a23a9ec6Sbellard 2031a23a9ec6Sbellard s->temp_count += s->nb_temps; 2032a23a9ec6Sbellard if (s->nb_temps > s->temp_count_max) 2033a23a9ec6Sbellard s->temp_count_max = s->nb_temps; 2034c896fe29Sbellard } 2035c896fe29Sbellard #endif 2036c896fe29Sbellard 20372ba1eeb6Spbrook tcg_gen_code_common(s, gen_code_buf, -1); 2038c896fe29Sbellard 2039c896fe29Sbellard /* flush instruction cache */ 2040c896fe29Sbellard flush_icache_range((unsigned long)gen_code_buf, 2041c896fe29Sbellard (unsigned long)s->code_ptr); 2042c896fe29Sbellard return s->code_ptr - gen_code_buf; 2043c896fe29Sbellard } 2044c896fe29Sbellard 20452ba1eeb6Spbrook /* Return the index of the micro operation such as the pc after is < 2046623e265cSpbrook offset bytes from the start of the TB. The contents of gen_code_buf must 2047623e265cSpbrook not be changed, though writing the same values is ok. 2048623e265cSpbrook Return -1 if not found. */ 2049623e265cSpbrook int dyngen_code_search_pc(TCGContext *s, uint8_t *gen_code_buf, long offset) 2050c896fe29Sbellard { 2051623e265cSpbrook return tcg_gen_code_common(s, gen_code_buf, offset); 2052c896fe29Sbellard } 2053a23a9ec6Sbellard 2054a23a9ec6Sbellard #ifdef CONFIG_PROFILER 2055a23a9ec6Sbellard void tcg_dump_info(FILE *f, 2056a23a9ec6Sbellard int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) 2057a23a9ec6Sbellard { 2058a23a9ec6Sbellard TCGContext *s = &tcg_ctx; 2059a23a9ec6Sbellard int64_t tot; 2060a23a9ec6Sbellard 2061a23a9ec6Sbellard tot = s->interm_time + s->code_time; 2062a23a9ec6Sbellard cpu_fprintf(f, "JIT cycles %" PRId64 " (%0.3f s at 2.4 GHz)\n", 2063a23a9ec6Sbellard tot, tot / 2.4e9); 2064a23a9ec6Sbellard cpu_fprintf(f, "translated TBs %" PRId64 " (aborted=%" PRId64 " %0.1f%%)\n", 2065a23a9ec6Sbellard s->tb_count, 2066a23a9ec6Sbellard s->tb_count1 - s->tb_count, 2067a23a9ec6Sbellard s->tb_count1 ? (double)(s->tb_count1 - s->tb_count) / s->tb_count1 * 100.0 : 0); 2068a23a9ec6Sbellard cpu_fprintf(f, "avg ops/TB %0.1f max=%d\n", 2069a23a9ec6Sbellard s->tb_count ? (double)s->op_count / s->tb_count : 0, s->op_count_max); 2070a23a9ec6Sbellard cpu_fprintf(f, "old ops/total ops %0.1f%%\n", 2071a23a9ec6Sbellard s->op_count ? (double)s->old_op_count / s->op_count * 100.0 : 0); 2072a23a9ec6Sbellard cpu_fprintf(f, "deleted ops/TB %0.2f\n", 2073a23a9ec6Sbellard s->tb_count ? 2074a23a9ec6Sbellard (double)s->del_op_count / s->tb_count : 0); 2075a23a9ec6Sbellard cpu_fprintf(f, "avg temps/TB %0.2f max=%d\n", 2076a23a9ec6Sbellard s->tb_count ? 2077a23a9ec6Sbellard (double)s->temp_count / s->tb_count : 0, 2078a23a9ec6Sbellard s->temp_count_max); 2079a23a9ec6Sbellard 2080a23a9ec6Sbellard cpu_fprintf(f, "cycles/op %0.1f\n", 2081a23a9ec6Sbellard s->op_count ? (double)tot / s->op_count : 0); 2082a23a9ec6Sbellard cpu_fprintf(f, "cycles/in byte %0.1f\n", 2083a23a9ec6Sbellard s->code_in_len ? (double)tot / s->code_in_len : 0); 2084a23a9ec6Sbellard cpu_fprintf(f, "cycles/out byte %0.1f\n", 2085a23a9ec6Sbellard s->code_out_len ? (double)tot / s->code_out_len : 0); 2086a23a9ec6Sbellard if (tot == 0) 2087a23a9ec6Sbellard tot = 1; 2088a23a9ec6Sbellard cpu_fprintf(f, " gen_interm time %0.1f%%\n", 2089a23a9ec6Sbellard (double)s->interm_time / tot * 100.0); 2090a23a9ec6Sbellard cpu_fprintf(f, " gen_code time %0.1f%%\n", 2091a23a9ec6Sbellard (double)s->code_time / tot * 100.0); 2092a23a9ec6Sbellard cpu_fprintf(f, "liveness/code time %0.1f%%\n", 2093a23a9ec6Sbellard (double)s->la_time / (s->code_time ? s->code_time : 1) * 100.0); 2094a23a9ec6Sbellard cpu_fprintf(f, "cpu_restore count %" PRId64 "\n", 2095a23a9ec6Sbellard s->restore_count); 2096a23a9ec6Sbellard cpu_fprintf(f, " avg cycles %0.1f\n", 2097a23a9ec6Sbellard s->restore_count ? (double)s->restore_time / s->restore_count : 0); 2098a23a9ec6Sbellard { 2099a23a9ec6Sbellard extern void dump_op_count(void); 2100a23a9ec6Sbellard dump_op_count(); 2101a23a9ec6Sbellard } 2102a23a9ec6Sbellard } 2103a23a9ec6Sbellard #else 210424bf7b3aSbellard void tcg_dump_info(FILE *f, 2105a23a9ec6Sbellard int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) 2106a23a9ec6Sbellard { 210724bf7b3aSbellard cpu_fprintf(f, "[TCG profiler not compiled]\n"); 2108a23a9ec6Sbellard } 2109a23a9ec6Sbellard #endif 2110