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 { 269e8996ee0Sbellard int i; 270c896fe29Sbellard tcg_pool_reset(s); 271c896fe29Sbellard s->nb_temps = s->nb_globals; 272*641d5fbeSbellard for(i = 0; i < (TCG_TYPE_COUNT * 2); i++) 273e8996ee0Sbellard 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 410*641d5fbeSbellard TCGv tcg_temp_new_internal(TCGType type, int temp_local) 411c896fe29Sbellard { 412c896fe29Sbellard TCGContext *s = &tcg_ctx; 413c896fe29Sbellard TCGTemp *ts; 414*641d5fbeSbellard int idx, k; 415c896fe29Sbellard 416*641d5fbeSbellard k = type; 417*641d5fbeSbellard if (temp_local) 418*641d5fbeSbellard k += TCG_TYPE_COUNT; 419*641d5fbeSbellard idx = s->first_free_temp[k]; 420e8996ee0Sbellard if (idx != -1) { 421e8996ee0Sbellard /* There is already an available temp with the 422e8996ee0Sbellard right type */ 423e8996ee0Sbellard ts = &s->temps[idx]; 424*641d5fbeSbellard s->first_free_temp[k] = ts->next_free_temp; 425e8996ee0Sbellard ts->temp_allocated = 1; 426*641d5fbeSbellard assert(ts->temp_local == temp_local); 427e8996ee0Sbellard } else { 428c896fe29Sbellard idx = s->nb_temps; 429c896fe29Sbellard #if TCG_TARGET_REG_BITS == 32 430c896fe29Sbellard if (type == TCG_TYPE_I64) { 431c896fe29Sbellard tcg_temp_alloc(s, s->nb_temps + 1); 432c896fe29Sbellard ts = &s->temps[s->nb_temps]; 433c896fe29Sbellard ts->base_type = type; 434c896fe29Sbellard ts->type = TCG_TYPE_I32; 435e8996ee0Sbellard ts->temp_allocated = 1; 436*641d5fbeSbellard ts->temp_local = temp_local; 437c896fe29Sbellard ts->name = NULL; 438c896fe29Sbellard ts++; 439c896fe29Sbellard ts->base_type = TCG_TYPE_I32; 440c896fe29Sbellard ts->type = TCG_TYPE_I32; 441e8996ee0Sbellard ts->temp_allocated = 1; 442*641d5fbeSbellard ts->temp_local = temp_local; 443c896fe29Sbellard ts->name = NULL; 444c896fe29Sbellard s->nb_temps += 2; 445c896fe29Sbellard } else 446c896fe29Sbellard #endif 447c896fe29Sbellard { 448c896fe29Sbellard tcg_temp_alloc(s, s->nb_temps + 1); 449c896fe29Sbellard ts = &s->temps[s->nb_temps]; 450c896fe29Sbellard ts->base_type = type; 451c896fe29Sbellard ts->type = type; 452e8996ee0Sbellard ts->temp_allocated = 1; 453*641d5fbeSbellard ts->temp_local = temp_local; 454c896fe29Sbellard ts->name = NULL; 455c896fe29Sbellard s->nb_temps++; 456c896fe29Sbellard } 457e8996ee0Sbellard } 458ac56dd48Spbrook return MAKE_TCGV(idx); 459c896fe29Sbellard } 460c896fe29Sbellard 461e8996ee0Sbellard void tcg_temp_free(TCGv arg) 462c896fe29Sbellard { 463c896fe29Sbellard TCGContext *s = &tcg_ctx; 464c896fe29Sbellard TCGTemp *ts; 465e8996ee0Sbellard int idx = GET_TCGV(arg); 466*641d5fbeSbellard int k; 467c896fe29Sbellard 468e8996ee0Sbellard assert(idx >= s->nb_globals && idx < s->nb_temps); 469c896fe29Sbellard ts = &s->temps[idx]; 470e8996ee0Sbellard assert(ts->temp_allocated != 0); 471e8996ee0Sbellard ts->temp_allocated = 0; 472*641d5fbeSbellard k = ts->base_type; 473*641d5fbeSbellard if (ts->temp_local) 474*641d5fbeSbellard k += TCG_TYPE_COUNT; 475*641d5fbeSbellard ts->next_free_temp = s->first_free_temp[k]; 476*641d5fbeSbellard s->first_free_temp[k] = idx; 477e8996ee0Sbellard } 478e8996ee0Sbellard 479e8996ee0Sbellard 480e8996ee0Sbellard TCGv tcg_const_i32(int32_t val) 481e8996ee0Sbellard { 482e8996ee0Sbellard TCGv t0; 483e8996ee0Sbellard t0 = tcg_temp_new(TCG_TYPE_I32); 484e8996ee0Sbellard tcg_gen_movi_i32(t0, val); 485e8996ee0Sbellard return t0; 486c896fe29Sbellard } 487c896fe29Sbellard 488ac56dd48Spbrook TCGv tcg_const_i64(int64_t val) 489c896fe29Sbellard { 490e8996ee0Sbellard TCGv t0; 491e8996ee0Sbellard t0 = tcg_temp_new(TCG_TYPE_I64); 492e8996ee0Sbellard tcg_gen_movi_i64(t0, val); 493e8996ee0Sbellard return t0; 494c896fe29Sbellard } 495c896fe29Sbellard 496c896fe29Sbellard void tcg_register_helper(void *func, const char *name) 497c896fe29Sbellard { 498c896fe29Sbellard TCGContext *s = &tcg_ctx; 499c896fe29Sbellard int n; 500c896fe29Sbellard if ((s->nb_helpers + 1) > s->allocated_helpers) { 501c896fe29Sbellard n = s->allocated_helpers; 502c896fe29Sbellard if (n == 0) { 503c896fe29Sbellard n = 4; 504c896fe29Sbellard } else { 505c896fe29Sbellard n *= 2; 506c896fe29Sbellard } 507c896fe29Sbellard s->helpers = realloc(s->helpers, n * sizeof(TCGHelperInfo)); 508c896fe29Sbellard s->allocated_helpers = n; 509c896fe29Sbellard } 5104dc81f28Sbellard s->helpers[s->nb_helpers].func = (tcg_target_ulong)func; 511c896fe29Sbellard s->helpers[s->nb_helpers].name = name; 512c896fe29Sbellard s->nb_helpers++; 513c896fe29Sbellard } 514c896fe29Sbellard 515ac56dd48Spbrook static inline TCGType tcg_get_base_type(TCGContext *s, TCGv arg) 516c896fe29Sbellard { 517ac56dd48Spbrook return s->temps[GET_TCGV(arg)].base_type; 518c896fe29Sbellard } 519c896fe29Sbellard 520ac56dd48Spbrook static void tcg_gen_call_internal(TCGContext *s, TCGv func, 521c896fe29Sbellard unsigned int flags, 522ac56dd48Spbrook unsigned int nb_rets, const TCGv *rets, 523ac56dd48Spbrook unsigned int nb_params, const TCGv *params) 524c896fe29Sbellard { 525c896fe29Sbellard int i; 526c896fe29Sbellard *gen_opc_ptr++ = INDEX_op_call; 527c896fe29Sbellard *gen_opparam_ptr++ = (nb_rets << 16) | (nb_params + 1); 528c896fe29Sbellard for(i = 0; i < nb_rets; i++) { 529ac56dd48Spbrook *gen_opparam_ptr++ = GET_TCGV(rets[i]); 530c896fe29Sbellard } 531c896fe29Sbellard for(i = 0; i < nb_params; i++) { 532ac56dd48Spbrook *gen_opparam_ptr++ = GET_TCGV(params[i]); 533c896fe29Sbellard } 534ac56dd48Spbrook *gen_opparam_ptr++ = GET_TCGV(func); 535c896fe29Sbellard 536c896fe29Sbellard *gen_opparam_ptr++ = flags; 537c896fe29Sbellard /* total parameters, needed to go backward in the instruction stream */ 538c896fe29Sbellard *gen_opparam_ptr++ = 1 + nb_rets + nb_params + 3; 539c896fe29Sbellard } 540c896fe29Sbellard 541c896fe29Sbellard 542c896fe29Sbellard #if TCG_TARGET_REG_BITS < 64 54339cf05d3Sbellard /* Note: we convert the 64 bit args to 32 bit and do some alignment 54439cf05d3Sbellard and endian swap. Maybe it would be better to do the alignment 54539cf05d3Sbellard and endian swap in tcg_reg_alloc_call(). */ 546ac56dd48Spbrook void tcg_gen_call(TCGContext *s, TCGv func, unsigned int flags, 547ac56dd48Spbrook unsigned int nb_rets, const TCGv *rets, 548ac56dd48Spbrook unsigned int nb_params, const TCGv *args1) 549c896fe29Sbellard { 550ac56dd48Spbrook TCGv ret, *args2, rets_2[2], arg; 551c896fe29Sbellard int j, i, call_type; 552c896fe29Sbellard 553c896fe29Sbellard if (nb_rets == 1) { 554c896fe29Sbellard ret = rets[0]; 555c896fe29Sbellard if (tcg_get_base_type(s, ret) == TCG_TYPE_I64) { 556c896fe29Sbellard nb_rets = 2; 55739cf05d3Sbellard #ifdef TCG_TARGET_WORDS_BIGENDIAN 55839cf05d3Sbellard rets_2[0] = TCGV_HIGH(ret); 55939cf05d3Sbellard rets_2[1] = ret; 56039cf05d3Sbellard #else 561c896fe29Sbellard rets_2[0] = ret; 562ac56dd48Spbrook rets_2[1] = TCGV_HIGH(ret); 56339cf05d3Sbellard #endif 564c896fe29Sbellard rets = rets_2; 565c896fe29Sbellard } 566c896fe29Sbellard } 56739cf05d3Sbellard args2 = alloca((nb_params * 3) * sizeof(TCGv)); 568c896fe29Sbellard j = 0; 569c896fe29Sbellard call_type = (flags & TCG_CALL_TYPE_MASK); 570c896fe29Sbellard for(i = 0; i < nb_params; i++) { 571c896fe29Sbellard arg = args1[i]; 572c896fe29Sbellard if (tcg_get_base_type(s, arg) == TCG_TYPE_I64) { 573c896fe29Sbellard #ifdef TCG_TARGET_I386 574c896fe29Sbellard /* REGPARM case: if the third parameter is 64 bit, it is 575c896fe29Sbellard allocated on the stack */ 576c896fe29Sbellard if (j == 2 && call_type == TCG_CALL_TYPE_REGPARM) { 577c896fe29Sbellard call_type = TCG_CALL_TYPE_REGPARM_2; 578c896fe29Sbellard flags = (flags & ~TCG_CALL_TYPE_MASK) | call_type; 579c896fe29Sbellard } 580c896fe29Sbellard args2[j++] = arg; 581ac56dd48Spbrook args2[j++] = TCGV_HIGH(arg); 582c896fe29Sbellard #else 58339cf05d3Sbellard #ifdef TCG_TARGET_CALL_ALIGN_ARGS 58439cf05d3Sbellard /* some targets want aligned 64 bit args */ 58539cf05d3Sbellard if (j & 1) { 58639cf05d3Sbellard args2[j++] = TCG_CALL_DUMMY_ARG; 58739cf05d3Sbellard } 58839cf05d3Sbellard #endif 589c896fe29Sbellard #ifdef TCG_TARGET_WORDS_BIGENDIAN 590a0d69e00Sblueswir1 args2[j++] = TCGV_HIGH(arg); 591c896fe29Sbellard args2[j++] = arg; 592c896fe29Sbellard #else 593c896fe29Sbellard args2[j++] = arg; 594ac56dd48Spbrook args2[j++] = TCGV_HIGH(arg); 595c896fe29Sbellard #endif 596c896fe29Sbellard #endif 597c896fe29Sbellard } else { 598c896fe29Sbellard args2[j++] = arg; 599c896fe29Sbellard } 600c896fe29Sbellard } 601c896fe29Sbellard tcg_gen_call_internal(s, func, flags, 602c896fe29Sbellard nb_rets, rets, j, args2); 603c896fe29Sbellard } 604c896fe29Sbellard #else 605ac56dd48Spbrook void tcg_gen_call(TCGContext *s, TCGv func, unsigned int flags, 606ac56dd48Spbrook unsigned int nb_rets, const TCGv *rets, 607ac56dd48Spbrook unsigned int nb_params, const TCGv *args1) 608c896fe29Sbellard { 609c896fe29Sbellard tcg_gen_call_internal(s, func, flags, 610c896fe29Sbellard nb_rets, rets, nb_params, args1); 611c896fe29Sbellard } 612c896fe29Sbellard #endif 613c896fe29Sbellard 614ac56dd48Spbrook #if TCG_TARGET_REG_BITS == 32 615ac56dd48Spbrook void tcg_gen_shifti_i64(TCGv ret, TCGv arg1, 616c896fe29Sbellard int c, int right, int arith) 617c896fe29Sbellard { 618cf60bce4Sbellard if (c == 0) { 619cf60bce4Sbellard tcg_gen_mov_i32(ret, arg1); 620cf60bce4Sbellard tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1)); 621cf60bce4Sbellard } else if (c >= 32) { 622c896fe29Sbellard c -= 32; 623c896fe29Sbellard if (right) { 624c896fe29Sbellard if (arith) { 625ac56dd48Spbrook tcg_gen_sari_i32(ret, TCGV_HIGH(arg1), c); 626ac56dd48Spbrook tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), 31); 627c896fe29Sbellard } else { 628ac56dd48Spbrook tcg_gen_shri_i32(ret, TCGV_HIGH(arg1), c); 629ac56dd48Spbrook tcg_gen_movi_i32(TCGV_HIGH(ret), 0); 630c896fe29Sbellard } 631c896fe29Sbellard } else { 632ac56dd48Spbrook tcg_gen_shli_i32(TCGV_HIGH(ret), arg1, c); 633c896fe29Sbellard tcg_gen_movi_i32(ret, 0); 634c896fe29Sbellard } 635c896fe29Sbellard } else { 636ac56dd48Spbrook TCGv t0, t1; 637c896fe29Sbellard 638c896fe29Sbellard t0 = tcg_temp_new(TCG_TYPE_I32); 639c896fe29Sbellard t1 = tcg_temp_new(TCG_TYPE_I32); 640c896fe29Sbellard if (right) { 641ac56dd48Spbrook tcg_gen_shli_i32(t0, TCGV_HIGH(arg1), 32 - c); 642c896fe29Sbellard if (arith) 643ac56dd48Spbrook tcg_gen_sari_i32(t1, TCGV_HIGH(arg1), c); 644c896fe29Sbellard else 645ac56dd48Spbrook tcg_gen_shri_i32(t1, TCGV_HIGH(arg1), c); 646c896fe29Sbellard tcg_gen_shri_i32(ret, arg1, c); 647c896fe29Sbellard tcg_gen_or_i32(ret, ret, t0); 648ac56dd48Spbrook tcg_gen_mov_i32(TCGV_HIGH(ret), t1); 649c896fe29Sbellard } else { 650c896fe29Sbellard tcg_gen_shri_i32(t0, arg1, 32 - c); 651c896fe29Sbellard /* Note: ret can be the same as arg1, so we use t1 */ 652c896fe29Sbellard tcg_gen_shli_i32(t1, arg1, c); 653ac56dd48Spbrook tcg_gen_shli_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), c); 654ac56dd48Spbrook tcg_gen_or_i32(TCGV_HIGH(ret), TCGV_HIGH(ret), t0); 655c896fe29Sbellard tcg_gen_mov_i32(ret, t1); 656c896fe29Sbellard } 657e8996ee0Sbellard tcg_temp_free(t0); 658e8996ee0Sbellard tcg_temp_free(t1); 659c896fe29Sbellard } 660c896fe29Sbellard } 661ac56dd48Spbrook #endif 662c896fe29Sbellard 663c896fe29Sbellard void tcg_reg_alloc_start(TCGContext *s) 664c896fe29Sbellard { 665c896fe29Sbellard int i; 666c896fe29Sbellard TCGTemp *ts; 667c896fe29Sbellard for(i = 0; i < s->nb_globals; i++) { 668c896fe29Sbellard ts = &s->temps[i]; 669c896fe29Sbellard if (ts->fixed_reg) { 670c896fe29Sbellard ts->val_type = TEMP_VAL_REG; 671c896fe29Sbellard } else { 672c896fe29Sbellard ts->val_type = TEMP_VAL_MEM; 673c896fe29Sbellard } 674c896fe29Sbellard } 675e8996ee0Sbellard for(i = s->nb_globals; i < s->nb_temps; i++) { 676e8996ee0Sbellard ts = &s->temps[i]; 677e8996ee0Sbellard ts->val_type = TEMP_VAL_DEAD; 678e8996ee0Sbellard ts->mem_allocated = 0; 679e8996ee0Sbellard ts->fixed_reg = 0; 680e8996ee0Sbellard } 681c896fe29Sbellard for(i = 0; i < TCG_TARGET_NB_REGS; i++) { 682c896fe29Sbellard s->reg_to_temp[i] = -1; 683c896fe29Sbellard } 684c896fe29Sbellard } 685c896fe29Sbellard 686ac56dd48Spbrook static char *tcg_get_arg_str_idx(TCGContext *s, char *buf, int buf_size, 687ac56dd48Spbrook int idx) 688c896fe29Sbellard { 689c896fe29Sbellard TCGTemp *ts; 690ac56dd48Spbrook 691ac56dd48Spbrook ts = &s->temps[idx]; 692ac56dd48Spbrook if (idx < s->nb_globals) { 693ac56dd48Spbrook pstrcpy(buf, buf_size, ts->name); 694c896fe29Sbellard } else { 695*641d5fbeSbellard if (ts->temp_local) 696*641d5fbeSbellard snprintf(buf, buf_size, "loc%d", idx - s->nb_globals); 697*641d5fbeSbellard else 698ac56dd48Spbrook snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals); 699c896fe29Sbellard } 700c896fe29Sbellard return buf; 701c896fe29Sbellard } 702c896fe29Sbellard 703ac56dd48Spbrook char *tcg_get_arg_str(TCGContext *s, char *buf, int buf_size, TCGv arg) 704ac56dd48Spbrook { 705ac56dd48Spbrook return tcg_get_arg_str_idx(s, buf, buf_size, GET_TCGV(arg)); 706ac56dd48Spbrook } 707ac56dd48Spbrook 708e8996ee0Sbellard static int helper_cmp(const void *p1, const void *p2) 709e8996ee0Sbellard { 710e8996ee0Sbellard const TCGHelperInfo *th1 = p1; 711e8996ee0Sbellard const TCGHelperInfo *th2 = p2; 712e8996ee0Sbellard if (th1->func < th2->func) 713e8996ee0Sbellard return -1; 714e8996ee0Sbellard else if (th1->func == th2->func) 715e8996ee0Sbellard return 0; 716e8996ee0Sbellard else 717e8996ee0Sbellard return 1; 718e8996ee0Sbellard } 719e8996ee0Sbellard 720e8996ee0Sbellard /* find helper definition (Note: A hash table would be better) */ 7214dc81f28Sbellard static TCGHelperInfo *tcg_find_helper(TCGContext *s, tcg_target_ulong val) 7224dc81f28Sbellard { 723e8996ee0Sbellard int m, m_min, m_max; 724e8996ee0Sbellard TCGHelperInfo *th; 725e8996ee0Sbellard tcg_target_ulong v; 726e8996ee0Sbellard 727e8996ee0Sbellard if (unlikely(!s->helpers_sorted)) { 728e8996ee0Sbellard qsort(s->helpers, s->nb_helpers, sizeof(TCGHelperInfo), 729e8996ee0Sbellard helper_cmp); 730e8996ee0Sbellard s->helpers_sorted = 1; 731e8996ee0Sbellard } 732e8996ee0Sbellard 733e8996ee0Sbellard /* binary search */ 734e8996ee0Sbellard m_min = 0; 735e8996ee0Sbellard m_max = s->nb_helpers - 1; 736e8996ee0Sbellard while (m_min <= m_max) { 737e8996ee0Sbellard m = (m_min + m_max) >> 1; 738e8996ee0Sbellard th = &s->helpers[m]; 739e8996ee0Sbellard v = th->func; 740e8996ee0Sbellard if (v == val) 741e8996ee0Sbellard return th; 742e8996ee0Sbellard else if (val < v) { 743e8996ee0Sbellard m_max = m - 1; 744e8996ee0Sbellard } else { 745e8996ee0Sbellard m_min = m + 1; 746e8996ee0Sbellard } 7474dc81f28Sbellard } 7484dc81f28Sbellard return NULL; 7494dc81f28Sbellard } 7504dc81f28Sbellard 751c896fe29Sbellard void tcg_dump_ops(TCGContext *s, FILE *outfile) 752c896fe29Sbellard { 753c896fe29Sbellard const uint16_t *opc_ptr; 754c896fe29Sbellard const TCGArg *args; 755c896fe29Sbellard TCGArg arg; 7567e4597d7Sbellard int c, i, k, nb_oargs, nb_iargs, nb_cargs, first_insn; 757c896fe29Sbellard const TCGOpDef *def; 758c896fe29Sbellard char buf[128]; 759c896fe29Sbellard 7607e4597d7Sbellard first_insn = 1; 761c896fe29Sbellard opc_ptr = gen_opc_buf; 762c896fe29Sbellard args = gen_opparam_buf; 763c896fe29Sbellard while (opc_ptr < gen_opc_ptr) { 764c896fe29Sbellard c = *opc_ptr++; 765c896fe29Sbellard def = &tcg_op_defs[c]; 7667e4597d7Sbellard if (c == INDEX_op_debug_insn_start) { 7677e4597d7Sbellard uint64_t pc; 7687e4597d7Sbellard #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS 7697e4597d7Sbellard pc = ((uint64_t)args[1] << 32) | args[0]; 7707e4597d7Sbellard #else 7717e4597d7Sbellard pc = args[0]; 7727e4597d7Sbellard #endif 7737e4597d7Sbellard if (!first_insn) 7747e4597d7Sbellard fprintf(outfile, "\n"); 7757e4597d7Sbellard fprintf(outfile, " ---- 0x%" PRIx64, pc); 7767e4597d7Sbellard first_insn = 0; 7777e4597d7Sbellard nb_oargs = def->nb_oargs; 7787e4597d7Sbellard nb_iargs = def->nb_iargs; 7797e4597d7Sbellard nb_cargs = def->nb_cargs; 7807e4597d7Sbellard } else if (c == INDEX_op_call) { 781c896fe29Sbellard TCGArg arg; 7824dc81f28Sbellard 783c896fe29Sbellard /* variable number of arguments */ 784c896fe29Sbellard arg = *args++; 785c896fe29Sbellard nb_oargs = arg >> 16; 786c896fe29Sbellard nb_iargs = arg & 0xffff; 787c896fe29Sbellard nb_cargs = def->nb_cargs; 788b03cce8eSbellard 7897e4597d7Sbellard fprintf(outfile, " %s ", def->name); 7907e4597d7Sbellard 791b03cce8eSbellard /* function name */ 792b03cce8eSbellard fprintf(outfile, "%s", 793e8996ee0Sbellard tcg_get_arg_str_idx(s, buf, sizeof(buf), args[nb_oargs + nb_iargs - 1])); 794b03cce8eSbellard /* flags */ 795b03cce8eSbellard fprintf(outfile, ",$0x%" TCG_PRIlx, 796b03cce8eSbellard args[nb_oargs + nb_iargs]); 797b03cce8eSbellard /* nb out args */ 798b03cce8eSbellard fprintf(outfile, ",$%d", nb_oargs); 799b03cce8eSbellard for(i = 0; i < nb_oargs; i++) { 800b03cce8eSbellard fprintf(outfile, ","); 801b03cce8eSbellard fprintf(outfile, "%s", 802b03cce8eSbellard tcg_get_arg_str_idx(s, buf, sizeof(buf), args[i])); 803b03cce8eSbellard } 804b03cce8eSbellard for(i = 0; i < (nb_iargs - 1); i++) { 805b03cce8eSbellard fprintf(outfile, ","); 80639cf05d3Sbellard if (args[nb_oargs + i] == TCG_CALL_DUMMY_ARG) { 80739cf05d3Sbellard fprintf(outfile, "<dummy>"); 80839cf05d3Sbellard } else { 809b03cce8eSbellard fprintf(outfile, "%s", 810b03cce8eSbellard tcg_get_arg_str_idx(s, buf, sizeof(buf), args[nb_oargs + i])); 811b03cce8eSbellard } 81239cf05d3Sbellard } 813e8996ee0Sbellard } else if (c == INDEX_op_movi_i32 814e8996ee0Sbellard #if TCG_TARGET_REG_BITS == 64 815e8996ee0Sbellard || c == INDEX_op_movi_i64 816e8996ee0Sbellard #endif 817e8996ee0Sbellard ) { 818e8996ee0Sbellard tcg_target_ulong val; 819e8996ee0Sbellard TCGHelperInfo *th; 820e8996ee0Sbellard 821e8996ee0Sbellard nb_oargs = def->nb_oargs; 822e8996ee0Sbellard nb_iargs = def->nb_iargs; 823e8996ee0Sbellard nb_cargs = def->nb_cargs; 824e8996ee0Sbellard fprintf(outfile, " %s %s,$", def->name, 825e8996ee0Sbellard tcg_get_arg_str_idx(s, buf, sizeof(buf), args[0])); 826e8996ee0Sbellard val = args[1]; 827e8996ee0Sbellard th = tcg_find_helper(s, val); 828e8996ee0Sbellard if (th) { 829e8996ee0Sbellard fprintf(outfile, th->name); 830e8996ee0Sbellard } else { 831e8996ee0Sbellard if (c == INDEX_op_movi_i32) 832e8996ee0Sbellard fprintf(outfile, "0x%x", (uint32_t)val); 833e8996ee0Sbellard else 834e8996ee0Sbellard fprintf(outfile, "0x%" PRIx64 , (uint64_t)val); 835e8996ee0Sbellard } 836b03cce8eSbellard } else { 8377e4597d7Sbellard fprintf(outfile, " %s ", def->name); 838b03cce8eSbellard if (c == INDEX_op_nopn) { 839c896fe29Sbellard /* variable number of arguments */ 840c896fe29Sbellard nb_cargs = *args; 841c896fe29Sbellard nb_oargs = 0; 842c896fe29Sbellard nb_iargs = 0; 843c896fe29Sbellard } else { 844c896fe29Sbellard nb_oargs = def->nb_oargs; 845c896fe29Sbellard nb_iargs = def->nb_iargs; 846c896fe29Sbellard nb_cargs = def->nb_cargs; 847c896fe29Sbellard } 848c896fe29Sbellard 849c896fe29Sbellard k = 0; 850c896fe29Sbellard for(i = 0; i < nb_oargs; i++) { 851c896fe29Sbellard if (k != 0) 852c896fe29Sbellard fprintf(outfile, ","); 853ac56dd48Spbrook fprintf(outfile, "%s", 854ac56dd48Spbrook tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++])); 855c896fe29Sbellard } 856c896fe29Sbellard for(i = 0; i < nb_iargs; i++) { 857c896fe29Sbellard if (k != 0) 858c896fe29Sbellard fprintf(outfile, ","); 859ac56dd48Spbrook fprintf(outfile, "%s", 860ac56dd48Spbrook tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++])); 861c896fe29Sbellard } 862c896fe29Sbellard for(i = 0; i < nb_cargs; i++) { 863c896fe29Sbellard if (k != 0) 864c896fe29Sbellard fprintf(outfile, ","); 865c896fe29Sbellard arg = args[k++]; 866c896fe29Sbellard fprintf(outfile, "$0x%" TCG_PRIlx, arg); 867c896fe29Sbellard } 868b03cce8eSbellard } 869c896fe29Sbellard fprintf(outfile, "\n"); 870c896fe29Sbellard args += nb_iargs + nb_oargs + nb_cargs; 871c896fe29Sbellard } 872c896fe29Sbellard } 873c896fe29Sbellard 874c896fe29Sbellard /* we give more priority to constraints with less registers */ 875c896fe29Sbellard static int get_constraint_priority(const TCGOpDef *def, int k) 876c896fe29Sbellard { 877c896fe29Sbellard const TCGArgConstraint *arg_ct; 878c896fe29Sbellard 879c896fe29Sbellard int i, n; 880c896fe29Sbellard arg_ct = &def->args_ct[k]; 881c896fe29Sbellard if (arg_ct->ct & TCG_CT_ALIAS) { 882c896fe29Sbellard /* an alias is equivalent to a single register */ 883c896fe29Sbellard n = 1; 884c896fe29Sbellard } else { 885c896fe29Sbellard if (!(arg_ct->ct & TCG_CT_REG)) 886c896fe29Sbellard return 0; 887c896fe29Sbellard n = 0; 888c896fe29Sbellard for(i = 0; i < TCG_TARGET_NB_REGS; i++) { 889c896fe29Sbellard if (tcg_regset_test_reg(arg_ct->u.regs, i)) 890c896fe29Sbellard n++; 891c896fe29Sbellard } 892c896fe29Sbellard } 893c896fe29Sbellard return TCG_TARGET_NB_REGS - n + 1; 894c896fe29Sbellard } 895c896fe29Sbellard 896c896fe29Sbellard /* sort from highest priority to lowest */ 897c896fe29Sbellard static void sort_constraints(TCGOpDef *def, int start, int n) 898c896fe29Sbellard { 899c896fe29Sbellard int i, j, p1, p2, tmp; 900c896fe29Sbellard 901c896fe29Sbellard for(i = 0; i < n; i++) 902c896fe29Sbellard def->sorted_args[start + i] = start + i; 903c896fe29Sbellard if (n <= 1) 904c896fe29Sbellard return; 905c896fe29Sbellard for(i = 0; i < n - 1; i++) { 906c896fe29Sbellard for(j = i + 1; j < n; j++) { 907c896fe29Sbellard p1 = get_constraint_priority(def, def->sorted_args[start + i]); 908c896fe29Sbellard p2 = get_constraint_priority(def, def->sorted_args[start + j]); 909c896fe29Sbellard if (p1 < p2) { 910c896fe29Sbellard tmp = def->sorted_args[start + i]; 911c896fe29Sbellard def->sorted_args[start + i] = def->sorted_args[start + j]; 912c896fe29Sbellard def->sorted_args[start + j] = tmp; 913c896fe29Sbellard } 914c896fe29Sbellard } 915c896fe29Sbellard } 916c896fe29Sbellard } 917c896fe29Sbellard 918c896fe29Sbellard void tcg_add_target_add_op_defs(const TCGTargetOpDef *tdefs) 919c896fe29Sbellard { 920c896fe29Sbellard int op; 921c896fe29Sbellard TCGOpDef *def; 922c896fe29Sbellard const char *ct_str; 923c896fe29Sbellard int i, nb_args; 924c896fe29Sbellard 925c896fe29Sbellard for(;;) { 926c896fe29Sbellard if (tdefs->op < 0) 927c896fe29Sbellard break; 928c896fe29Sbellard op = tdefs->op; 929c896fe29Sbellard assert(op >= 0 && op < NB_OPS); 930c896fe29Sbellard def = &tcg_op_defs[op]; 931c896fe29Sbellard nb_args = def->nb_iargs + def->nb_oargs; 932c896fe29Sbellard for(i = 0; i < nb_args; i++) { 933c896fe29Sbellard ct_str = tdefs->args_ct_str[i]; 934c896fe29Sbellard tcg_regset_clear(def->args_ct[i].u.regs); 935c896fe29Sbellard def->args_ct[i].ct = 0; 936c896fe29Sbellard if (ct_str[0] >= '0' && ct_str[0] <= '9') { 937c896fe29Sbellard int oarg; 938c896fe29Sbellard oarg = ct_str[0] - '0'; 939c896fe29Sbellard assert(oarg < def->nb_oargs); 940c896fe29Sbellard assert(def->args_ct[oarg].ct & TCG_CT_REG); 941c896fe29Sbellard /* TCG_CT_ALIAS is for the output arguments. The input 9425ff9d6a4Sbellard argument is tagged with TCG_CT_IALIAS. */ 943c896fe29Sbellard def->args_ct[i] = def->args_ct[oarg]; 9445ff9d6a4Sbellard def->args_ct[oarg].ct = TCG_CT_ALIAS; 9455ff9d6a4Sbellard def->args_ct[oarg].alias_index = i; 946c896fe29Sbellard def->args_ct[i].ct |= TCG_CT_IALIAS; 9475ff9d6a4Sbellard def->args_ct[i].alias_index = oarg; 948c896fe29Sbellard } else { 949c896fe29Sbellard for(;;) { 950c896fe29Sbellard if (*ct_str == '\0') 951c896fe29Sbellard break; 952c896fe29Sbellard switch(*ct_str) { 953c896fe29Sbellard case 'i': 954c896fe29Sbellard def->args_ct[i].ct |= TCG_CT_CONST; 955c896fe29Sbellard ct_str++; 956c896fe29Sbellard break; 957c896fe29Sbellard default: 958c896fe29Sbellard if (target_parse_constraint(&def->args_ct[i], &ct_str) < 0) { 959c896fe29Sbellard fprintf(stderr, "Invalid constraint '%s' for arg %d of operation '%s'\n", 960c896fe29Sbellard ct_str, i, def->name); 961c896fe29Sbellard exit(1); 962c896fe29Sbellard } 963c896fe29Sbellard } 964c896fe29Sbellard } 965c896fe29Sbellard } 966c896fe29Sbellard } 967c896fe29Sbellard 968c896fe29Sbellard /* sort the constraints (XXX: this is just an heuristic) */ 969c896fe29Sbellard sort_constraints(def, 0, def->nb_oargs); 970c896fe29Sbellard sort_constraints(def, def->nb_oargs, def->nb_iargs); 971c896fe29Sbellard 972c896fe29Sbellard #if 0 973c896fe29Sbellard { 974c896fe29Sbellard int i; 975c896fe29Sbellard 976c896fe29Sbellard printf("%s: sorted=", def->name); 977c896fe29Sbellard for(i = 0; i < def->nb_oargs + def->nb_iargs; i++) 978c896fe29Sbellard printf(" %d", def->sorted_args[i]); 979c896fe29Sbellard printf("\n"); 980c896fe29Sbellard } 981c896fe29Sbellard #endif 982c896fe29Sbellard tdefs++; 983c896fe29Sbellard } 984c896fe29Sbellard 985c896fe29Sbellard } 986c896fe29Sbellard 987c896fe29Sbellard #ifdef USE_LIVENESS_ANALYSIS 988c896fe29Sbellard 989c896fe29Sbellard /* set a nop for an operation using 'nb_args' */ 990c896fe29Sbellard static inline void tcg_set_nop(TCGContext *s, uint16_t *opc_ptr, 991c896fe29Sbellard TCGArg *args, int nb_args) 992c896fe29Sbellard { 993c896fe29Sbellard if (nb_args == 0) { 994c896fe29Sbellard *opc_ptr = INDEX_op_nop; 995c896fe29Sbellard } else { 996c896fe29Sbellard *opc_ptr = INDEX_op_nopn; 997c896fe29Sbellard args[0] = nb_args; 998c896fe29Sbellard args[nb_args - 1] = nb_args; 999c896fe29Sbellard } 1000c896fe29Sbellard } 1001c896fe29Sbellard 1002*641d5fbeSbellard /* liveness analysis: end of function: globals are live, temps are 1003*641d5fbeSbellard dead. */ 1004*641d5fbeSbellard /* XXX: at this stage, not used as there would be little gains because 1005*641d5fbeSbellard most TBs end with a conditional jump. */ 1006*641d5fbeSbellard static inline void tcg_la_func_end(TCGContext *s, uint8_t *dead_temps) 1007c896fe29Sbellard { 1008c896fe29Sbellard memset(dead_temps, 0, s->nb_globals); 1009c896fe29Sbellard memset(dead_temps + s->nb_globals, 1, s->nb_temps - s->nb_globals); 1010c896fe29Sbellard } 1011c896fe29Sbellard 1012*641d5fbeSbellard /* liveness analysis: end of basic block: globals are live, temps are 1013*641d5fbeSbellard dead, local temps are live. */ 1014*641d5fbeSbellard static inline void tcg_la_bb_end(TCGContext *s, uint8_t *dead_temps) 1015*641d5fbeSbellard { 1016*641d5fbeSbellard int i; 1017*641d5fbeSbellard TCGTemp *ts; 1018*641d5fbeSbellard 1019*641d5fbeSbellard memset(dead_temps, 0, s->nb_globals); 1020*641d5fbeSbellard ts = &s->temps[s->nb_globals]; 1021*641d5fbeSbellard for(i = s->nb_globals; i < s->nb_temps; i++) { 1022*641d5fbeSbellard if (ts->temp_local) 1023*641d5fbeSbellard dead_temps[i] = 0; 1024*641d5fbeSbellard else 1025*641d5fbeSbellard dead_temps[i] = 1; 1026*641d5fbeSbellard ts++; 1027*641d5fbeSbellard } 1028*641d5fbeSbellard } 1029*641d5fbeSbellard 1030c896fe29Sbellard /* Liveness analysis : update the opc_dead_iargs array to tell if a 1031c896fe29Sbellard given input arguments is dead. Instructions updating dead 1032c896fe29Sbellard temporaries are removed. */ 1033c896fe29Sbellard void tcg_liveness_analysis(TCGContext *s) 1034c896fe29Sbellard { 1035c896fe29Sbellard int i, op_index, op, nb_args, nb_iargs, nb_oargs, arg, nb_ops; 1036c896fe29Sbellard TCGArg *args; 1037c896fe29Sbellard const TCGOpDef *def; 1038c896fe29Sbellard uint8_t *dead_temps; 1039c896fe29Sbellard unsigned int dead_iargs; 1040c896fe29Sbellard 1041c896fe29Sbellard gen_opc_ptr++; /* skip end */ 1042c896fe29Sbellard 1043c896fe29Sbellard nb_ops = gen_opc_ptr - gen_opc_buf; 1044c896fe29Sbellard 1045c896fe29Sbellard /* XXX: make it really dynamic */ 1046c896fe29Sbellard s->op_dead_iargs = tcg_malloc(OPC_BUF_SIZE * sizeof(uint16_t)); 1047c896fe29Sbellard 1048c896fe29Sbellard dead_temps = tcg_malloc(s->nb_temps); 1049c896fe29Sbellard memset(dead_temps, 1, s->nb_temps); 1050c896fe29Sbellard 1051c896fe29Sbellard args = gen_opparam_ptr; 1052c896fe29Sbellard op_index = nb_ops - 1; 1053c896fe29Sbellard while (op_index >= 0) { 1054c896fe29Sbellard op = gen_opc_buf[op_index]; 1055c896fe29Sbellard def = &tcg_op_defs[op]; 1056c896fe29Sbellard switch(op) { 1057c896fe29Sbellard case INDEX_op_call: 1058c6e113f5Sbellard { 1059c6e113f5Sbellard int call_flags; 1060c6e113f5Sbellard 1061c896fe29Sbellard nb_args = args[-1]; 1062c896fe29Sbellard args -= nb_args; 1063c896fe29Sbellard nb_iargs = args[0] & 0xffff; 1064c896fe29Sbellard nb_oargs = args[0] >> 16; 1065c896fe29Sbellard args++; 1066c6e113f5Sbellard call_flags = args[nb_oargs + nb_iargs]; 1067c6e113f5Sbellard 1068c6e113f5Sbellard /* pure functions can be removed if their result is not 1069c6e113f5Sbellard used */ 1070c6e113f5Sbellard if (call_flags & TCG_CALL_PURE) { 1071c6e113f5Sbellard for(i = 0; i < nb_oargs; i++) { 1072c6e113f5Sbellard arg = args[i]; 1073c6e113f5Sbellard if (!dead_temps[arg]) 1074c6e113f5Sbellard goto do_not_remove_call; 1075c6e113f5Sbellard } 1076c6e113f5Sbellard tcg_set_nop(s, gen_opc_buf + op_index, 1077c6e113f5Sbellard args - 1, nb_args); 1078c6e113f5Sbellard } else { 1079c6e113f5Sbellard do_not_remove_call: 1080c896fe29Sbellard 1081c896fe29Sbellard /* output args are dead */ 1082c896fe29Sbellard for(i = 0; i < nb_oargs; i++) { 1083c896fe29Sbellard arg = args[i]; 1084c896fe29Sbellard dead_temps[arg] = 1; 1085c896fe29Sbellard } 1086c896fe29Sbellard 1087c896fe29Sbellard /* globals are live (they may be used by the call) */ 1088c896fe29Sbellard memset(dead_temps, 0, s->nb_globals); 1089c896fe29Sbellard 1090c896fe29Sbellard /* input args are live */ 1091c896fe29Sbellard dead_iargs = 0; 1092c896fe29Sbellard for(i = 0; i < nb_iargs; i++) { 1093c896fe29Sbellard arg = args[i + nb_oargs]; 109439cf05d3Sbellard if (arg != TCG_CALL_DUMMY_ARG) { 1095c896fe29Sbellard if (dead_temps[arg]) { 1096c896fe29Sbellard dead_iargs |= (1 << i); 1097c896fe29Sbellard } 1098c896fe29Sbellard dead_temps[arg] = 0; 1099c896fe29Sbellard } 110039cf05d3Sbellard } 1101c896fe29Sbellard s->op_dead_iargs[op_index] = dead_iargs; 1102c6e113f5Sbellard } 1103c896fe29Sbellard args--; 1104c6e113f5Sbellard } 1105c896fe29Sbellard break; 1106c896fe29Sbellard case INDEX_op_set_label: 1107c896fe29Sbellard args--; 1108c896fe29Sbellard /* mark end of basic block */ 1109c896fe29Sbellard tcg_la_bb_end(s, dead_temps); 1110c896fe29Sbellard break; 11117e4597d7Sbellard case INDEX_op_debug_insn_start: 11127e4597d7Sbellard args -= def->nb_args; 11137e4597d7Sbellard break; 1114c896fe29Sbellard case INDEX_op_nopn: 1115c896fe29Sbellard nb_args = args[-1]; 1116c896fe29Sbellard args -= nb_args; 1117c896fe29Sbellard break; 11185ff9d6a4Sbellard case INDEX_op_discard: 11195ff9d6a4Sbellard args--; 11205ff9d6a4Sbellard /* mark the temporary as dead */ 11215ff9d6a4Sbellard dead_temps[args[0]] = 1; 11225ff9d6a4Sbellard break; 1123c896fe29Sbellard case INDEX_op_macro_2: 1124c896fe29Sbellard { 1125c896fe29Sbellard int dead_args[2], macro_id; 1126c896fe29Sbellard int saved_op_index, saved_arg_index; 1127c896fe29Sbellard int macro_op_index, macro_arg_index; 1128c896fe29Sbellard int macro_end_op_index, macro_end_arg_index; 1129c896fe29Sbellard int last_nb_temps; 1130c896fe29Sbellard 1131c896fe29Sbellard nb_args = 3; 1132c896fe29Sbellard args -= nb_args; 1133c896fe29Sbellard dead_args[0] = dead_temps[args[0]]; 1134c896fe29Sbellard dead_args[1] = dead_temps[args[1]]; 1135c896fe29Sbellard macro_id = args[2]; 1136c896fe29Sbellard 1137c896fe29Sbellard /* call the macro function which generate code 1138c896fe29Sbellard depending on the live outputs */ 1139c896fe29Sbellard saved_op_index = op_index; 1140c896fe29Sbellard saved_arg_index = args - gen_opparam_buf; 1141c896fe29Sbellard 1142c896fe29Sbellard /* add a macro start instruction */ 1143c896fe29Sbellard *gen_opc_ptr++ = INDEX_op_macro_start; 1144c896fe29Sbellard *gen_opparam_ptr++ = saved_op_index; 1145c896fe29Sbellard *gen_opparam_ptr++ = saved_arg_index; 1146c896fe29Sbellard 1147c896fe29Sbellard macro_op_index = gen_opc_ptr - gen_opc_buf; 1148c896fe29Sbellard macro_arg_index = gen_opparam_ptr - gen_opparam_buf; 1149c896fe29Sbellard 1150c896fe29Sbellard last_nb_temps = s->nb_temps; 1151c896fe29Sbellard 1152c896fe29Sbellard s->macro_func(s, macro_id, dead_args); 1153c896fe29Sbellard 1154c896fe29Sbellard /* realloc temp info (XXX: make it faster) */ 1155c896fe29Sbellard if (s->nb_temps > last_nb_temps) { 1156c896fe29Sbellard uint8_t *new_dead_temps; 1157c896fe29Sbellard 1158c896fe29Sbellard new_dead_temps = tcg_malloc(s->nb_temps); 1159c896fe29Sbellard memcpy(new_dead_temps, dead_temps, last_nb_temps); 1160c896fe29Sbellard memset(new_dead_temps + last_nb_temps, 1, 1161c896fe29Sbellard s->nb_temps - last_nb_temps); 1162c896fe29Sbellard dead_temps = new_dead_temps; 1163c896fe29Sbellard } 1164c896fe29Sbellard 1165c896fe29Sbellard macro_end_op_index = gen_opc_ptr - gen_opc_buf; 1166c896fe29Sbellard macro_end_arg_index = gen_opparam_ptr - gen_opparam_buf; 1167c896fe29Sbellard 1168c896fe29Sbellard /* end of macro: add a goto to the next instruction */ 1169c896fe29Sbellard *gen_opc_ptr++ = INDEX_op_macro_end; 1170c896fe29Sbellard *gen_opparam_ptr++ = op_index + 1; 1171c896fe29Sbellard *gen_opparam_ptr++ = saved_arg_index + nb_args; 1172c896fe29Sbellard 1173c896fe29Sbellard /* modify the macro operation to be a macro_goto */ 1174c896fe29Sbellard gen_opc_buf[op_index] = INDEX_op_macro_goto; 1175c896fe29Sbellard args[0] = macro_op_index; 1176c896fe29Sbellard args[1] = macro_arg_index; 1177c896fe29Sbellard args[2] = 0; /* dummy third arg to match the 1178c896fe29Sbellard macro parameters */ 1179c896fe29Sbellard 1180c896fe29Sbellard /* set the next instruction to the end of the macro */ 1181c896fe29Sbellard op_index = macro_end_op_index; 1182c896fe29Sbellard args = macro_end_arg_index + gen_opparam_buf; 1183c896fe29Sbellard } 1184c896fe29Sbellard break; 1185c896fe29Sbellard case INDEX_op_macro_start: 1186c896fe29Sbellard args -= 2; 1187c896fe29Sbellard op_index = args[0]; 1188c896fe29Sbellard args = gen_opparam_buf + args[1]; 1189c896fe29Sbellard break; 1190c896fe29Sbellard case INDEX_op_macro_goto: 1191c896fe29Sbellard case INDEX_op_macro_end: 1192c896fe29Sbellard tcg_abort(); /* should never happen in liveness analysis */ 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 1402*641d5fbeSbellard /* save a temporary to memory. 'allocated_regs' is used in case a 1403e8996ee0Sbellard temporary registers needs to be allocated to store a constant. */ 1404*641d5fbeSbellard static void temp_save(TCGContext *s, int temp, TCGRegSet allocated_regs) 1405c896fe29Sbellard { 1406c896fe29Sbellard TCGTemp *ts; 1407*641d5fbeSbellard int reg; 1408c896fe29Sbellard 1409*641d5fbeSbellard 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); 1421*641d5fbeSbellard if (!ts->mem_allocated) 1422*641d5fbeSbellard 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 } 1434*641d5fbeSbellard 1435*641d5fbeSbellard /* save globals to their cannonical location and assume they can be 1436*641d5fbeSbellard modified be the following code. 'allocated_regs' is used in case a 1437*641d5fbeSbellard temporary registers needs to be allocated to store a constant. */ 1438*641d5fbeSbellard static void save_globals(TCGContext *s, TCGRegSet allocated_regs) 1439*641d5fbeSbellard { 1440*641d5fbeSbellard int i; 1441*641d5fbeSbellard 1442*641d5fbeSbellard for(i = 0; i < s->nb_globals; i++) { 1443*641d5fbeSbellard temp_save(s, i, allocated_regs); 1444*641d5fbeSbellard } 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]; 1456*641d5fbeSbellard if (ts->temp_local) { 1457*641d5fbeSbellard temp_save(s, i, allocated_regs); 1458*641d5fbeSbellard } 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 } 1464*641d5fbeSbellard } 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 { 1484e8996ee0Sbellard /* The movi is not explicitely 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 { 1919c896fe29Sbellard int opc, op_index, macro_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 macro_op_index = -1; 1954c896fe29Sbellard args = gen_opparam_buf; 1955c896fe29Sbellard op_index = 0; 1956b3db8758Sblueswir1 1957c896fe29Sbellard for(;;) { 1958c896fe29Sbellard opc = gen_opc_buf[op_index]; 1959c896fe29Sbellard #ifdef CONFIG_PROFILER 1960c896fe29Sbellard dyngen_table_op_count[opc]++; 1961c896fe29Sbellard #endif 1962c896fe29Sbellard def = &tcg_op_defs[opc]; 1963c896fe29Sbellard #if 0 1964c896fe29Sbellard printf("%s: %d %d %d\n", def->name, 1965c896fe29Sbellard def->nb_oargs, def->nb_iargs, def->nb_cargs); 1966c896fe29Sbellard // dump_regs(s); 1967c896fe29Sbellard #endif 1968c896fe29Sbellard switch(opc) { 1969c896fe29Sbellard case INDEX_op_mov_i32: 1970c896fe29Sbellard #if TCG_TARGET_REG_BITS == 64 1971c896fe29Sbellard case INDEX_op_mov_i64: 1972c896fe29Sbellard #endif 1973c896fe29Sbellard dead_iargs = s->op_dead_iargs[op_index]; 1974c896fe29Sbellard tcg_reg_alloc_mov(s, def, args, dead_iargs); 1975c896fe29Sbellard break; 1976e8996ee0Sbellard case INDEX_op_movi_i32: 1977e8996ee0Sbellard #if TCG_TARGET_REG_BITS == 64 1978e8996ee0Sbellard case INDEX_op_movi_i64: 1979e8996ee0Sbellard #endif 1980e8996ee0Sbellard tcg_reg_alloc_movi(s, args); 1981e8996ee0Sbellard break; 19827e4597d7Sbellard case INDEX_op_debug_insn_start: 19837e4597d7Sbellard /* debug instruction */ 19847e4597d7Sbellard break; 1985c896fe29Sbellard case INDEX_op_nop: 1986c896fe29Sbellard case INDEX_op_nop1: 1987c896fe29Sbellard case INDEX_op_nop2: 1988c896fe29Sbellard case INDEX_op_nop3: 1989c896fe29Sbellard break; 1990c896fe29Sbellard case INDEX_op_nopn: 1991c896fe29Sbellard args += args[0]; 1992c896fe29Sbellard goto next; 19935ff9d6a4Sbellard case INDEX_op_discard: 19945ff9d6a4Sbellard { 19955ff9d6a4Sbellard TCGTemp *ts; 19965ff9d6a4Sbellard ts = &s->temps[args[0]]; 19975ff9d6a4Sbellard /* mark the temporary as dead */ 1998e8996ee0Sbellard if (!ts->fixed_reg) { 19995ff9d6a4Sbellard if (ts->val_type == TEMP_VAL_REG) 20005ff9d6a4Sbellard s->reg_to_temp[ts->reg] = -1; 20015ff9d6a4Sbellard ts->val_type = TEMP_VAL_DEAD; 20025ff9d6a4Sbellard } 20035ff9d6a4Sbellard } 20045ff9d6a4Sbellard break; 2005c896fe29Sbellard case INDEX_op_macro_goto: 2006c896fe29Sbellard macro_op_index = op_index; /* only used for exceptions */ 2007c896fe29Sbellard op_index = args[0] - 1; 2008c896fe29Sbellard args = gen_opparam_buf + args[1]; 2009c896fe29Sbellard goto next; 2010c896fe29Sbellard case INDEX_op_macro_end: 2011c896fe29Sbellard macro_op_index = -1; /* only used for exceptions */ 2012c896fe29Sbellard op_index = args[0] - 1; 2013c896fe29Sbellard args = gen_opparam_buf + args[1]; 2014c896fe29Sbellard goto next; 2015c896fe29Sbellard case INDEX_op_macro_start: 2016c896fe29Sbellard /* must never happen here */ 2017c896fe29Sbellard tcg_abort(); 2018c896fe29Sbellard case INDEX_op_set_label: 2019e8996ee0Sbellard tcg_reg_alloc_bb_end(s, s->reserved_regs); 2020c896fe29Sbellard tcg_out_label(s, args[0], (long)s->code_ptr); 2021c896fe29Sbellard break; 2022c896fe29Sbellard case INDEX_op_call: 2023c896fe29Sbellard dead_iargs = s->op_dead_iargs[op_index]; 2024c896fe29Sbellard args += tcg_reg_alloc_call(s, def, opc, args, dead_iargs); 2025c896fe29Sbellard goto next; 2026c896fe29Sbellard case INDEX_op_end: 2027c896fe29Sbellard goto the_end; 2028cf2be984Sblueswir1 2029bf6247fbSblueswir1 #ifdef CONFIG_DYNGEN_OP 2030c896fe29Sbellard case 0 ... INDEX_op_end - 1: 2031c896fe29Sbellard /* legacy dyngen ops */ 2032c896fe29Sbellard #ifdef CONFIG_PROFILER 2033a23a9ec6Sbellard s->old_op_count++; 2034c896fe29Sbellard #endif 2035e8996ee0Sbellard tcg_reg_alloc_bb_end(s, s->reserved_regs); 20362ba1eeb6Spbrook if (search_pc >= 0) { 2037c896fe29Sbellard s->code_ptr += def->copy_size; 2038c896fe29Sbellard args += def->nb_args; 2039c896fe29Sbellard } else { 2040c896fe29Sbellard args = dyngen_op(s, opc, args); 2041c896fe29Sbellard } 2042c896fe29Sbellard goto next; 2043cf2be984Sblueswir1 #endif 2044c896fe29Sbellard default: 2045c896fe29Sbellard /* Note: in order to speed up the code, it would be much 2046c896fe29Sbellard faster to have specialized register allocator functions for 2047c896fe29Sbellard some common argument patterns */ 2048c896fe29Sbellard dead_iargs = s->op_dead_iargs[op_index]; 2049c896fe29Sbellard tcg_reg_alloc_op(s, def, opc, args, dead_iargs); 2050c896fe29Sbellard break; 2051c896fe29Sbellard } 2052c896fe29Sbellard args += def->nb_args; 2053c896fe29Sbellard next: ; 20542ba1eeb6Spbrook if (search_pc >= 0 && search_pc < s->code_ptr - gen_code_buf) { 2055c896fe29Sbellard if (macro_op_index >= 0) 2056c896fe29Sbellard return macro_op_index; 2057c896fe29Sbellard else 2058c896fe29Sbellard return op_index; 2059c896fe29Sbellard } 2060c896fe29Sbellard op_index++; 2061c896fe29Sbellard #ifndef NDEBUG 2062c896fe29Sbellard check_regs(s); 2063c896fe29Sbellard #endif 2064c896fe29Sbellard } 2065c896fe29Sbellard the_end: 2066c896fe29Sbellard return -1; 2067c896fe29Sbellard } 2068c896fe29Sbellard 2069c896fe29Sbellard int dyngen_code(TCGContext *s, uint8_t *gen_code_buf) 2070c896fe29Sbellard { 2071c896fe29Sbellard #ifdef CONFIG_PROFILER 2072c896fe29Sbellard { 2073c896fe29Sbellard int n; 2074c896fe29Sbellard n = (gen_opc_ptr - gen_opc_buf); 2075a23a9ec6Sbellard s->op_count += n; 2076a23a9ec6Sbellard if (n > s->op_count_max) 2077a23a9ec6Sbellard s->op_count_max = n; 2078a23a9ec6Sbellard 2079a23a9ec6Sbellard s->temp_count += s->nb_temps; 2080a23a9ec6Sbellard if (s->nb_temps > s->temp_count_max) 2081a23a9ec6Sbellard s->temp_count_max = s->nb_temps; 2082c896fe29Sbellard } 2083c896fe29Sbellard #endif 2084c896fe29Sbellard 20852ba1eeb6Spbrook tcg_gen_code_common(s, gen_code_buf, -1); 2086c896fe29Sbellard 2087c896fe29Sbellard /* flush instruction cache */ 2088c896fe29Sbellard flush_icache_range((unsigned long)gen_code_buf, 2089c896fe29Sbellard (unsigned long)s->code_ptr); 2090c896fe29Sbellard return s->code_ptr - gen_code_buf; 2091c896fe29Sbellard } 2092c896fe29Sbellard 20932ba1eeb6Spbrook /* Return the index of the micro operation such as the pc after is < 2094623e265cSpbrook offset bytes from the start of the TB. The contents of gen_code_buf must 2095623e265cSpbrook not be changed, though writing the same values is ok. 2096623e265cSpbrook Return -1 if not found. */ 2097623e265cSpbrook int dyngen_code_search_pc(TCGContext *s, uint8_t *gen_code_buf, long offset) 2098c896fe29Sbellard { 2099623e265cSpbrook return tcg_gen_code_common(s, gen_code_buf, offset); 2100c896fe29Sbellard } 2101a23a9ec6Sbellard 2102a23a9ec6Sbellard #ifdef CONFIG_PROFILER 2103a23a9ec6Sbellard void tcg_dump_info(FILE *f, 2104a23a9ec6Sbellard int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) 2105a23a9ec6Sbellard { 2106a23a9ec6Sbellard TCGContext *s = &tcg_ctx; 2107a23a9ec6Sbellard int64_t tot; 2108a23a9ec6Sbellard 2109a23a9ec6Sbellard tot = s->interm_time + s->code_time; 2110a23a9ec6Sbellard cpu_fprintf(f, "JIT cycles %" PRId64 " (%0.3f s at 2.4 GHz)\n", 2111a23a9ec6Sbellard tot, tot / 2.4e9); 2112a23a9ec6Sbellard cpu_fprintf(f, "translated TBs %" PRId64 " (aborted=%" PRId64 " %0.1f%%)\n", 2113a23a9ec6Sbellard s->tb_count, 2114a23a9ec6Sbellard s->tb_count1 - s->tb_count, 2115a23a9ec6Sbellard s->tb_count1 ? (double)(s->tb_count1 - s->tb_count) / s->tb_count1 * 100.0 : 0); 2116a23a9ec6Sbellard cpu_fprintf(f, "avg ops/TB %0.1f max=%d\n", 2117a23a9ec6Sbellard s->tb_count ? (double)s->op_count / s->tb_count : 0, s->op_count_max); 2118a23a9ec6Sbellard cpu_fprintf(f, "old ops/total ops %0.1f%%\n", 2119a23a9ec6Sbellard s->op_count ? (double)s->old_op_count / s->op_count * 100.0 : 0); 2120a23a9ec6Sbellard cpu_fprintf(f, "deleted ops/TB %0.2f\n", 2121a23a9ec6Sbellard s->tb_count ? 2122a23a9ec6Sbellard (double)s->del_op_count / s->tb_count : 0); 2123a23a9ec6Sbellard cpu_fprintf(f, "avg temps/TB %0.2f max=%d\n", 2124a23a9ec6Sbellard s->tb_count ? 2125a23a9ec6Sbellard (double)s->temp_count / s->tb_count : 0, 2126a23a9ec6Sbellard s->temp_count_max); 2127a23a9ec6Sbellard 2128a23a9ec6Sbellard cpu_fprintf(f, "cycles/op %0.1f\n", 2129a23a9ec6Sbellard s->op_count ? (double)tot / s->op_count : 0); 2130a23a9ec6Sbellard cpu_fprintf(f, "cycles/in byte %0.1f\n", 2131a23a9ec6Sbellard s->code_in_len ? (double)tot / s->code_in_len : 0); 2132a23a9ec6Sbellard cpu_fprintf(f, "cycles/out byte %0.1f\n", 2133a23a9ec6Sbellard s->code_out_len ? (double)tot / s->code_out_len : 0); 2134a23a9ec6Sbellard if (tot == 0) 2135a23a9ec6Sbellard tot = 1; 2136a23a9ec6Sbellard cpu_fprintf(f, " gen_interm time %0.1f%%\n", 2137a23a9ec6Sbellard (double)s->interm_time / tot * 100.0); 2138a23a9ec6Sbellard cpu_fprintf(f, " gen_code time %0.1f%%\n", 2139a23a9ec6Sbellard (double)s->code_time / tot * 100.0); 2140a23a9ec6Sbellard cpu_fprintf(f, "liveness/code time %0.1f%%\n", 2141a23a9ec6Sbellard (double)s->la_time / (s->code_time ? s->code_time : 1) * 100.0); 2142a23a9ec6Sbellard cpu_fprintf(f, "cpu_restore count %" PRId64 "\n", 2143a23a9ec6Sbellard s->restore_count); 2144a23a9ec6Sbellard cpu_fprintf(f, " avg cycles %0.1f\n", 2145a23a9ec6Sbellard s->restore_count ? (double)s->restore_time / s->restore_count : 0); 2146a23a9ec6Sbellard { 2147a23a9ec6Sbellard extern void dump_op_count(void); 2148a23a9ec6Sbellard dump_op_count(); 2149a23a9ec6Sbellard } 2150a23a9ec6Sbellard } 2151a23a9ec6Sbellard #else 215224bf7b3aSbellard void tcg_dump_info(FILE *f, 2153a23a9ec6Sbellard int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) 2154a23a9ec6Sbellard { 215524bf7b3aSbellard cpu_fprintf(f, "[TCG profiler not compiled]\n"); 2156a23a9ec6Sbellard } 2157a23a9ec6Sbellard #endif 2158