1c896fe29Sbellard /* 2c896fe29Sbellard * Tiny Code Generator for QEMU 3c896fe29Sbellard * 4c896fe29Sbellard * Copyright (c) 2008 Fabrice Bellard 5c896fe29Sbellard * 6c896fe29Sbellard * Permission is hereby granted, free of charge, to any person obtaining a copy 7c896fe29Sbellard * of this software and associated documentation files (the "Software"), to deal 8c896fe29Sbellard * in the Software without restriction, including without limitation the rights 9c896fe29Sbellard * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10c896fe29Sbellard * copies of the Software, and to permit persons to whom the Software is 11c896fe29Sbellard * furnished to do so, subject to the following conditions: 12c896fe29Sbellard * 13c896fe29Sbellard * The above copyright notice and this permission notice shall be included in 14c896fe29Sbellard * all copies or substantial portions of the Software. 15c896fe29Sbellard * 16c896fe29Sbellard * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17c896fe29Sbellard * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18c896fe29Sbellard * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19c896fe29Sbellard * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20c896fe29Sbellard * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21c896fe29Sbellard * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22c896fe29Sbellard * THE SOFTWARE. 23c896fe29Sbellard */ 24c896fe29Sbellard 25c896fe29Sbellard /* define it to use liveness analysis (better code) */ 268f2e8c07SKirill Batuzov #define USE_TCG_OPTIMIZATIONS 27c896fe29Sbellard 28757e725bSPeter Maydell #include "qemu/osdep.h" 29cca82982Saurel32 30813da627SRichard Henderson /* Define to jump the ELF file used to communicate with GDB. */ 31813da627SRichard Henderson #undef DEBUG_JIT 32813da627SRichard Henderson 3372fd2efbSEmilio G. Cota #include "qemu/error-report.h" 34f348b6d1SVeronia Bahaa #include "qemu/cutils.h" 351de7afc9SPaolo Bonzini #include "qemu/host-utils.h" 36d4c51a0aSMarkus Armbruster #include "qemu/qemu-print.h" 371de7afc9SPaolo Bonzini #include "qemu/timer.h" 38*084cfca1SRichard Henderson #include "qemu/cacheflush.h" 39c896fe29Sbellard 40c5d3c498SStefan Weil /* Note: the long term plan is to reduce the dependencies on the QEMU 41c896fe29Sbellard CPU definitions. Currently they are used for qemu_ld/st 42c896fe29Sbellard instructions */ 43c896fe29Sbellard #define NO_CPU_IO_DEFS 44c896fe29Sbellard #include "cpu.h" 45c896fe29Sbellard 4663c91552SPaolo Bonzini #include "exec/exec-all.h" 4763c91552SPaolo Bonzini 485cc8767dSLike Xu #if !defined(CONFIG_USER_ONLY) 495cc8767dSLike Xu #include "hw/boards.h" 505cc8767dSLike Xu #endif 515cc8767dSLike Xu 52dcb32f1dSPhilippe Mathieu-Daudé #include "tcg/tcg-op.h" 53813da627SRichard Henderson 54edee2579SRichard Henderson #if UINTPTR_MAX == UINT32_MAX 55813da627SRichard Henderson # define ELF_CLASS ELFCLASS32 56edee2579SRichard Henderson #else 57edee2579SRichard Henderson # define ELF_CLASS ELFCLASS64 58813da627SRichard Henderson #endif 59813da627SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN 60813da627SRichard Henderson # define ELF_DATA ELFDATA2MSB 61813da627SRichard Henderson #else 62813da627SRichard Henderson # define ELF_DATA ELFDATA2LSB 63813da627SRichard Henderson #endif 64813da627SRichard Henderson 65c896fe29Sbellard #include "elf.h" 66508127e2SPaolo Bonzini #include "exec/log.h" 673468b59eSEmilio G. Cota #include "sysemu/sysemu.h" 68c896fe29Sbellard 69139c1837SPaolo Bonzini /* Forward declarations for functions declared in tcg-target.c.inc and 70ce151109SPeter Maydell used here. */ 71e4d58b41SRichard Henderson static void tcg_target_init(TCGContext *s); 72f69d277eSRichard Henderson static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode); 73e4d58b41SRichard Henderson static void tcg_target_qemu_prologue(TCGContext *s); 746ac17786SRichard Henderson static bool patch_reloc(tcg_insn_unit *code_ptr, int type, 752ba7fae2SRichard Henderson intptr_t value, intptr_t addend); 76c896fe29Sbellard 77497a22ebSRichard Henderson /* The CIE and FDE header definitions will be common to all hosts. */ 78497a22ebSRichard Henderson typedef struct { 79497a22ebSRichard Henderson uint32_t len __attribute__((aligned((sizeof(void *))))); 80497a22ebSRichard Henderson uint32_t id; 81497a22ebSRichard Henderson uint8_t version; 82497a22ebSRichard Henderson char augmentation[1]; 83497a22ebSRichard Henderson uint8_t code_align; 84497a22ebSRichard Henderson uint8_t data_align; 85497a22ebSRichard Henderson uint8_t return_column; 86497a22ebSRichard Henderson } DebugFrameCIE; 87497a22ebSRichard Henderson 88497a22ebSRichard Henderson typedef struct QEMU_PACKED { 89497a22ebSRichard Henderson uint32_t len __attribute__((aligned((sizeof(void *))))); 90497a22ebSRichard Henderson uint32_t cie_offset; 91edee2579SRichard Henderson uintptr_t func_start; 92edee2579SRichard Henderson uintptr_t func_len; 93497a22ebSRichard Henderson } DebugFrameFDEHeader; 94497a22ebSRichard Henderson 952c90784aSRichard Henderson typedef struct QEMU_PACKED { 962c90784aSRichard Henderson DebugFrameCIE cie; 972c90784aSRichard Henderson DebugFrameFDEHeader fde; 982c90784aSRichard Henderson } DebugFrameHeader; 992c90784aSRichard Henderson 100813da627SRichard Henderson static void tcg_register_jit_int(void *buf, size_t size, 1012c90784aSRichard Henderson const void *debug_frame, 1022c90784aSRichard Henderson size_t debug_frame_size) 103813da627SRichard Henderson __attribute__((unused)); 104813da627SRichard Henderson 105139c1837SPaolo Bonzini /* Forward declarations for functions declared and used in tcg-target.c.inc. */ 106069ea736SRichard Henderson static const char *target_parse_constraint(TCGArgConstraint *ct, 107069ea736SRichard Henderson const char *ct_str, TCGType type); 1082a534affSRichard Henderson static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1, 109a05b5b9bSRichard Henderson intptr_t arg2); 11078113e83SRichard Henderson static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg); 111c0ad3001SStefan Weil static void tcg_out_movi(TCGContext *s, TCGType type, 1122a534affSRichard Henderson TCGReg ret, tcg_target_long arg); 113c0ad3001SStefan Weil static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, 114c0ad3001SStefan Weil const int *const_args); 115d2fd745fSRichard Henderson #if TCG_TARGET_MAYBE_vec 116e7632cfaSRichard Henderson static bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece, 117e7632cfaSRichard Henderson TCGReg dst, TCGReg src); 118d6ecb4a9SRichard Henderson static bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece, 119d6ecb4a9SRichard Henderson TCGReg dst, TCGReg base, intptr_t offset); 120e7632cfaSRichard Henderson static void tcg_out_dupi_vec(TCGContext *s, TCGType type, 121e7632cfaSRichard Henderson TCGReg dst, tcg_target_long arg); 122d2fd745fSRichard Henderson static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc, unsigned vecl, 123d2fd745fSRichard Henderson unsigned vece, const TCGArg *args, 124d2fd745fSRichard Henderson const int *const_args); 125d2fd745fSRichard Henderson #else 126e7632cfaSRichard Henderson static inline bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece, 127e7632cfaSRichard Henderson TCGReg dst, TCGReg src) 128e7632cfaSRichard Henderson { 129e7632cfaSRichard Henderson g_assert_not_reached(); 130e7632cfaSRichard Henderson } 131d6ecb4a9SRichard Henderson static inline bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece, 132d6ecb4a9SRichard Henderson TCGReg dst, TCGReg base, intptr_t offset) 133d6ecb4a9SRichard Henderson { 134d6ecb4a9SRichard Henderson g_assert_not_reached(); 135d6ecb4a9SRichard Henderson } 136e7632cfaSRichard Henderson static inline void tcg_out_dupi_vec(TCGContext *s, TCGType type, 137e7632cfaSRichard Henderson TCGReg dst, tcg_target_long arg) 138e7632cfaSRichard Henderson { 139e7632cfaSRichard Henderson g_assert_not_reached(); 140e7632cfaSRichard Henderson } 141d2fd745fSRichard Henderson static inline void tcg_out_vec_op(TCGContext *s, TCGOpcode opc, unsigned vecl, 142d2fd745fSRichard Henderson unsigned vece, const TCGArg *args, 143d2fd745fSRichard Henderson const int *const_args) 144d2fd745fSRichard Henderson { 145d2fd745fSRichard Henderson g_assert_not_reached(); 146d2fd745fSRichard Henderson } 147d2fd745fSRichard Henderson #endif 1482a534affSRichard Henderson static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1, 149a05b5b9bSRichard Henderson intptr_t arg2); 15059d7c14eSRichard Henderson static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val, 15159d7c14eSRichard Henderson TCGReg base, intptr_t ofs); 152cf066674SRichard Henderson static void tcg_out_call(TCGContext *s, tcg_insn_unit *target); 153f6c6afc1SRichard Henderson static int tcg_target_const_match(tcg_target_long val, TCGType type, 154c0ad3001SStefan Weil const TCGArgConstraint *arg_ct); 155659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS 156aeee05f5SRichard Henderson static int tcg_out_ldst_finalize(TCGContext *s); 157659ef5cbSRichard Henderson #endif 158c896fe29Sbellard 159a505785cSEmilio G. Cota #define TCG_HIGHWATER 1024 160a505785cSEmilio G. Cota 161df2cce29SEmilio G. Cota static TCGContext **tcg_ctxs; 162df2cce29SEmilio G. Cota static unsigned int n_tcg_ctxs; 1631c2adb95SRichard Henderson TCGv_env cpu_env = 0; 164df2cce29SEmilio G. Cota 165be2cdc5eSEmilio G. Cota struct tcg_region_tree { 166be2cdc5eSEmilio G. Cota QemuMutex lock; 167be2cdc5eSEmilio G. Cota GTree *tree; 168be2cdc5eSEmilio G. Cota /* padding to avoid false sharing is computed at run-time */ 169be2cdc5eSEmilio G. Cota }; 170be2cdc5eSEmilio G. Cota 171e8feb96fSEmilio G. Cota /* 172e8feb96fSEmilio G. Cota * We divide code_gen_buffer into equally-sized "regions" that TCG threads 173e8feb96fSEmilio G. Cota * dynamically allocate from as demand dictates. Given appropriate region 174e8feb96fSEmilio G. Cota * sizing, this minimizes flushes even when some TCG threads generate a lot 175e8feb96fSEmilio G. Cota * more code than others. 176e8feb96fSEmilio G. Cota */ 177e8feb96fSEmilio G. Cota struct tcg_region_state { 178e8feb96fSEmilio G. Cota QemuMutex lock; 179e8feb96fSEmilio G. Cota 180e8feb96fSEmilio G. Cota /* fields set at init time */ 181e8feb96fSEmilio G. Cota void *start; 182e8feb96fSEmilio G. Cota void *start_aligned; 183e8feb96fSEmilio G. Cota void *end; 184e8feb96fSEmilio G. Cota size_t n; 185e8feb96fSEmilio G. Cota size_t size; /* size of one region */ 186e8feb96fSEmilio G. Cota size_t stride; /* .size + guard size */ 187e8feb96fSEmilio G. Cota 188e8feb96fSEmilio G. Cota /* fields protected by the lock */ 189e8feb96fSEmilio G. Cota size_t current; /* current region index */ 190e8feb96fSEmilio G. Cota size_t agg_size_full; /* aggregate size of full regions */ 191e8feb96fSEmilio G. Cota }; 192e8feb96fSEmilio G. Cota 193e8feb96fSEmilio G. Cota static struct tcg_region_state region; 194be2cdc5eSEmilio G. Cota /* 195be2cdc5eSEmilio G. Cota * This is an array of struct tcg_region_tree's, with padding. 196be2cdc5eSEmilio G. Cota * We use void * to simplify the computation of region_trees[i]; each 197be2cdc5eSEmilio G. Cota * struct is found every tree_size bytes. 198be2cdc5eSEmilio G. Cota */ 199be2cdc5eSEmilio G. Cota static void *region_trees; 200be2cdc5eSEmilio G. Cota static size_t tree_size; 201d2fd745fSRichard Henderson static TCGRegSet tcg_target_available_regs[TCG_TYPE_COUNT]; 202b1d8e52eSblueswir1 static TCGRegSet tcg_target_call_clobber_regs; 203c896fe29Sbellard 2041813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE == 1 2054196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out8(TCGContext *s, uint8_t v) 206c896fe29Sbellard { 207c896fe29Sbellard *s->code_ptr++ = v; 208c896fe29Sbellard } 209c896fe29Sbellard 2104196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch8(tcg_insn_unit *p, 2114196dca6SPeter Maydell uint8_t v) 2125c53bb81SPeter Maydell { 2131813e175SRichard Henderson *p = v; 2145c53bb81SPeter Maydell } 2151813e175SRichard Henderson #endif 2165c53bb81SPeter Maydell 2171813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 2 2184196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out16(TCGContext *s, uint16_t v) 219c896fe29Sbellard { 2201813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 2) { 2211813e175SRichard Henderson *s->code_ptr++ = v; 2221813e175SRichard Henderson } else { 2231813e175SRichard Henderson tcg_insn_unit *p = s->code_ptr; 2244387345aSPeter Maydell memcpy(p, &v, sizeof(v)); 2251813e175SRichard Henderson s->code_ptr = p + (2 / TCG_TARGET_INSN_UNIT_SIZE); 2261813e175SRichard Henderson } 227c896fe29Sbellard } 228c896fe29Sbellard 2294196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch16(tcg_insn_unit *p, 2304196dca6SPeter Maydell uint16_t v) 2315c53bb81SPeter Maydell { 2321813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 2) { 2331813e175SRichard Henderson *p = v; 2341813e175SRichard Henderson } else { 2355c53bb81SPeter Maydell memcpy(p, &v, sizeof(v)); 2365c53bb81SPeter Maydell } 2371813e175SRichard Henderson } 2381813e175SRichard Henderson #endif 2395c53bb81SPeter Maydell 2401813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 4 2414196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out32(TCGContext *s, uint32_t v) 242c896fe29Sbellard { 2431813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 4) { 2441813e175SRichard Henderson *s->code_ptr++ = v; 2451813e175SRichard Henderson } else { 2461813e175SRichard Henderson tcg_insn_unit *p = s->code_ptr; 2474387345aSPeter Maydell memcpy(p, &v, sizeof(v)); 2481813e175SRichard Henderson s->code_ptr = p + (4 / TCG_TARGET_INSN_UNIT_SIZE); 2491813e175SRichard Henderson } 250c896fe29Sbellard } 251c896fe29Sbellard 2524196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch32(tcg_insn_unit *p, 2534196dca6SPeter Maydell uint32_t v) 2545c53bb81SPeter Maydell { 2551813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 4) { 2561813e175SRichard Henderson *p = v; 2571813e175SRichard Henderson } else { 2585c53bb81SPeter Maydell memcpy(p, &v, sizeof(v)); 2595c53bb81SPeter Maydell } 2601813e175SRichard Henderson } 2611813e175SRichard Henderson #endif 2625c53bb81SPeter Maydell 2631813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 8 2644196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out64(TCGContext *s, uint64_t v) 265ac26eb69SRichard Henderson { 2661813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 8) { 2671813e175SRichard Henderson *s->code_ptr++ = v; 2681813e175SRichard Henderson } else { 2691813e175SRichard Henderson tcg_insn_unit *p = s->code_ptr; 2704387345aSPeter Maydell memcpy(p, &v, sizeof(v)); 2711813e175SRichard Henderson s->code_ptr = p + (8 / TCG_TARGET_INSN_UNIT_SIZE); 2721813e175SRichard Henderson } 273ac26eb69SRichard Henderson } 274ac26eb69SRichard Henderson 2754196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch64(tcg_insn_unit *p, 2764196dca6SPeter Maydell uint64_t v) 2775c53bb81SPeter Maydell { 2781813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 8) { 2791813e175SRichard Henderson *p = v; 2801813e175SRichard Henderson } else { 2815c53bb81SPeter Maydell memcpy(p, &v, sizeof(v)); 2825c53bb81SPeter Maydell } 2831813e175SRichard Henderson } 2841813e175SRichard Henderson #endif 2855c53bb81SPeter Maydell 286c896fe29Sbellard /* label relocation processing */ 287c896fe29Sbellard 2881813e175SRichard Henderson static void tcg_out_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type, 289bec16311SRichard Henderson TCGLabel *l, intptr_t addend) 290c896fe29Sbellard { 2917ecd02a0SRichard Henderson TCGRelocation *r = tcg_malloc(sizeof(TCGRelocation)); 292c896fe29Sbellard 293c896fe29Sbellard r->type = type; 294c896fe29Sbellard r->ptr = code_ptr; 295c896fe29Sbellard r->addend = addend; 2967ecd02a0SRichard Henderson QSIMPLEQ_INSERT_TAIL(&l->relocs, r, next); 297c896fe29Sbellard } 298c896fe29Sbellard 299bec16311SRichard Henderson static void tcg_out_label(TCGContext *s, TCGLabel *l, tcg_insn_unit *ptr) 300c896fe29Sbellard { 301eabb7b91SAurelien Jarno tcg_debug_assert(!l->has_value); 302c896fe29Sbellard l->has_value = 1; 3031813e175SRichard Henderson l->u.value_ptr = ptr; 304c896fe29Sbellard } 305c896fe29Sbellard 30642a268c2SRichard Henderson TCGLabel *gen_new_label(void) 307c896fe29Sbellard { 308b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 30951e3972cSRichard Henderson TCGLabel *l = tcg_malloc(sizeof(TCGLabel)); 310c896fe29Sbellard 3117ecd02a0SRichard Henderson memset(l, 0, sizeof(TCGLabel)); 3127ecd02a0SRichard Henderson l->id = s->nb_labels++; 3137ecd02a0SRichard Henderson QSIMPLEQ_INIT(&l->relocs); 3147ecd02a0SRichard Henderson 315bef16ab4SRichard Henderson QSIMPLEQ_INSERT_TAIL(&s->labels, l, next); 31642a268c2SRichard Henderson 31742a268c2SRichard Henderson return l; 318c896fe29Sbellard } 319c896fe29Sbellard 3207ecd02a0SRichard Henderson static bool tcg_resolve_relocs(TCGContext *s) 3217ecd02a0SRichard Henderson { 3227ecd02a0SRichard Henderson TCGLabel *l; 3237ecd02a0SRichard Henderson 3247ecd02a0SRichard Henderson QSIMPLEQ_FOREACH(l, &s->labels, next) { 3257ecd02a0SRichard Henderson TCGRelocation *r; 3267ecd02a0SRichard Henderson uintptr_t value = l->u.value; 3277ecd02a0SRichard Henderson 3287ecd02a0SRichard Henderson QSIMPLEQ_FOREACH(r, &l->relocs, next) { 3297ecd02a0SRichard Henderson if (!patch_reloc(r->ptr, r->type, value, r->addend)) { 3307ecd02a0SRichard Henderson return false; 3317ecd02a0SRichard Henderson } 3327ecd02a0SRichard Henderson } 3337ecd02a0SRichard Henderson } 3347ecd02a0SRichard Henderson return true; 3357ecd02a0SRichard Henderson } 3367ecd02a0SRichard Henderson 3379f754620SRichard Henderson static void set_jmp_reset_offset(TCGContext *s, int which) 3389f754620SRichard Henderson { 339f14bed3fSRichard Henderson /* 340f14bed3fSRichard Henderson * We will check for overflow at the end of the opcode loop in 341f14bed3fSRichard Henderson * tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX. 342f14bed3fSRichard Henderson */ 343f14bed3fSRichard Henderson s->tb_jmp_reset_offset[which] = tcg_current_code_size(s); 3449f754620SRichard Henderson } 3459f754620SRichard Henderson 346139c1837SPaolo Bonzini #include "tcg-target.c.inc" 347c896fe29Sbellard 348be2cdc5eSEmilio G. Cota /* compare a pointer @ptr and a tb_tc @s */ 349be2cdc5eSEmilio G. Cota static int ptr_cmp_tb_tc(const void *ptr, const struct tb_tc *s) 350be2cdc5eSEmilio G. Cota { 351be2cdc5eSEmilio G. Cota if (ptr >= s->ptr + s->size) { 352be2cdc5eSEmilio G. Cota return 1; 353be2cdc5eSEmilio G. Cota } else if (ptr < s->ptr) { 354be2cdc5eSEmilio G. Cota return -1; 355be2cdc5eSEmilio G. Cota } 356be2cdc5eSEmilio G. Cota return 0; 357be2cdc5eSEmilio G. Cota } 358be2cdc5eSEmilio G. Cota 359be2cdc5eSEmilio G. Cota static gint tb_tc_cmp(gconstpointer ap, gconstpointer bp) 360be2cdc5eSEmilio G. Cota { 361be2cdc5eSEmilio G. Cota const struct tb_tc *a = ap; 362be2cdc5eSEmilio G. Cota const struct tb_tc *b = bp; 363be2cdc5eSEmilio G. Cota 364be2cdc5eSEmilio G. Cota /* 365be2cdc5eSEmilio G. Cota * When both sizes are set, we know this isn't a lookup. 366be2cdc5eSEmilio G. Cota * This is the most likely case: every TB must be inserted; lookups 367be2cdc5eSEmilio G. Cota * are a lot less frequent. 368be2cdc5eSEmilio G. Cota */ 369be2cdc5eSEmilio G. Cota if (likely(a->size && b->size)) { 370be2cdc5eSEmilio G. Cota if (a->ptr > b->ptr) { 371be2cdc5eSEmilio G. Cota return 1; 372be2cdc5eSEmilio G. Cota } else if (a->ptr < b->ptr) { 373be2cdc5eSEmilio G. Cota return -1; 374be2cdc5eSEmilio G. Cota } 375be2cdc5eSEmilio G. Cota /* a->ptr == b->ptr should happen only on deletions */ 376be2cdc5eSEmilio G. Cota g_assert(a->size == b->size); 377be2cdc5eSEmilio G. Cota return 0; 378be2cdc5eSEmilio G. Cota } 379be2cdc5eSEmilio G. Cota /* 380be2cdc5eSEmilio G. Cota * All lookups have either .size field set to 0. 381be2cdc5eSEmilio G. Cota * From the glib sources we see that @ap is always the lookup key. However 382be2cdc5eSEmilio G. Cota * the docs provide no guarantee, so we just mark this case as likely. 383be2cdc5eSEmilio G. Cota */ 384be2cdc5eSEmilio G. Cota if (likely(a->size == 0)) { 385be2cdc5eSEmilio G. Cota return ptr_cmp_tb_tc(a->ptr, b); 386be2cdc5eSEmilio G. Cota } 387be2cdc5eSEmilio G. Cota return ptr_cmp_tb_tc(b->ptr, a); 388be2cdc5eSEmilio G. Cota } 389be2cdc5eSEmilio G. Cota 390be2cdc5eSEmilio G. Cota static void tcg_region_trees_init(void) 391be2cdc5eSEmilio G. Cota { 392be2cdc5eSEmilio G. Cota size_t i; 393be2cdc5eSEmilio G. Cota 394be2cdc5eSEmilio G. Cota tree_size = ROUND_UP(sizeof(struct tcg_region_tree), qemu_dcache_linesize); 395be2cdc5eSEmilio G. Cota region_trees = qemu_memalign(qemu_dcache_linesize, region.n * tree_size); 396be2cdc5eSEmilio G. Cota for (i = 0; i < region.n; i++) { 397be2cdc5eSEmilio G. Cota struct tcg_region_tree *rt = region_trees + i * tree_size; 398be2cdc5eSEmilio G. Cota 399be2cdc5eSEmilio G. Cota qemu_mutex_init(&rt->lock); 400be2cdc5eSEmilio G. Cota rt->tree = g_tree_new(tb_tc_cmp); 401be2cdc5eSEmilio G. Cota } 402be2cdc5eSEmilio G. Cota } 403be2cdc5eSEmilio G. Cota 404be2cdc5eSEmilio G. Cota static struct tcg_region_tree *tc_ptr_to_region_tree(void *p) 405be2cdc5eSEmilio G. Cota { 406be2cdc5eSEmilio G. Cota size_t region_idx; 407be2cdc5eSEmilio G. Cota 408be2cdc5eSEmilio G. Cota if (p < region.start_aligned) { 409be2cdc5eSEmilio G. Cota region_idx = 0; 410be2cdc5eSEmilio G. Cota } else { 411be2cdc5eSEmilio G. Cota ptrdiff_t offset = p - region.start_aligned; 412be2cdc5eSEmilio G. Cota 413be2cdc5eSEmilio G. Cota if (offset > region.stride * (region.n - 1)) { 414be2cdc5eSEmilio G. Cota region_idx = region.n - 1; 415be2cdc5eSEmilio G. Cota } else { 416be2cdc5eSEmilio G. Cota region_idx = offset / region.stride; 417be2cdc5eSEmilio G. Cota } 418be2cdc5eSEmilio G. Cota } 419be2cdc5eSEmilio G. Cota return region_trees + region_idx * tree_size; 420be2cdc5eSEmilio G. Cota } 421be2cdc5eSEmilio G. Cota 422be2cdc5eSEmilio G. Cota void tcg_tb_insert(TranslationBlock *tb) 423be2cdc5eSEmilio G. Cota { 424be2cdc5eSEmilio G. Cota struct tcg_region_tree *rt = tc_ptr_to_region_tree(tb->tc.ptr); 425be2cdc5eSEmilio G. Cota 426be2cdc5eSEmilio G. Cota qemu_mutex_lock(&rt->lock); 427be2cdc5eSEmilio G. Cota g_tree_insert(rt->tree, &tb->tc, tb); 428be2cdc5eSEmilio G. Cota qemu_mutex_unlock(&rt->lock); 429be2cdc5eSEmilio G. Cota } 430be2cdc5eSEmilio G. Cota 431be2cdc5eSEmilio G. Cota void tcg_tb_remove(TranslationBlock *tb) 432be2cdc5eSEmilio G. Cota { 433be2cdc5eSEmilio G. Cota struct tcg_region_tree *rt = tc_ptr_to_region_tree(tb->tc.ptr); 434be2cdc5eSEmilio G. Cota 435be2cdc5eSEmilio G. Cota qemu_mutex_lock(&rt->lock); 436be2cdc5eSEmilio G. Cota g_tree_remove(rt->tree, &tb->tc); 437be2cdc5eSEmilio G. Cota qemu_mutex_unlock(&rt->lock); 438be2cdc5eSEmilio G. Cota } 439be2cdc5eSEmilio G. Cota 440be2cdc5eSEmilio G. Cota /* 441be2cdc5eSEmilio G. Cota * Find the TB 'tb' such that 442be2cdc5eSEmilio G. Cota * tb->tc.ptr <= tc_ptr < tb->tc.ptr + tb->tc.size 443be2cdc5eSEmilio G. Cota * Return NULL if not found. 444be2cdc5eSEmilio G. Cota */ 445be2cdc5eSEmilio G. Cota TranslationBlock *tcg_tb_lookup(uintptr_t tc_ptr) 446be2cdc5eSEmilio G. Cota { 447be2cdc5eSEmilio G. Cota struct tcg_region_tree *rt = tc_ptr_to_region_tree((void *)tc_ptr); 448be2cdc5eSEmilio G. Cota TranslationBlock *tb; 449be2cdc5eSEmilio G. Cota struct tb_tc s = { .ptr = (void *)tc_ptr }; 450be2cdc5eSEmilio G. Cota 451be2cdc5eSEmilio G. Cota qemu_mutex_lock(&rt->lock); 452be2cdc5eSEmilio G. Cota tb = g_tree_lookup(rt->tree, &s); 453be2cdc5eSEmilio G. Cota qemu_mutex_unlock(&rt->lock); 454be2cdc5eSEmilio G. Cota return tb; 455be2cdc5eSEmilio G. Cota } 456be2cdc5eSEmilio G. Cota 457be2cdc5eSEmilio G. Cota static void tcg_region_tree_lock_all(void) 458be2cdc5eSEmilio G. Cota { 459be2cdc5eSEmilio G. Cota size_t i; 460be2cdc5eSEmilio G. Cota 461be2cdc5eSEmilio G. Cota for (i = 0; i < region.n; i++) { 462be2cdc5eSEmilio G. Cota struct tcg_region_tree *rt = region_trees + i * tree_size; 463be2cdc5eSEmilio G. Cota 464be2cdc5eSEmilio G. Cota qemu_mutex_lock(&rt->lock); 465be2cdc5eSEmilio G. Cota } 466be2cdc5eSEmilio G. Cota } 467be2cdc5eSEmilio G. Cota 468be2cdc5eSEmilio G. Cota static void tcg_region_tree_unlock_all(void) 469be2cdc5eSEmilio G. Cota { 470be2cdc5eSEmilio G. Cota size_t i; 471be2cdc5eSEmilio G. Cota 472be2cdc5eSEmilio G. Cota for (i = 0; i < region.n; i++) { 473be2cdc5eSEmilio G. Cota struct tcg_region_tree *rt = region_trees + i * tree_size; 474be2cdc5eSEmilio G. Cota 475be2cdc5eSEmilio G. Cota qemu_mutex_unlock(&rt->lock); 476be2cdc5eSEmilio G. Cota } 477be2cdc5eSEmilio G. Cota } 478be2cdc5eSEmilio G. Cota 479be2cdc5eSEmilio G. Cota void tcg_tb_foreach(GTraverseFunc func, gpointer user_data) 480be2cdc5eSEmilio G. Cota { 481be2cdc5eSEmilio G. Cota size_t i; 482be2cdc5eSEmilio G. Cota 483be2cdc5eSEmilio G. Cota tcg_region_tree_lock_all(); 484be2cdc5eSEmilio G. Cota for (i = 0; i < region.n; i++) { 485be2cdc5eSEmilio G. Cota struct tcg_region_tree *rt = region_trees + i * tree_size; 486be2cdc5eSEmilio G. Cota 487be2cdc5eSEmilio G. Cota g_tree_foreach(rt->tree, func, user_data); 488be2cdc5eSEmilio G. Cota } 489be2cdc5eSEmilio G. Cota tcg_region_tree_unlock_all(); 490be2cdc5eSEmilio G. Cota } 491be2cdc5eSEmilio G. Cota 492be2cdc5eSEmilio G. Cota size_t tcg_nb_tbs(void) 493be2cdc5eSEmilio G. Cota { 494be2cdc5eSEmilio G. Cota size_t nb_tbs = 0; 495be2cdc5eSEmilio G. Cota size_t i; 496be2cdc5eSEmilio G. Cota 497be2cdc5eSEmilio G. Cota tcg_region_tree_lock_all(); 498be2cdc5eSEmilio G. Cota for (i = 0; i < region.n; i++) { 499be2cdc5eSEmilio G. Cota struct tcg_region_tree *rt = region_trees + i * tree_size; 500be2cdc5eSEmilio G. Cota 501be2cdc5eSEmilio G. Cota nb_tbs += g_tree_nnodes(rt->tree); 502be2cdc5eSEmilio G. Cota } 503be2cdc5eSEmilio G. Cota tcg_region_tree_unlock_all(); 504be2cdc5eSEmilio G. Cota return nb_tbs; 505be2cdc5eSEmilio G. Cota } 506be2cdc5eSEmilio G. Cota 507938e897aSEmilio G. Cota static gboolean tcg_region_tree_traverse(gpointer k, gpointer v, gpointer data) 508938e897aSEmilio G. Cota { 509938e897aSEmilio G. Cota TranslationBlock *tb = v; 510938e897aSEmilio G. Cota 511938e897aSEmilio G. Cota tb_destroy(tb); 512938e897aSEmilio G. Cota return FALSE; 513938e897aSEmilio G. Cota } 514938e897aSEmilio G. Cota 515be2cdc5eSEmilio G. Cota static void tcg_region_tree_reset_all(void) 516be2cdc5eSEmilio G. Cota { 517be2cdc5eSEmilio G. Cota size_t i; 518be2cdc5eSEmilio G. Cota 519be2cdc5eSEmilio G. Cota tcg_region_tree_lock_all(); 520be2cdc5eSEmilio G. Cota for (i = 0; i < region.n; i++) { 521be2cdc5eSEmilio G. Cota struct tcg_region_tree *rt = region_trees + i * tree_size; 522be2cdc5eSEmilio G. Cota 523938e897aSEmilio G. Cota g_tree_foreach(rt->tree, tcg_region_tree_traverse, NULL); 524be2cdc5eSEmilio G. Cota /* Increment the refcount first so that destroy acts as a reset */ 525be2cdc5eSEmilio G. Cota g_tree_ref(rt->tree); 526be2cdc5eSEmilio G. Cota g_tree_destroy(rt->tree); 527be2cdc5eSEmilio G. Cota } 528be2cdc5eSEmilio G. Cota tcg_region_tree_unlock_all(); 529be2cdc5eSEmilio G. Cota } 530be2cdc5eSEmilio G. Cota 531e8feb96fSEmilio G. Cota static void tcg_region_bounds(size_t curr_region, void **pstart, void **pend) 532e8feb96fSEmilio G. Cota { 533e8feb96fSEmilio G. Cota void *start, *end; 534e8feb96fSEmilio G. Cota 535e8feb96fSEmilio G. Cota start = region.start_aligned + curr_region * region.stride; 536e8feb96fSEmilio G. Cota end = start + region.size; 537e8feb96fSEmilio G. Cota 538e8feb96fSEmilio G. Cota if (curr_region == 0) { 539e8feb96fSEmilio G. Cota start = region.start; 540e8feb96fSEmilio G. Cota } 541e8feb96fSEmilio G. Cota if (curr_region == region.n - 1) { 542e8feb96fSEmilio G. Cota end = region.end; 543e8feb96fSEmilio G. Cota } 544e8feb96fSEmilio G. Cota 545e8feb96fSEmilio G. Cota *pstart = start; 546e8feb96fSEmilio G. Cota *pend = end; 547e8feb96fSEmilio G. Cota } 548e8feb96fSEmilio G. Cota 549e8feb96fSEmilio G. Cota static void tcg_region_assign(TCGContext *s, size_t curr_region) 550e8feb96fSEmilio G. Cota { 551e8feb96fSEmilio G. Cota void *start, *end; 552e8feb96fSEmilio G. Cota 553e8feb96fSEmilio G. Cota tcg_region_bounds(curr_region, &start, &end); 554e8feb96fSEmilio G. Cota 555e8feb96fSEmilio G. Cota s->code_gen_buffer = start; 556e8feb96fSEmilio G. Cota s->code_gen_ptr = start; 557e8feb96fSEmilio G. Cota s->code_gen_buffer_size = end - start; 558e8feb96fSEmilio G. Cota s->code_gen_highwater = end - TCG_HIGHWATER; 559e8feb96fSEmilio G. Cota } 560e8feb96fSEmilio G. Cota 561e8feb96fSEmilio G. Cota static bool tcg_region_alloc__locked(TCGContext *s) 562e8feb96fSEmilio G. Cota { 563e8feb96fSEmilio G. Cota if (region.current == region.n) { 564e8feb96fSEmilio G. Cota return true; 565e8feb96fSEmilio G. Cota } 566e8feb96fSEmilio G. Cota tcg_region_assign(s, region.current); 567e8feb96fSEmilio G. Cota region.current++; 568e8feb96fSEmilio G. Cota return false; 569e8feb96fSEmilio G. Cota } 570e8feb96fSEmilio G. Cota 571e8feb96fSEmilio G. Cota /* 572e8feb96fSEmilio G. Cota * Request a new region once the one in use has filled up. 573e8feb96fSEmilio G. Cota * Returns true on error. 574e8feb96fSEmilio G. Cota */ 575e8feb96fSEmilio G. Cota static bool tcg_region_alloc(TCGContext *s) 576e8feb96fSEmilio G. Cota { 577e8feb96fSEmilio G. Cota bool err; 578e8feb96fSEmilio G. Cota /* read the region size now; alloc__locked will overwrite it on success */ 579e8feb96fSEmilio G. Cota size_t size_full = s->code_gen_buffer_size; 580e8feb96fSEmilio G. Cota 581e8feb96fSEmilio G. Cota qemu_mutex_lock(®ion.lock); 582e8feb96fSEmilio G. Cota err = tcg_region_alloc__locked(s); 583e8feb96fSEmilio G. Cota if (!err) { 584e8feb96fSEmilio G. Cota region.agg_size_full += size_full - TCG_HIGHWATER; 585e8feb96fSEmilio G. Cota } 586e8feb96fSEmilio G. Cota qemu_mutex_unlock(®ion.lock); 587e8feb96fSEmilio G. Cota return err; 588e8feb96fSEmilio G. Cota } 589e8feb96fSEmilio G. Cota 590e8feb96fSEmilio G. Cota /* 591e8feb96fSEmilio G. Cota * Perform a context's first region allocation. 592e8feb96fSEmilio G. Cota * This function does _not_ increment region.agg_size_full. 593e8feb96fSEmilio G. Cota */ 594e8feb96fSEmilio G. Cota static inline bool tcg_region_initial_alloc__locked(TCGContext *s) 595e8feb96fSEmilio G. Cota { 596e8feb96fSEmilio G. Cota return tcg_region_alloc__locked(s); 597e8feb96fSEmilio G. Cota } 598e8feb96fSEmilio G. Cota 599e8feb96fSEmilio G. Cota /* Call from a safe-work context */ 600e8feb96fSEmilio G. Cota void tcg_region_reset_all(void) 601e8feb96fSEmilio G. Cota { 602d73415a3SStefan Hajnoczi unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs); 603e8feb96fSEmilio G. Cota unsigned int i; 604e8feb96fSEmilio G. Cota 605e8feb96fSEmilio G. Cota qemu_mutex_lock(®ion.lock); 606e8feb96fSEmilio G. Cota region.current = 0; 607e8feb96fSEmilio G. Cota region.agg_size_full = 0; 608e8feb96fSEmilio G. Cota 6093468b59eSEmilio G. Cota for (i = 0; i < n_ctxs; i++) { 610d73415a3SStefan Hajnoczi TCGContext *s = qatomic_read(&tcg_ctxs[i]); 6113468b59eSEmilio G. Cota bool err = tcg_region_initial_alloc__locked(s); 612e8feb96fSEmilio G. Cota 613e8feb96fSEmilio G. Cota g_assert(!err); 614e8feb96fSEmilio G. Cota } 615e8feb96fSEmilio G. Cota qemu_mutex_unlock(®ion.lock); 616be2cdc5eSEmilio G. Cota 617be2cdc5eSEmilio G. Cota tcg_region_tree_reset_all(); 618e8feb96fSEmilio G. Cota } 619e8feb96fSEmilio G. Cota 6203468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY 6213468b59eSEmilio G. Cota static size_t tcg_n_regions(void) 6223468b59eSEmilio G. Cota { 6233468b59eSEmilio G. Cota return 1; 6243468b59eSEmilio G. Cota } 6253468b59eSEmilio G. Cota #else 6263468b59eSEmilio G. Cota /* 6273468b59eSEmilio G. Cota * It is likely that some vCPUs will translate more code than others, so we 6283468b59eSEmilio G. Cota * first try to set more regions than max_cpus, with those regions being of 6293468b59eSEmilio G. Cota * reasonable size. If that's not possible we make do by evenly dividing 6303468b59eSEmilio G. Cota * the code_gen_buffer among the vCPUs. 6313468b59eSEmilio G. Cota */ 6323468b59eSEmilio G. Cota static size_t tcg_n_regions(void) 6333468b59eSEmilio G. Cota { 6343468b59eSEmilio G. Cota size_t i; 6353468b59eSEmilio G. Cota 6363468b59eSEmilio G. Cota /* Use a single region if all we have is one vCPU thread */ 6375cc8767dSLike Xu #if !defined(CONFIG_USER_ONLY) 6385cc8767dSLike Xu MachineState *ms = MACHINE(qdev_get_machine()); 6395cc8767dSLike Xu unsigned int max_cpus = ms->smp.max_cpus; 6405cc8767dSLike Xu #endif 6413468b59eSEmilio G. Cota if (max_cpus == 1 || !qemu_tcg_mttcg_enabled()) { 6423468b59eSEmilio G. Cota return 1; 6433468b59eSEmilio G. Cota } 6443468b59eSEmilio G. Cota 6453468b59eSEmilio G. Cota /* Try to have more regions than max_cpus, with each region being >= 2 MB */ 6463468b59eSEmilio G. Cota for (i = 8; i > 0; i--) { 6473468b59eSEmilio G. Cota size_t regions_per_thread = i; 6483468b59eSEmilio G. Cota size_t region_size; 6493468b59eSEmilio G. Cota 6503468b59eSEmilio G. Cota region_size = tcg_init_ctx.code_gen_buffer_size; 6513468b59eSEmilio G. Cota region_size /= max_cpus * regions_per_thread; 6523468b59eSEmilio G. Cota 6533468b59eSEmilio G. Cota if (region_size >= 2 * 1024u * 1024) { 6543468b59eSEmilio G. Cota return max_cpus * regions_per_thread; 6553468b59eSEmilio G. Cota } 6563468b59eSEmilio G. Cota } 6573468b59eSEmilio G. Cota /* If we can't, then just allocate one region per vCPU thread */ 6583468b59eSEmilio G. Cota return max_cpus; 6593468b59eSEmilio G. Cota } 6603468b59eSEmilio G. Cota #endif 6613468b59eSEmilio G. Cota 662e8feb96fSEmilio G. Cota /* 663e8feb96fSEmilio G. Cota * Initializes region partitioning. 664e8feb96fSEmilio G. Cota * 665e8feb96fSEmilio G. Cota * Called at init time from the parent thread (i.e. the one calling 666e8feb96fSEmilio G. Cota * tcg_context_init), after the target's TCG globals have been set. 6673468b59eSEmilio G. Cota * 6683468b59eSEmilio G. Cota * Region partitioning works by splitting code_gen_buffer into separate regions, 6693468b59eSEmilio G. Cota * and then assigning regions to TCG threads so that the threads can translate 6703468b59eSEmilio G. Cota * code in parallel without synchronization. 6713468b59eSEmilio G. Cota * 6723468b59eSEmilio G. Cota * In softmmu the number of TCG threads is bounded by max_cpus, so we use at 6733468b59eSEmilio G. Cota * least max_cpus regions in MTTCG. In !MTTCG we use a single region. 6743468b59eSEmilio G. Cota * Note that the TCG options from the command-line (i.e. -accel accel=tcg,[...]) 6753468b59eSEmilio G. Cota * must have been parsed before calling this function, since it calls 6763468b59eSEmilio G. Cota * qemu_tcg_mttcg_enabled(). 6773468b59eSEmilio G. Cota * 6783468b59eSEmilio G. Cota * In user-mode we use a single region. Having multiple regions in user-mode 6793468b59eSEmilio G. Cota * is not supported, because the number of vCPU threads (recall that each thread 6803468b59eSEmilio G. Cota * spawned by the guest corresponds to a vCPU thread) is only bounded by the 6813468b59eSEmilio G. Cota * OS, and usually this number is huge (tens of thousands is not uncommon). 6823468b59eSEmilio G. Cota * Thus, given this large bound on the number of vCPU threads and the fact 6833468b59eSEmilio G. Cota * that code_gen_buffer is allocated at compile-time, we cannot guarantee 6843468b59eSEmilio G. Cota * that the availability of at least one region per vCPU thread. 6853468b59eSEmilio G. Cota * 6863468b59eSEmilio G. Cota * However, this user-mode limitation is unlikely to be a significant problem 6873468b59eSEmilio G. Cota * in practice. Multi-threaded guests share most if not all of their translated 6883468b59eSEmilio G. Cota * code, which makes parallel code generation less appealing than in softmmu. 689e8feb96fSEmilio G. Cota */ 690e8feb96fSEmilio G. Cota void tcg_region_init(void) 691e8feb96fSEmilio G. Cota { 692e8feb96fSEmilio G. Cota void *buf = tcg_init_ctx.code_gen_buffer; 693e8feb96fSEmilio G. Cota void *aligned; 694e8feb96fSEmilio G. Cota size_t size = tcg_init_ctx.code_gen_buffer_size; 695e8feb96fSEmilio G. Cota size_t page_size = qemu_real_host_page_size; 696e8feb96fSEmilio G. Cota size_t region_size; 697e8feb96fSEmilio G. Cota size_t n_regions; 698e8feb96fSEmilio G. Cota size_t i; 699e8feb96fSEmilio G. Cota 7003468b59eSEmilio G. Cota n_regions = tcg_n_regions(); 701e8feb96fSEmilio G. Cota 702e8feb96fSEmilio G. Cota /* The first region will be 'aligned - buf' bytes larger than the others */ 703e8feb96fSEmilio G. Cota aligned = QEMU_ALIGN_PTR_UP(buf, page_size); 704e8feb96fSEmilio G. Cota g_assert(aligned < tcg_init_ctx.code_gen_buffer + size); 705e8feb96fSEmilio G. Cota /* 706e8feb96fSEmilio G. Cota * Make region_size a multiple of page_size, using aligned as the start. 707e8feb96fSEmilio G. Cota * As a result of this we might end up with a few extra pages at the end of 708e8feb96fSEmilio G. Cota * the buffer; we will assign those to the last region. 709e8feb96fSEmilio G. Cota */ 710e8feb96fSEmilio G. Cota region_size = (size - (aligned - buf)) / n_regions; 711e8feb96fSEmilio G. Cota region_size = QEMU_ALIGN_DOWN(region_size, page_size); 712e8feb96fSEmilio G. Cota 713e8feb96fSEmilio G. Cota /* A region must have at least 2 pages; one code, one guard */ 714e8feb96fSEmilio G. Cota g_assert(region_size >= 2 * page_size); 715e8feb96fSEmilio G. Cota 716e8feb96fSEmilio G. Cota /* init the region struct */ 717e8feb96fSEmilio G. Cota qemu_mutex_init(®ion.lock); 718e8feb96fSEmilio G. Cota region.n = n_regions; 719e8feb96fSEmilio G. Cota region.size = region_size - page_size; 720e8feb96fSEmilio G. Cota region.stride = region_size; 721e8feb96fSEmilio G. Cota region.start = buf; 722e8feb96fSEmilio G. Cota region.start_aligned = aligned; 723e8feb96fSEmilio G. Cota /* page-align the end, since its last page will be a guard page */ 724e8feb96fSEmilio G. Cota region.end = QEMU_ALIGN_PTR_DOWN(buf + size, page_size); 725e8feb96fSEmilio G. Cota /* account for that last guard page */ 726e8feb96fSEmilio G. Cota region.end -= page_size; 727e8feb96fSEmilio G. Cota 728e8feb96fSEmilio G. Cota /* set guard pages */ 729e8feb96fSEmilio G. Cota for (i = 0; i < region.n; i++) { 730e8feb96fSEmilio G. Cota void *start, *end; 731e8feb96fSEmilio G. Cota int rc; 732e8feb96fSEmilio G. Cota 733e8feb96fSEmilio G. Cota tcg_region_bounds(i, &start, &end); 734e8feb96fSEmilio G. Cota rc = qemu_mprotect_none(end, page_size); 735e8feb96fSEmilio G. Cota g_assert(!rc); 736e8feb96fSEmilio G. Cota } 737e8feb96fSEmilio G. Cota 738be2cdc5eSEmilio G. Cota tcg_region_trees_init(); 739be2cdc5eSEmilio G. Cota 7403468b59eSEmilio G. Cota /* In user-mode we support only one ctx, so do the initial allocation now */ 7413468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY 742e8feb96fSEmilio G. Cota { 743e8feb96fSEmilio G. Cota bool err = tcg_region_initial_alloc__locked(tcg_ctx); 744e8feb96fSEmilio G. Cota 745e8feb96fSEmilio G. Cota g_assert(!err); 746e8feb96fSEmilio G. Cota } 7473468b59eSEmilio G. Cota #endif 748e8feb96fSEmilio G. Cota } 749e8feb96fSEmilio G. Cota 75038b47b19SEmilio G. Cota static void alloc_tcg_plugin_context(TCGContext *s) 75138b47b19SEmilio G. Cota { 75238b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN 75338b47b19SEmilio G. Cota s->plugin_tb = g_new0(struct qemu_plugin_tb, 1); 75438b47b19SEmilio G. Cota s->plugin_tb->insns = 75538b47b19SEmilio G. Cota g_ptr_array_new_with_free_func(qemu_plugin_insn_cleanup_fn); 75638b47b19SEmilio G. Cota #endif 75738b47b19SEmilio G. Cota } 75838b47b19SEmilio G. Cota 759e8feb96fSEmilio G. Cota /* 7603468b59eSEmilio G. Cota * All TCG threads except the parent (i.e. the one that called tcg_context_init 7613468b59eSEmilio G. Cota * and registered the target's TCG globals) must register with this function 7623468b59eSEmilio G. Cota * before initiating translation. 7633468b59eSEmilio G. Cota * 7643468b59eSEmilio G. Cota * In user-mode we just point tcg_ctx to tcg_init_ctx. See the documentation 7653468b59eSEmilio G. Cota * of tcg_region_init() for the reasoning behind this. 7663468b59eSEmilio G. Cota * 7673468b59eSEmilio G. Cota * In softmmu each caller registers its context in tcg_ctxs[]. Note that in 7683468b59eSEmilio G. Cota * softmmu tcg_ctxs[] does not track tcg_ctx_init, since the initial context 7693468b59eSEmilio G. Cota * is not used anymore for translation once this function is called. 7703468b59eSEmilio G. Cota * 7713468b59eSEmilio G. Cota * Not tracking tcg_init_ctx in tcg_ctxs[] in softmmu keeps code that iterates 7723468b59eSEmilio G. Cota * over the array (e.g. tcg_code_size() the same for both softmmu and user-mode. 7733468b59eSEmilio G. Cota */ 7743468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY 7753468b59eSEmilio G. Cota void tcg_register_thread(void) 7763468b59eSEmilio G. Cota { 7773468b59eSEmilio G. Cota tcg_ctx = &tcg_init_ctx; 7783468b59eSEmilio G. Cota } 7793468b59eSEmilio G. Cota #else 7803468b59eSEmilio G. Cota void tcg_register_thread(void) 7813468b59eSEmilio G. Cota { 7825cc8767dSLike Xu MachineState *ms = MACHINE(qdev_get_machine()); 7833468b59eSEmilio G. Cota TCGContext *s = g_malloc(sizeof(*s)); 7843468b59eSEmilio G. Cota unsigned int i, n; 7853468b59eSEmilio G. Cota bool err; 7863468b59eSEmilio G. Cota 7873468b59eSEmilio G. Cota *s = tcg_init_ctx; 7883468b59eSEmilio G. Cota 7893468b59eSEmilio G. Cota /* Relink mem_base. */ 7903468b59eSEmilio G. Cota for (i = 0, n = tcg_init_ctx.nb_globals; i < n; ++i) { 7913468b59eSEmilio G. Cota if (tcg_init_ctx.temps[i].mem_base) { 7923468b59eSEmilio G. Cota ptrdiff_t b = tcg_init_ctx.temps[i].mem_base - tcg_init_ctx.temps; 7933468b59eSEmilio G. Cota tcg_debug_assert(b >= 0 && b < n); 7943468b59eSEmilio G. Cota s->temps[i].mem_base = &s->temps[b]; 7953468b59eSEmilio G. Cota } 7963468b59eSEmilio G. Cota } 7973468b59eSEmilio G. Cota 7983468b59eSEmilio G. Cota /* Claim an entry in tcg_ctxs */ 799d73415a3SStefan Hajnoczi n = qatomic_fetch_inc(&n_tcg_ctxs); 8005cc8767dSLike Xu g_assert(n < ms->smp.max_cpus); 801d73415a3SStefan Hajnoczi qatomic_set(&tcg_ctxs[n], s); 8023468b59eSEmilio G. Cota 80338b47b19SEmilio G. Cota if (n > 0) { 80438b47b19SEmilio G. Cota alloc_tcg_plugin_context(s); 80538b47b19SEmilio G. Cota } 80638b47b19SEmilio G. Cota 8073468b59eSEmilio G. Cota tcg_ctx = s; 8083468b59eSEmilio G. Cota qemu_mutex_lock(®ion.lock); 8093468b59eSEmilio G. Cota err = tcg_region_initial_alloc__locked(tcg_ctx); 8103468b59eSEmilio G. Cota g_assert(!err); 8113468b59eSEmilio G. Cota qemu_mutex_unlock(®ion.lock); 8123468b59eSEmilio G. Cota } 8133468b59eSEmilio G. Cota #endif /* !CONFIG_USER_ONLY */ 8143468b59eSEmilio G. Cota 8153468b59eSEmilio G. Cota /* 816e8feb96fSEmilio G. Cota * Returns the size (in bytes) of all translated code (i.e. from all regions) 817e8feb96fSEmilio G. Cota * currently in the cache. 818e8feb96fSEmilio G. Cota * See also: tcg_code_capacity() 819e8feb96fSEmilio G. Cota * Do not confuse with tcg_current_code_size(); that one applies to a single 820e8feb96fSEmilio G. Cota * TCG context. 821e8feb96fSEmilio G. Cota */ 822e8feb96fSEmilio G. Cota size_t tcg_code_size(void) 823e8feb96fSEmilio G. Cota { 824d73415a3SStefan Hajnoczi unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs); 825e8feb96fSEmilio G. Cota unsigned int i; 826e8feb96fSEmilio G. Cota size_t total; 827e8feb96fSEmilio G. Cota 828e8feb96fSEmilio G. Cota qemu_mutex_lock(®ion.lock); 829e8feb96fSEmilio G. Cota total = region.agg_size_full; 8303468b59eSEmilio G. Cota for (i = 0; i < n_ctxs; i++) { 831d73415a3SStefan Hajnoczi const TCGContext *s = qatomic_read(&tcg_ctxs[i]); 832e8feb96fSEmilio G. Cota size_t size; 833e8feb96fSEmilio G. Cota 834d73415a3SStefan Hajnoczi size = qatomic_read(&s->code_gen_ptr) - s->code_gen_buffer; 835e8feb96fSEmilio G. Cota g_assert(size <= s->code_gen_buffer_size); 836e8feb96fSEmilio G. Cota total += size; 837e8feb96fSEmilio G. Cota } 838e8feb96fSEmilio G. Cota qemu_mutex_unlock(®ion.lock); 839e8feb96fSEmilio G. Cota return total; 840e8feb96fSEmilio G. Cota } 841e8feb96fSEmilio G. Cota 842e8feb96fSEmilio G. Cota /* 843e8feb96fSEmilio G. Cota * Returns the code capacity (in bytes) of the entire cache, i.e. including all 844e8feb96fSEmilio G. Cota * regions. 845e8feb96fSEmilio G. Cota * See also: tcg_code_size() 846e8feb96fSEmilio G. Cota */ 847e8feb96fSEmilio G. Cota size_t tcg_code_capacity(void) 848e8feb96fSEmilio G. Cota { 849e8feb96fSEmilio G. Cota size_t guard_size, capacity; 850e8feb96fSEmilio G. Cota 851e8feb96fSEmilio G. Cota /* no need for synchronization; these variables are set at init time */ 852e8feb96fSEmilio G. Cota guard_size = region.stride - region.size; 853e8feb96fSEmilio G. Cota capacity = region.end + guard_size - region.start; 854e8feb96fSEmilio G. Cota capacity -= region.n * (guard_size + TCG_HIGHWATER); 855e8feb96fSEmilio G. Cota return capacity; 856e8feb96fSEmilio G. Cota } 857e8feb96fSEmilio G. Cota 858128ed227SEmilio G. Cota size_t tcg_tb_phys_invalidate_count(void) 859128ed227SEmilio G. Cota { 860d73415a3SStefan Hajnoczi unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs); 861128ed227SEmilio G. Cota unsigned int i; 862128ed227SEmilio G. Cota size_t total = 0; 863128ed227SEmilio G. Cota 864128ed227SEmilio G. Cota for (i = 0; i < n_ctxs; i++) { 865d73415a3SStefan Hajnoczi const TCGContext *s = qatomic_read(&tcg_ctxs[i]); 866128ed227SEmilio G. Cota 867d73415a3SStefan Hajnoczi total += qatomic_read(&s->tb_phys_invalidate_count); 868128ed227SEmilio G. Cota } 869128ed227SEmilio G. Cota return total; 870128ed227SEmilio G. Cota } 871128ed227SEmilio G. Cota 872c896fe29Sbellard /* pool based memory allocation */ 873c896fe29Sbellard void *tcg_malloc_internal(TCGContext *s, int size) 874c896fe29Sbellard { 875c896fe29Sbellard TCGPool *p; 876c896fe29Sbellard int pool_size; 877c896fe29Sbellard 878c896fe29Sbellard if (size > TCG_POOL_CHUNK_SIZE) { 879c896fe29Sbellard /* big malloc: insert a new pool (XXX: could optimize) */ 8807267c094SAnthony Liguori p = g_malloc(sizeof(TCGPool) + size); 881c896fe29Sbellard p->size = size; 8824055299eSKirill Batuzov p->next = s->pool_first_large; 8834055299eSKirill Batuzov s->pool_first_large = p; 8844055299eSKirill Batuzov return p->data; 885c896fe29Sbellard } else { 886c896fe29Sbellard p = s->pool_current; 887c896fe29Sbellard if (!p) { 888c896fe29Sbellard p = s->pool_first; 889c896fe29Sbellard if (!p) 890c896fe29Sbellard goto new_pool; 891c896fe29Sbellard } else { 892c896fe29Sbellard if (!p->next) { 893c896fe29Sbellard new_pool: 894c896fe29Sbellard pool_size = TCG_POOL_CHUNK_SIZE; 8957267c094SAnthony Liguori p = g_malloc(sizeof(TCGPool) + pool_size); 896c896fe29Sbellard p->size = pool_size; 897c896fe29Sbellard p->next = NULL; 898c896fe29Sbellard if (s->pool_current) 899c896fe29Sbellard s->pool_current->next = p; 900c896fe29Sbellard else 901c896fe29Sbellard s->pool_first = p; 902c896fe29Sbellard } else { 903c896fe29Sbellard p = p->next; 904c896fe29Sbellard } 905c896fe29Sbellard } 906c896fe29Sbellard } 907c896fe29Sbellard s->pool_current = p; 908c896fe29Sbellard s->pool_cur = p->data + size; 909c896fe29Sbellard s->pool_end = p->data + p->size; 910c896fe29Sbellard return p->data; 911c896fe29Sbellard } 912c896fe29Sbellard 913c896fe29Sbellard void tcg_pool_reset(TCGContext *s) 914c896fe29Sbellard { 9154055299eSKirill Batuzov TCGPool *p, *t; 9164055299eSKirill Batuzov for (p = s->pool_first_large; p; p = t) { 9174055299eSKirill Batuzov t = p->next; 9184055299eSKirill Batuzov g_free(p); 9194055299eSKirill Batuzov } 9204055299eSKirill Batuzov s->pool_first_large = NULL; 921c896fe29Sbellard s->pool_cur = s->pool_end = NULL; 922c896fe29Sbellard s->pool_current = NULL; 923c896fe29Sbellard } 924c896fe29Sbellard 925100b5e01SRichard Henderson typedef struct TCGHelperInfo { 926100b5e01SRichard Henderson void *func; 927100b5e01SRichard Henderson const char *name; 928afb49896SRichard Henderson unsigned flags; 929afb49896SRichard Henderson unsigned sizemask; 930100b5e01SRichard Henderson } TCGHelperInfo; 931100b5e01SRichard Henderson 9322ef6175aSRichard Henderson #include "exec/helper-proto.h" 9332ef6175aSRichard Henderson 934100b5e01SRichard Henderson static const TCGHelperInfo all_helpers[] = { 9352ef6175aSRichard Henderson #include "exec/helper-tcg.h" 936100b5e01SRichard Henderson }; 937619205fdSEmilio G. Cota static GHashTable *helper_table; 938100b5e01SRichard Henderson 93991478cefSRichard Henderson static int indirect_reg_alloc_order[ARRAY_SIZE(tcg_target_reg_alloc_order)]; 940f69d277eSRichard Henderson static void process_op_defs(TCGContext *s); 9411c2adb95SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type, 9421c2adb95SRichard Henderson TCGReg reg, const char *name); 94391478cefSRichard Henderson 944c896fe29Sbellard void tcg_context_init(TCGContext *s) 945c896fe29Sbellard { 946100b5e01SRichard Henderson int op, total_args, n, i; 947c896fe29Sbellard TCGOpDef *def; 948c896fe29Sbellard TCGArgConstraint *args_ct; 9491c2adb95SRichard Henderson TCGTemp *ts; 950c896fe29Sbellard 951c896fe29Sbellard memset(s, 0, sizeof(*s)); 952c896fe29Sbellard s->nb_globals = 0; 953c896fe29Sbellard 954c896fe29Sbellard /* Count total number of arguments and allocate the corresponding 955c896fe29Sbellard space */ 956c896fe29Sbellard total_args = 0; 957c896fe29Sbellard for(op = 0; op < NB_OPS; op++) { 958c896fe29Sbellard def = &tcg_op_defs[op]; 959c896fe29Sbellard n = def->nb_iargs + def->nb_oargs; 960c896fe29Sbellard total_args += n; 961c896fe29Sbellard } 962c896fe29Sbellard 963bc2b17e6SRichard Henderson args_ct = g_new0(TCGArgConstraint, total_args); 964c896fe29Sbellard 965c896fe29Sbellard for(op = 0; op < NB_OPS; op++) { 966c896fe29Sbellard def = &tcg_op_defs[op]; 967c896fe29Sbellard def->args_ct = args_ct; 968c896fe29Sbellard n = def->nb_iargs + def->nb_oargs; 969c896fe29Sbellard args_ct += n; 970c896fe29Sbellard } 971c896fe29Sbellard 9725cd8f621SRichard Henderson /* Register helpers. */ 97384fd9dd3SRichard Henderson /* Use g_direct_hash/equal for direct pointer comparisons on func. */ 974619205fdSEmilio G. Cota helper_table = g_hash_table_new(NULL, NULL); 97584fd9dd3SRichard Henderson 976100b5e01SRichard Henderson for (i = 0; i < ARRAY_SIZE(all_helpers); ++i) { 97784fd9dd3SRichard Henderson g_hash_table_insert(helper_table, (gpointer)all_helpers[i].func, 97872866e82SRichard Henderson (gpointer)&all_helpers[i]); 979100b5e01SRichard Henderson } 9805cd8f621SRichard Henderson 981c896fe29Sbellard tcg_target_init(s); 982f69d277eSRichard Henderson process_op_defs(s); 98391478cefSRichard Henderson 98491478cefSRichard Henderson /* Reverse the order of the saved registers, assuming they're all at 98591478cefSRichard Henderson the start of tcg_target_reg_alloc_order. */ 98691478cefSRichard Henderson for (n = 0; n < ARRAY_SIZE(tcg_target_reg_alloc_order); ++n) { 98791478cefSRichard Henderson int r = tcg_target_reg_alloc_order[n]; 98891478cefSRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, r)) { 98991478cefSRichard Henderson break; 99091478cefSRichard Henderson } 99191478cefSRichard Henderson } 99291478cefSRichard Henderson for (i = 0; i < n; ++i) { 99391478cefSRichard Henderson indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[n - 1 - i]; 99491478cefSRichard Henderson } 99591478cefSRichard Henderson for (; i < ARRAY_SIZE(tcg_target_reg_alloc_order); ++i) { 99691478cefSRichard Henderson indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[i]; 99791478cefSRichard Henderson } 998b1311c4aSEmilio G. Cota 99938b47b19SEmilio G. Cota alloc_tcg_plugin_context(s); 100038b47b19SEmilio G. Cota 1001b1311c4aSEmilio G. Cota tcg_ctx = s; 10023468b59eSEmilio G. Cota /* 10033468b59eSEmilio G. Cota * In user-mode we simply share the init context among threads, since we 10043468b59eSEmilio G. Cota * use a single region. See the documentation tcg_region_init() for the 10053468b59eSEmilio G. Cota * reasoning behind this. 10063468b59eSEmilio G. Cota * In softmmu we will have at most max_cpus TCG threads. 10073468b59eSEmilio G. Cota */ 10083468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY 1009df2cce29SEmilio G. Cota tcg_ctxs = &tcg_ctx; 1010df2cce29SEmilio G. Cota n_tcg_ctxs = 1; 10113468b59eSEmilio G. Cota #else 10125cc8767dSLike Xu MachineState *ms = MACHINE(qdev_get_machine()); 10135cc8767dSLike Xu unsigned int max_cpus = ms->smp.max_cpus; 10143468b59eSEmilio G. Cota tcg_ctxs = g_new(TCGContext *, max_cpus); 10153468b59eSEmilio G. Cota #endif 10161c2adb95SRichard Henderson 10171c2adb95SRichard Henderson tcg_debug_assert(!tcg_regset_test_reg(s->reserved_regs, TCG_AREG0)); 10181c2adb95SRichard Henderson ts = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, TCG_AREG0, "env"); 10191c2adb95SRichard Henderson cpu_env = temp_tcgv_ptr(ts); 10209002ec79SRichard Henderson } 1021b03cce8eSbellard 10226e3b2bfdSEmilio G. Cota /* 10236e3b2bfdSEmilio G. Cota * Allocate TBs right before their corresponding translated code, making 10246e3b2bfdSEmilio G. Cota * sure that TBs and code are on different cache lines. 10256e3b2bfdSEmilio G. Cota */ 10266e3b2bfdSEmilio G. Cota TranslationBlock *tcg_tb_alloc(TCGContext *s) 10276e3b2bfdSEmilio G. Cota { 10286e3b2bfdSEmilio G. Cota uintptr_t align = qemu_icache_linesize; 10296e3b2bfdSEmilio G. Cota TranslationBlock *tb; 10306e3b2bfdSEmilio G. Cota void *next; 10316e3b2bfdSEmilio G. Cota 1032e8feb96fSEmilio G. Cota retry: 10336e3b2bfdSEmilio G. Cota tb = (void *)ROUND_UP((uintptr_t)s->code_gen_ptr, align); 10346e3b2bfdSEmilio G. Cota next = (void *)ROUND_UP((uintptr_t)(tb + 1), align); 10356e3b2bfdSEmilio G. Cota 10366e3b2bfdSEmilio G. Cota if (unlikely(next > s->code_gen_highwater)) { 1037e8feb96fSEmilio G. Cota if (tcg_region_alloc(s)) { 10386e3b2bfdSEmilio G. Cota return NULL; 10396e3b2bfdSEmilio G. Cota } 1040e8feb96fSEmilio G. Cota goto retry; 1041e8feb96fSEmilio G. Cota } 1042d73415a3SStefan Hajnoczi qatomic_set(&s->code_gen_ptr, next); 104357a26946SRichard Henderson s->data_gen_ptr = NULL; 10446e3b2bfdSEmilio G. Cota return tb; 10456e3b2bfdSEmilio G. Cota } 10466e3b2bfdSEmilio G. Cota 10479002ec79SRichard Henderson void tcg_prologue_init(TCGContext *s) 10489002ec79SRichard Henderson { 10498163b749SRichard Henderson size_t prologue_size, total_size; 10508163b749SRichard Henderson void *buf0, *buf1; 10518163b749SRichard Henderson 10528163b749SRichard Henderson /* Put the prologue at the beginning of code_gen_buffer. */ 10538163b749SRichard Henderson buf0 = s->code_gen_buffer; 10545b38ee31SRichard Henderson total_size = s->code_gen_buffer_size; 10558163b749SRichard Henderson s->code_ptr = buf0; 10568163b749SRichard Henderson s->code_buf = buf0; 10575b38ee31SRichard Henderson s->data_gen_ptr = NULL; 10588163b749SRichard Henderson s->code_gen_prologue = buf0; 10598163b749SRichard Henderson 10605b38ee31SRichard Henderson /* Compute a high-water mark, at which we voluntarily flush the buffer 10615b38ee31SRichard Henderson and start over. The size here is arbitrary, significantly larger 10625b38ee31SRichard Henderson than we expect the code generation for any one opcode to require. */ 10635b38ee31SRichard Henderson s->code_gen_highwater = s->code_gen_buffer + (total_size - TCG_HIGHWATER); 10645b38ee31SRichard Henderson 10655b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS 10665b38ee31SRichard Henderson s->pool_labels = NULL; 10675b38ee31SRichard Henderson #endif 10685b38ee31SRichard Henderson 10698163b749SRichard Henderson /* Generate the prologue. */ 1070b03cce8eSbellard tcg_target_qemu_prologue(s); 10715b38ee31SRichard Henderson 10725b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS 10735b38ee31SRichard Henderson /* Allow the prologue to put e.g. guest_base into a pool entry. */ 10745b38ee31SRichard Henderson { 10751768987bSRichard Henderson int result = tcg_out_pool_finalize(s); 10761768987bSRichard Henderson tcg_debug_assert(result == 0); 10775b38ee31SRichard Henderson } 10785b38ee31SRichard Henderson #endif 10795b38ee31SRichard Henderson 10808163b749SRichard Henderson buf1 = s->code_ptr; 10818163b749SRichard Henderson flush_icache_range((uintptr_t)buf0, (uintptr_t)buf1); 10828163b749SRichard Henderson 10838163b749SRichard Henderson /* Deduct the prologue from the buffer. */ 10848163b749SRichard Henderson prologue_size = tcg_current_code_size(s); 10858163b749SRichard Henderson s->code_gen_ptr = buf1; 10868163b749SRichard Henderson s->code_gen_buffer = buf1; 10878163b749SRichard Henderson s->code_buf = buf1; 10885b38ee31SRichard Henderson total_size -= prologue_size; 10898163b749SRichard Henderson s->code_gen_buffer_size = total_size; 10908163b749SRichard Henderson 10918163b749SRichard Henderson tcg_register_jit(s->code_gen_buffer, total_size); 1092d6b64b2bSRichard Henderson 1093d6b64b2bSRichard Henderson #ifdef DEBUG_DISAS 1094d6b64b2bSRichard Henderson if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) { 1095fc59d2d8SRobert Foley FILE *logfile = qemu_log_lock(); 10968163b749SRichard Henderson qemu_log("PROLOGUE: [size=%zu]\n", prologue_size); 10975b38ee31SRichard Henderson if (s->data_gen_ptr) { 10985b38ee31SRichard Henderson size_t code_size = s->data_gen_ptr - buf0; 10995b38ee31SRichard Henderson size_t data_size = prologue_size - code_size; 11005b38ee31SRichard Henderson size_t i; 11015b38ee31SRichard Henderson 11024c389f6eSRichard Henderson log_disas(buf0, code_size); 11035b38ee31SRichard Henderson 11045b38ee31SRichard Henderson for (i = 0; i < data_size; i += sizeof(tcg_target_ulong)) { 11055b38ee31SRichard Henderson if (sizeof(tcg_target_ulong) == 8) { 11065b38ee31SRichard Henderson qemu_log("0x%08" PRIxPTR ": .quad 0x%016" PRIx64 "\n", 11075b38ee31SRichard Henderson (uintptr_t)s->data_gen_ptr + i, 11085b38ee31SRichard Henderson *(uint64_t *)(s->data_gen_ptr + i)); 11095b38ee31SRichard Henderson } else { 11105b38ee31SRichard Henderson qemu_log("0x%08" PRIxPTR ": .long 0x%08x\n", 11115b38ee31SRichard Henderson (uintptr_t)s->data_gen_ptr + i, 11125b38ee31SRichard Henderson *(uint32_t *)(s->data_gen_ptr + i)); 11135b38ee31SRichard Henderson } 11145b38ee31SRichard Henderson } 11155b38ee31SRichard Henderson } else { 11164c389f6eSRichard Henderson log_disas(buf0, prologue_size); 11175b38ee31SRichard Henderson } 1118d6b64b2bSRichard Henderson qemu_log("\n"); 1119d6b64b2bSRichard Henderson qemu_log_flush(); 1120fc59d2d8SRobert Foley qemu_log_unlock(logfile); 1121d6b64b2bSRichard Henderson } 1122d6b64b2bSRichard Henderson #endif 1123cedbcb01SEmilio G. Cota 1124cedbcb01SEmilio G. Cota /* Assert that goto_ptr is implemented completely. */ 1125cedbcb01SEmilio G. Cota if (TCG_TARGET_HAS_goto_ptr) { 1126cedbcb01SEmilio G. Cota tcg_debug_assert(s->code_gen_epilogue != NULL); 1127cedbcb01SEmilio G. Cota } 1128c896fe29Sbellard } 1129c896fe29Sbellard 1130c896fe29Sbellard void tcg_func_start(TCGContext *s) 1131c896fe29Sbellard { 1132c896fe29Sbellard tcg_pool_reset(s); 1133c896fe29Sbellard s->nb_temps = s->nb_globals; 11340ec9eabcSRichard Henderson 11350ec9eabcSRichard Henderson /* No temps have been previously allocated for size or locality. */ 11360ec9eabcSRichard Henderson memset(s->free_temps, 0, sizeof(s->free_temps)); 11370ec9eabcSRichard Henderson 1138abebf925SRichard Henderson s->nb_ops = 0; 1139c896fe29Sbellard s->nb_labels = 0; 1140c896fe29Sbellard s->current_frame_offset = s->frame_start; 1141c896fe29Sbellard 11420a209d4bSRichard Henderson #ifdef CONFIG_DEBUG_TCG 11430a209d4bSRichard Henderson s->goto_tb_issue_mask = 0; 11440a209d4bSRichard Henderson #endif 11450a209d4bSRichard Henderson 114615fa08f8SRichard Henderson QTAILQ_INIT(&s->ops); 114715fa08f8SRichard Henderson QTAILQ_INIT(&s->free_ops); 1148bef16ab4SRichard Henderson QSIMPLEQ_INIT(&s->labels); 1149c896fe29Sbellard } 1150c896fe29Sbellard 11517ca4b752SRichard Henderson static inline TCGTemp *tcg_temp_alloc(TCGContext *s) 11527ca4b752SRichard Henderson { 11537ca4b752SRichard Henderson int n = s->nb_temps++; 11547ca4b752SRichard Henderson tcg_debug_assert(n < TCG_MAX_TEMPS); 11557ca4b752SRichard Henderson return memset(&s->temps[n], 0, sizeof(TCGTemp)); 11567ca4b752SRichard Henderson } 11577ca4b752SRichard Henderson 11587ca4b752SRichard Henderson static inline TCGTemp *tcg_global_alloc(TCGContext *s) 11597ca4b752SRichard Henderson { 1160fa477d25SRichard Henderson TCGTemp *ts; 1161fa477d25SRichard Henderson 11627ca4b752SRichard Henderson tcg_debug_assert(s->nb_globals == s->nb_temps); 11637ca4b752SRichard Henderson s->nb_globals++; 1164fa477d25SRichard Henderson ts = tcg_temp_alloc(s); 1165fa477d25SRichard Henderson ts->temp_global = 1; 1166fa477d25SRichard Henderson 1167fa477d25SRichard Henderson return ts; 1168c896fe29Sbellard } 1169c896fe29Sbellard 1170085272b3SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type, 1171b6638662SRichard Henderson TCGReg reg, const char *name) 1172c896fe29Sbellard { 1173c896fe29Sbellard TCGTemp *ts; 1174c896fe29Sbellard 1175b3a62939SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && type != TCG_TYPE_I32) { 1176c896fe29Sbellard tcg_abort(); 1177b3a62939SRichard Henderson } 11787ca4b752SRichard Henderson 11797ca4b752SRichard Henderson ts = tcg_global_alloc(s); 1180c896fe29Sbellard ts->base_type = type; 1181c896fe29Sbellard ts->type = type; 1182c896fe29Sbellard ts->fixed_reg = 1; 1183c896fe29Sbellard ts->reg = reg; 1184c896fe29Sbellard ts->name = name; 1185c896fe29Sbellard tcg_regset_set_reg(s->reserved_regs, reg); 11867ca4b752SRichard Henderson 1187085272b3SRichard Henderson return ts; 1188a7812ae4Spbrook } 1189a7812ae4Spbrook 1190b6638662SRichard Henderson void tcg_set_frame(TCGContext *s, TCGReg reg, intptr_t start, intptr_t size) 1191a7812ae4Spbrook { 1192b3a62939SRichard Henderson s->frame_start = start; 1193b3a62939SRichard Henderson s->frame_end = start + size; 1194085272b3SRichard Henderson s->frame_temp 1195085272b3SRichard Henderson = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, reg, "_frame"); 1196b3a62939SRichard Henderson } 1197a7812ae4Spbrook 1198085272b3SRichard Henderson TCGTemp *tcg_global_mem_new_internal(TCGType type, TCGv_ptr base, 1199e1ccc054SRichard Henderson intptr_t offset, const char *name) 1200c896fe29Sbellard { 1201b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 1202dc41aa7dSRichard Henderson TCGTemp *base_ts = tcgv_ptr_temp(base); 12037ca4b752SRichard Henderson TCGTemp *ts = tcg_global_alloc(s); 1204b3915dbbSRichard Henderson int indirect_reg = 0, bigendian = 0; 12057ca4b752SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN 12067ca4b752SRichard Henderson bigendian = 1; 12077ca4b752SRichard Henderson #endif 1208c896fe29Sbellard 1209b3915dbbSRichard Henderson if (!base_ts->fixed_reg) { 12105a18407fSRichard Henderson /* We do not support double-indirect registers. */ 12115a18407fSRichard Henderson tcg_debug_assert(!base_ts->indirect_reg); 1212b3915dbbSRichard Henderson base_ts->indirect_base = 1; 12135a18407fSRichard Henderson s->nb_indirects += (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64 12145a18407fSRichard Henderson ? 2 : 1); 12155a18407fSRichard Henderson indirect_reg = 1; 1216b3915dbbSRichard Henderson } 1217b3915dbbSRichard Henderson 12187ca4b752SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) { 12197ca4b752SRichard Henderson TCGTemp *ts2 = tcg_global_alloc(s); 1220c896fe29Sbellard char buf[64]; 12217ca4b752SRichard Henderson 12227ca4b752SRichard Henderson ts->base_type = TCG_TYPE_I64; 1223c896fe29Sbellard ts->type = TCG_TYPE_I32; 1224b3915dbbSRichard Henderson ts->indirect_reg = indirect_reg; 1225c896fe29Sbellard ts->mem_allocated = 1; 1226b3a62939SRichard Henderson ts->mem_base = base_ts; 12277ca4b752SRichard Henderson ts->mem_offset = offset + bigendian * 4; 1228c896fe29Sbellard pstrcpy(buf, sizeof(buf), name); 1229c896fe29Sbellard pstrcat(buf, sizeof(buf), "_0"); 1230c896fe29Sbellard ts->name = strdup(buf); 1231c896fe29Sbellard 12327ca4b752SRichard Henderson tcg_debug_assert(ts2 == ts + 1); 12337ca4b752SRichard Henderson ts2->base_type = TCG_TYPE_I64; 12347ca4b752SRichard Henderson ts2->type = TCG_TYPE_I32; 1235b3915dbbSRichard Henderson ts2->indirect_reg = indirect_reg; 12367ca4b752SRichard Henderson ts2->mem_allocated = 1; 12377ca4b752SRichard Henderson ts2->mem_base = base_ts; 12387ca4b752SRichard Henderson ts2->mem_offset = offset + (1 - bigendian) * 4; 1239c896fe29Sbellard pstrcpy(buf, sizeof(buf), name); 1240c896fe29Sbellard pstrcat(buf, sizeof(buf), "_1"); 1241120c1084SRichard Henderson ts2->name = strdup(buf); 12427ca4b752SRichard Henderson } else { 1243c896fe29Sbellard ts->base_type = type; 1244c896fe29Sbellard ts->type = type; 1245b3915dbbSRichard Henderson ts->indirect_reg = indirect_reg; 1246c896fe29Sbellard ts->mem_allocated = 1; 1247b3a62939SRichard Henderson ts->mem_base = base_ts; 1248c896fe29Sbellard ts->mem_offset = offset; 1249c896fe29Sbellard ts->name = name; 1250c896fe29Sbellard } 1251085272b3SRichard Henderson return ts; 1252c896fe29Sbellard } 1253c896fe29Sbellard 12545bfa8034SRichard Henderson TCGTemp *tcg_temp_new_internal(TCGType type, bool temp_local) 1255c896fe29Sbellard { 1256b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 1257c896fe29Sbellard TCGTemp *ts; 1258641d5fbeSbellard int idx, k; 1259c896fe29Sbellard 12600ec9eabcSRichard Henderson k = type + (temp_local ? TCG_TYPE_COUNT : 0); 12610ec9eabcSRichard Henderson idx = find_first_bit(s->free_temps[k].l, TCG_MAX_TEMPS); 12620ec9eabcSRichard Henderson if (idx < TCG_MAX_TEMPS) { 12630ec9eabcSRichard Henderson /* There is already an available temp with the right type. */ 12640ec9eabcSRichard Henderson clear_bit(idx, s->free_temps[k].l); 12650ec9eabcSRichard Henderson 1266e8996ee0Sbellard ts = &s->temps[idx]; 1267e8996ee0Sbellard ts->temp_allocated = 1; 12687ca4b752SRichard Henderson tcg_debug_assert(ts->base_type == type); 12697ca4b752SRichard Henderson tcg_debug_assert(ts->temp_local == temp_local); 1270e8996ee0Sbellard } else { 12717ca4b752SRichard Henderson ts = tcg_temp_alloc(s); 12727ca4b752SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) { 12737ca4b752SRichard Henderson TCGTemp *ts2 = tcg_temp_alloc(s); 12747ca4b752SRichard Henderson 1275c896fe29Sbellard ts->base_type = type; 1276c896fe29Sbellard ts->type = TCG_TYPE_I32; 1277e8996ee0Sbellard ts->temp_allocated = 1; 1278641d5fbeSbellard ts->temp_local = temp_local; 12797ca4b752SRichard Henderson 12807ca4b752SRichard Henderson tcg_debug_assert(ts2 == ts + 1); 12817ca4b752SRichard Henderson ts2->base_type = TCG_TYPE_I64; 12827ca4b752SRichard Henderson ts2->type = TCG_TYPE_I32; 12837ca4b752SRichard Henderson ts2->temp_allocated = 1; 12847ca4b752SRichard Henderson ts2->temp_local = temp_local; 12857ca4b752SRichard Henderson } else { 1286c896fe29Sbellard ts->base_type = type; 1287c896fe29Sbellard ts->type = type; 1288e8996ee0Sbellard ts->temp_allocated = 1; 1289641d5fbeSbellard ts->temp_local = temp_local; 1290c896fe29Sbellard } 1291e8996ee0Sbellard } 129227bfd83cSPeter Maydell 129327bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG) 129427bfd83cSPeter Maydell s->temps_in_use++; 129527bfd83cSPeter Maydell #endif 1296085272b3SRichard Henderson return ts; 1297c896fe29Sbellard } 1298c896fe29Sbellard 1299d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec(TCGType type) 1300d2fd745fSRichard Henderson { 1301d2fd745fSRichard Henderson TCGTemp *t; 1302d2fd745fSRichard Henderson 1303d2fd745fSRichard Henderson #ifdef CONFIG_DEBUG_TCG 1304d2fd745fSRichard Henderson switch (type) { 1305d2fd745fSRichard Henderson case TCG_TYPE_V64: 1306d2fd745fSRichard Henderson assert(TCG_TARGET_HAS_v64); 1307d2fd745fSRichard Henderson break; 1308d2fd745fSRichard Henderson case TCG_TYPE_V128: 1309d2fd745fSRichard Henderson assert(TCG_TARGET_HAS_v128); 1310d2fd745fSRichard Henderson break; 1311d2fd745fSRichard Henderson case TCG_TYPE_V256: 1312d2fd745fSRichard Henderson assert(TCG_TARGET_HAS_v256); 1313d2fd745fSRichard Henderson break; 1314d2fd745fSRichard Henderson default: 1315d2fd745fSRichard Henderson g_assert_not_reached(); 1316d2fd745fSRichard Henderson } 1317d2fd745fSRichard Henderson #endif 1318d2fd745fSRichard Henderson 1319d2fd745fSRichard Henderson t = tcg_temp_new_internal(type, 0); 1320d2fd745fSRichard Henderson return temp_tcgv_vec(t); 1321d2fd745fSRichard Henderson } 1322d2fd745fSRichard Henderson 1323d2fd745fSRichard Henderson /* Create a new temp of the same type as an existing temp. */ 1324d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec_matching(TCGv_vec match) 1325d2fd745fSRichard Henderson { 1326d2fd745fSRichard Henderson TCGTemp *t = tcgv_vec_temp(match); 1327d2fd745fSRichard Henderson 1328d2fd745fSRichard Henderson tcg_debug_assert(t->temp_allocated != 0); 1329d2fd745fSRichard Henderson 1330d2fd745fSRichard Henderson t = tcg_temp_new_internal(t->base_type, 0); 1331d2fd745fSRichard Henderson return temp_tcgv_vec(t); 1332d2fd745fSRichard Henderson } 1333d2fd745fSRichard Henderson 13345bfa8034SRichard Henderson void tcg_temp_free_internal(TCGTemp *ts) 1335c896fe29Sbellard { 1336b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 1337085272b3SRichard Henderson int k, idx; 1338c896fe29Sbellard 133927bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG) 134027bfd83cSPeter Maydell s->temps_in_use--; 134127bfd83cSPeter Maydell if (s->temps_in_use < 0) { 134227bfd83cSPeter Maydell fprintf(stderr, "More temporaries freed than allocated!\n"); 134327bfd83cSPeter Maydell } 134427bfd83cSPeter Maydell #endif 134527bfd83cSPeter Maydell 1346085272b3SRichard Henderson tcg_debug_assert(ts->temp_global == 0); 1347eabb7b91SAurelien Jarno tcg_debug_assert(ts->temp_allocated != 0); 1348e8996ee0Sbellard ts->temp_allocated = 0; 13490ec9eabcSRichard Henderson 1350085272b3SRichard Henderson idx = temp_idx(ts); 135118d13fa2SAlexander Graf k = ts->base_type + (ts->temp_local ? TCG_TYPE_COUNT : 0); 13520ec9eabcSRichard Henderson set_bit(idx, s->free_temps[k].l); 1353e8996ee0Sbellard } 1354e8996ee0Sbellard 1355a7812ae4Spbrook TCGv_i32 tcg_const_i32(int32_t val) 1356a7812ae4Spbrook { 1357a7812ae4Spbrook TCGv_i32 t0; 1358a7812ae4Spbrook t0 = tcg_temp_new_i32(); 1359e8996ee0Sbellard tcg_gen_movi_i32(t0, val); 1360e8996ee0Sbellard return t0; 1361c896fe29Sbellard } 1362c896fe29Sbellard 1363a7812ae4Spbrook TCGv_i64 tcg_const_i64(int64_t val) 1364c896fe29Sbellard { 1365a7812ae4Spbrook TCGv_i64 t0; 1366a7812ae4Spbrook t0 = tcg_temp_new_i64(); 1367e8996ee0Sbellard tcg_gen_movi_i64(t0, val); 1368e8996ee0Sbellard return t0; 1369c896fe29Sbellard } 1370c896fe29Sbellard 1371a7812ae4Spbrook TCGv_i32 tcg_const_local_i32(int32_t val) 1372bdffd4a9Saurel32 { 1373a7812ae4Spbrook TCGv_i32 t0; 1374a7812ae4Spbrook t0 = tcg_temp_local_new_i32(); 1375bdffd4a9Saurel32 tcg_gen_movi_i32(t0, val); 1376bdffd4a9Saurel32 return t0; 1377bdffd4a9Saurel32 } 1378bdffd4a9Saurel32 1379a7812ae4Spbrook TCGv_i64 tcg_const_local_i64(int64_t val) 1380bdffd4a9Saurel32 { 1381a7812ae4Spbrook TCGv_i64 t0; 1382a7812ae4Spbrook t0 = tcg_temp_local_new_i64(); 1383bdffd4a9Saurel32 tcg_gen_movi_i64(t0, val); 1384bdffd4a9Saurel32 return t0; 1385bdffd4a9Saurel32 } 1386bdffd4a9Saurel32 138727bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG) 138827bfd83cSPeter Maydell void tcg_clear_temp_count(void) 138927bfd83cSPeter Maydell { 1390b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 139127bfd83cSPeter Maydell s->temps_in_use = 0; 139227bfd83cSPeter Maydell } 139327bfd83cSPeter Maydell 139427bfd83cSPeter Maydell int tcg_check_temp_count(void) 139527bfd83cSPeter Maydell { 1396b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 139727bfd83cSPeter Maydell if (s->temps_in_use) { 139827bfd83cSPeter Maydell /* Clear the count so that we don't give another 139927bfd83cSPeter Maydell * warning immediately next time around. 140027bfd83cSPeter Maydell */ 140127bfd83cSPeter Maydell s->temps_in_use = 0; 140227bfd83cSPeter Maydell return 1; 140327bfd83cSPeter Maydell } 140427bfd83cSPeter Maydell return 0; 140527bfd83cSPeter Maydell } 140627bfd83cSPeter Maydell #endif 140727bfd83cSPeter Maydell 1408be0f34b5SRichard Henderson /* Return true if OP may appear in the opcode stream. 1409be0f34b5SRichard Henderson Test the runtime variable that controls each opcode. */ 1410be0f34b5SRichard Henderson bool tcg_op_supported(TCGOpcode op) 1411be0f34b5SRichard Henderson { 1412d2fd745fSRichard Henderson const bool have_vec 1413d2fd745fSRichard Henderson = TCG_TARGET_HAS_v64 | TCG_TARGET_HAS_v128 | TCG_TARGET_HAS_v256; 1414d2fd745fSRichard Henderson 1415be0f34b5SRichard Henderson switch (op) { 1416be0f34b5SRichard Henderson case INDEX_op_discard: 1417be0f34b5SRichard Henderson case INDEX_op_set_label: 1418be0f34b5SRichard Henderson case INDEX_op_call: 1419be0f34b5SRichard Henderson case INDEX_op_br: 1420be0f34b5SRichard Henderson case INDEX_op_mb: 1421be0f34b5SRichard Henderson case INDEX_op_insn_start: 1422be0f34b5SRichard Henderson case INDEX_op_exit_tb: 1423be0f34b5SRichard Henderson case INDEX_op_goto_tb: 1424be0f34b5SRichard Henderson case INDEX_op_qemu_ld_i32: 1425be0f34b5SRichard Henderson case INDEX_op_qemu_st_i32: 1426be0f34b5SRichard Henderson case INDEX_op_qemu_ld_i64: 1427be0f34b5SRichard Henderson case INDEX_op_qemu_st_i64: 1428be0f34b5SRichard Henderson return true; 1429be0f34b5SRichard Henderson 1430be0f34b5SRichard Henderson case INDEX_op_goto_ptr: 1431be0f34b5SRichard Henderson return TCG_TARGET_HAS_goto_ptr; 1432be0f34b5SRichard Henderson 1433be0f34b5SRichard Henderson case INDEX_op_mov_i32: 1434be0f34b5SRichard Henderson case INDEX_op_movi_i32: 1435be0f34b5SRichard Henderson case INDEX_op_setcond_i32: 1436be0f34b5SRichard Henderson case INDEX_op_brcond_i32: 1437be0f34b5SRichard Henderson case INDEX_op_ld8u_i32: 1438be0f34b5SRichard Henderson case INDEX_op_ld8s_i32: 1439be0f34b5SRichard Henderson case INDEX_op_ld16u_i32: 1440be0f34b5SRichard Henderson case INDEX_op_ld16s_i32: 1441be0f34b5SRichard Henderson case INDEX_op_ld_i32: 1442be0f34b5SRichard Henderson case INDEX_op_st8_i32: 1443be0f34b5SRichard Henderson case INDEX_op_st16_i32: 1444be0f34b5SRichard Henderson case INDEX_op_st_i32: 1445be0f34b5SRichard Henderson case INDEX_op_add_i32: 1446be0f34b5SRichard Henderson case INDEX_op_sub_i32: 1447be0f34b5SRichard Henderson case INDEX_op_mul_i32: 1448be0f34b5SRichard Henderson case INDEX_op_and_i32: 1449be0f34b5SRichard Henderson case INDEX_op_or_i32: 1450be0f34b5SRichard Henderson case INDEX_op_xor_i32: 1451be0f34b5SRichard Henderson case INDEX_op_shl_i32: 1452be0f34b5SRichard Henderson case INDEX_op_shr_i32: 1453be0f34b5SRichard Henderson case INDEX_op_sar_i32: 1454be0f34b5SRichard Henderson return true; 1455be0f34b5SRichard Henderson 1456be0f34b5SRichard Henderson case INDEX_op_movcond_i32: 1457be0f34b5SRichard Henderson return TCG_TARGET_HAS_movcond_i32; 1458be0f34b5SRichard Henderson case INDEX_op_div_i32: 1459be0f34b5SRichard Henderson case INDEX_op_divu_i32: 1460be0f34b5SRichard Henderson return TCG_TARGET_HAS_div_i32; 1461be0f34b5SRichard Henderson case INDEX_op_rem_i32: 1462be0f34b5SRichard Henderson case INDEX_op_remu_i32: 1463be0f34b5SRichard Henderson return TCG_TARGET_HAS_rem_i32; 1464be0f34b5SRichard Henderson case INDEX_op_div2_i32: 1465be0f34b5SRichard Henderson case INDEX_op_divu2_i32: 1466be0f34b5SRichard Henderson return TCG_TARGET_HAS_div2_i32; 1467be0f34b5SRichard Henderson case INDEX_op_rotl_i32: 1468be0f34b5SRichard Henderson case INDEX_op_rotr_i32: 1469be0f34b5SRichard Henderson return TCG_TARGET_HAS_rot_i32; 1470be0f34b5SRichard Henderson case INDEX_op_deposit_i32: 1471be0f34b5SRichard Henderson return TCG_TARGET_HAS_deposit_i32; 1472be0f34b5SRichard Henderson case INDEX_op_extract_i32: 1473be0f34b5SRichard Henderson return TCG_TARGET_HAS_extract_i32; 1474be0f34b5SRichard Henderson case INDEX_op_sextract_i32: 1475be0f34b5SRichard Henderson return TCG_TARGET_HAS_sextract_i32; 1476fce1296fSRichard Henderson case INDEX_op_extract2_i32: 1477fce1296fSRichard Henderson return TCG_TARGET_HAS_extract2_i32; 1478be0f34b5SRichard Henderson case INDEX_op_add2_i32: 1479be0f34b5SRichard Henderson return TCG_TARGET_HAS_add2_i32; 1480be0f34b5SRichard Henderson case INDEX_op_sub2_i32: 1481be0f34b5SRichard Henderson return TCG_TARGET_HAS_sub2_i32; 1482be0f34b5SRichard Henderson case INDEX_op_mulu2_i32: 1483be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulu2_i32; 1484be0f34b5SRichard Henderson case INDEX_op_muls2_i32: 1485be0f34b5SRichard Henderson return TCG_TARGET_HAS_muls2_i32; 1486be0f34b5SRichard Henderson case INDEX_op_muluh_i32: 1487be0f34b5SRichard Henderson return TCG_TARGET_HAS_muluh_i32; 1488be0f34b5SRichard Henderson case INDEX_op_mulsh_i32: 1489be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulsh_i32; 1490be0f34b5SRichard Henderson case INDEX_op_ext8s_i32: 1491be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8s_i32; 1492be0f34b5SRichard Henderson case INDEX_op_ext16s_i32: 1493be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16s_i32; 1494be0f34b5SRichard Henderson case INDEX_op_ext8u_i32: 1495be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8u_i32; 1496be0f34b5SRichard Henderson case INDEX_op_ext16u_i32: 1497be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16u_i32; 1498be0f34b5SRichard Henderson case INDEX_op_bswap16_i32: 1499be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap16_i32; 1500be0f34b5SRichard Henderson case INDEX_op_bswap32_i32: 1501be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap32_i32; 1502be0f34b5SRichard Henderson case INDEX_op_not_i32: 1503be0f34b5SRichard Henderson return TCG_TARGET_HAS_not_i32; 1504be0f34b5SRichard Henderson case INDEX_op_neg_i32: 1505be0f34b5SRichard Henderson return TCG_TARGET_HAS_neg_i32; 1506be0f34b5SRichard Henderson case INDEX_op_andc_i32: 1507be0f34b5SRichard Henderson return TCG_TARGET_HAS_andc_i32; 1508be0f34b5SRichard Henderson case INDEX_op_orc_i32: 1509be0f34b5SRichard Henderson return TCG_TARGET_HAS_orc_i32; 1510be0f34b5SRichard Henderson case INDEX_op_eqv_i32: 1511be0f34b5SRichard Henderson return TCG_TARGET_HAS_eqv_i32; 1512be0f34b5SRichard Henderson case INDEX_op_nand_i32: 1513be0f34b5SRichard Henderson return TCG_TARGET_HAS_nand_i32; 1514be0f34b5SRichard Henderson case INDEX_op_nor_i32: 1515be0f34b5SRichard Henderson return TCG_TARGET_HAS_nor_i32; 1516be0f34b5SRichard Henderson case INDEX_op_clz_i32: 1517be0f34b5SRichard Henderson return TCG_TARGET_HAS_clz_i32; 1518be0f34b5SRichard Henderson case INDEX_op_ctz_i32: 1519be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctz_i32; 1520be0f34b5SRichard Henderson case INDEX_op_ctpop_i32: 1521be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctpop_i32; 1522be0f34b5SRichard Henderson 1523be0f34b5SRichard Henderson case INDEX_op_brcond2_i32: 1524be0f34b5SRichard Henderson case INDEX_op_setcond2_i32: 1525be0f34b5SRichard Henderson return TCG_TARGET_REG_BITS == 32; 1526be0f34b5SRichard Henderson 1527be0f34b5SRichard Henderson case INDEX_op_mov_i64: 1528be0f34b5SRichard Henderson case INDEX_op_movi_i64: 1529be0f34b5SRichard Henderson case INDEX_op_setcond_i64: 1530be0f34b5SRichard Henderson case INDEX_op_brcond_i64: 1531be0f34b5SRichard Henderson case INDEX_op_ld8u_i64: 1532be0f34b5SRichard Henderson case INDEX_op_ld8s_i64: 1533be0f34b5SRichard Henderson case INDEX_op_ld16u_i64: 1534be0f34b5SRichard Henderson case INDEX_op_ld16s_i64: 1535be0f34b5SRichard Henderson case INDEX_op_ld32u_i64: 1536be0f34b5SRichard Henderson case INDEX_op_ld32s_i64: 1537be0f34b5SRichard Henderson case INDEX_op_ld_i64: 1538be0f34b5SRichard Henderson case INDEX_op_st8_i64: 1539be0f34b5SRichard Henderson case INDEX_op_st16_i64: 1540be0f34b5SRichard Henderson case INDEX_op_st32_i64: 1541be0f34b5SRichard Henderson case INDEX_op_st_i64: 1542be0f34b5SRichard Henderson case INDEX_op_add_i64: 1543be0f34b5SRichard Henderson case INDEX_op_sub_i64: 1544be0f34b5SRichard Henderson case INDEX_op_mul_i64: 1545be0f34b5SRichard Henderson case INDEX_op_and_i64: 1546be0f34b5SRichard Henderson case INDEX_op_or_i64: 1547be0f34b5SRichard Henderson case INDEX_op_xor_i64: 1548be0f34b5SRichard Henderson case INDEX_op_shl_i64: 1549be0f34b5SRichard Henderson case INDEX_op_shr_i64: 1550be0f34b5SRichard Henderson case INDEX_op_sar_i64: 1551be0f34b5SRichard Henderson case INDEX_op_ext_i32_i64: 1552be0f34b5SRichard Henderson case INDEX_op_extu_i32_i64: 1553be0f34b5SRichard Henderson return TCG_TARGET_REG_BITS == 64; 1554be0f34b5SRichard Henderson 1555be0f34b5SRichard Henderson case INDEX_op_movcond_i64: 1556be0f34b5SRichard Henderson return TCG_TARGET_HAS_movcond_i64; 1557be0f34b5SRichard Henderson case INDEX_op_div_i64: 1558be0f34b5SRichard Henderson case INDEX_op_divu_i64: 1559be0f34b5SRichard Henderson return TCG_TARGET_HAS_div_i64; 1560be0f34b5SRichard Henderson case INDEX_op_rem_i64: 1561be0f34b5SRichard Henderson case INDEX_op_remu_i64: 1562be0f34b5SRichard Henderson return TCG_TARGET_HAS_rem_i64; 1563be0f34b5SRichard Henderson case INDEX_op_div2_i64: 1564be0f34b5SRichard Henderson case INDEX_op_divu2_i64: 1565be0f34b5SRichard Henderson return TCG_TARGET_HAS_div2_i64; 1566be0f34b5SRichard Henderson case INDEX_op_rotl_i64: 1567be0f34b5SRichard Henderson case INDEX_op_rotr_i64: 1568be0f34b5SRichard Henderson return TCG_TARGET_HAS_rot_i64; 1569be0f34b5SRichard Henderson case INDEX_op_deposit_i64: 1570be0f34b5SRichard Henderson return TCG_TARGET_HAS_deposit_i64; 1571be0f34b5SRichard Henderson case INDEX_op_extract_i64: 1572be0f34b5SRichard Henderson return TCG_TARGET_HAS_extract_i64; 1573be0f34b5SRichard Henderson case INDEX_op_sextract_i64: 1574be0f34b5SRichard Henderson return TCG_TARGET_HAS_sextract_i64; 1575fce1296fSRichard Henderson case INDEX_op_extract2_i64: 1576fce1296fSRichard Henderson return TCG_TARGET_HAS_extract2_i64; 1577be0f34b5SRichard Henderson case INDEX_op_extrl_i64_i32: 1578be0f34b5SRichard Henderson return TCG_TARGET_HAS_extrl_i64_i32; 1579be0f34b5SRichard Henderson case INDEX_op_extrh_i64_i32: 1580be0f34b5SRichard Henderson return TCG_TARGET_HAS_extrh_i64_i32; 1581be0f34b5SRichard Henderson case INDEX_op_ext8s_i64: 1582be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8s_i64; 1583be0f34b5SRichard Henderson case INDEX_op_ext16s_i64: 1584be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16s_i64; 1585be0f34b5SRichard Henderson case INDEX_op_ext32s_i64: 1586be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext32s_i64; 1587be0f34b5SRichard Henderson case INDEX_op_ext8u_i64: 1588be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8u_i64; 1589be0f34b5SRichard Henderson case INDEX_op_ext16u_i64: 1590be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16u_i64; 1591be0f34b5SRichard Henderson case INDEX_op_ext32u_i64: 1592be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext32u_i64; 1593be0f34b5SRichard Henderson case INDEX_op_bswap16_i64: 1594be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap16_i64; 1595be0f34b5SRichard Henderson case INDEX_op_bswap32_i64: 1596be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap32_i64; 1597be0f34b5SRichard Henderson case INDEX_op_bswap64_i64: 1598be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap64_i64; 1599be0f34b5SRichard Henderson case INDEX_op_not_i64: 1600be0f34b5SRichard Henderson return TCG_TARGET_HAS_not_i64; 1601be0f34b5SRichard Henderson case INDEX_op_neg_i64: 1602be0f34b5SRichard Henderson return TCG_TARGET_HAS_neg_i64; 1603be0f34b5SRichard Henderson case INDEX_op_andc_i64: 1604be0f34b5SRichard Henderson return TCG_TARGET_HAS_andc_i64; 1605be0f34b5SRichard Henderson case INDEX_op_orc_i64: 1606be0f34b5SRichard Henderson return TCG_TARGET_HAS_orc_i64; 1607be0f34b5SRichard Henderson case INDEX_op_eqv_i64: 1608be0f34b5SRichard Henderson return TCG_TARGET_HAS_eqv_i64; 1609be0f34b5SRichard Henderson case INDEX_op_nand_i64: 1610be0f34b5SRichard Henderson return TCG_TARGET_HAS_nand_i64; 1611be0f34b5SRichard Henderson case INDEX_op_nor_i64: 1612be0f34b5SRichard Henderson return TCG_TARGET_HAS_nor_i64; 1613be0f34b5SRichard Henderson case INDEX_op_clz_i64: 1614be0f34b5SRichard Henderson return TCG_TARGET_HAS_clz_i64; 1615be0f34b5SRichard Henderson case INDEX_op_ctz_i64: 1616be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctz_i64; 1617be0f34b5SRichard Henderson case INDEX_op_ctpop_i64: 1618be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctpop_i64; 1619be0f34b5SRichard Henderson case INDEX_op_add2_i64: 1620be0f34b5SRichard Henderson return TCG_TARGET_HAS_add2_i64; 1621be0f34b5SRichard Henderson case INDEX_op_sub2_i64: 1622be0f34b5SRichard Henderson return TCG_TARGET_HAS_sub2_i64; 1623be0f34b5SRichard Henderson case INDEX_op_mulu2_i64: 1624be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulu2_i64; 1625be0f34b5SRichard Henderson case INDEX_op_muls2_i64: 1626be0f34b5SRichard Henderson return TCG_TARGET_HAS_muls2_i64; 1627be0f34b5SRichard Henderson case INDEX_op_muluh_i64: 1628be0f34b5SRichard Henderson return TCG_TARGET_HAS_muluh_i64; 1629be0f34b5SRichard Henderson case INDEX_op_mulsh_i64: 1630be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulsh_i64; 1631be0f34b5SRichard Henderson 1632d2fd745fSRichard Henderson case INDEX_op_mov_vec: 1633d2fd745fSRichard Henderson case INDEX_op_dup_vec: 1634d2fd745fSRichard Henderson case INDEX_op_dupi_vec: 163537ee55a0SRichard Henderson case INDEX_op_dupm_vec: 1636d2fd745fSRichard Henderson case INDEX_op_ld_vec: 1637d2fd745fSRichard Henderson case INDEX_op_st_vec: 1638d2fd745fSRichard Henderson case INDEX_op_add_vec: 1639d2fd745fSRichard Henderson case INDEX_op_sub_vec: 1640d2fd745fSRichard Henderson case INDEX_op_and_vec: 1641d2fd745fSRichard Henderson case INDEX_op_or_vec: 1642d2fd745fSRichard Henderson case INDEX_op_xor_vec: 1643212be173SRichard Henderson case INDEX_op_cmp_vec: 1644d2fd745fSRichard Henderson return have_vec; 1645d2fd745fSRichard Henderson case INDEX_op_dup2_vec: 1646d2fd745fSRichard Henderson return have_vec && TCG_TARGET_REG_BITS == 32; 1647d2fd745fSRichard Henderson case INDEX_op_not_vec: 1648d2fd745fSRichard Henderson return have_vec && TCG_TARGET_HAS_not_vec; 1649d2fd745fSRichard Henderson case INDEX_op_neg_vec: 1650d2fd745fSRichard Henderson return have_vec && TCG_TARGET_HAS_neg_vec; 1651bcefc902SRichard Henderson case INDEX_op_abs_vec: 1652bcefc902SRichard Henderson return have_vec && TCG_TARGET_HAS_abs_vec; 1653d2fd745fSRichard Henderson case INDEX_op_andc_vec: 1654d2fd745fSRichard Henderson return have_vec && TCG_TARGET_HAS_andc_vec; 1655d2fd745fSRichard Henderson case INDEX_op_orc_vec: 1656d2fd745fSRichard Henderson return have_vec && TCG_TARGET_HAS_orc_vec; 16573774030aSRichard Henderson case INDEX_op_mul_vec: 16583774030aSRichard Henderson return have_vec && TCG_TARGET_HAS_mul_vec; 1659d0ec9796SRichard Henderson case INDEX_op_shli_vec: 1660d0ec9796SRichard Henderson case INDEX_op_shri_vec: 1661d0ec9796SRichard Henderson case INDEX_op_sari_vec: 1662d0ec9796SRichard Henderson return have_vec && TCG_TARGET_HAS_shi_vec; 1663d0ec9796SRichard Henderson case INDEX_op_shls_vec: 1664d0ec9796SRichard Henderson case INDEX_op_shrs_vec: 1665d0ec9796SRichard Henderson case INDEX_op_sars_vec: 1666d0ec9796SRichard Henderson return have_vec && TCG_TARGET_HAS_shs_vec; 1667d0ec9796SRichard Henderson case INDEX_op_shlv_vec: 1668d0ec9796SRichard Henderson case INDEX_op_shrv_vec: 1669d0ec9796SRichard Henderson case INDEX_op_sarv_vec: 1670d0ec9796SRichard Henderson return have_vec && TCG_TARGET_HAS_shv_vec; 1671b0f7e744SRichard Henderson case INDEX_op_rotli_vec: 1672b0f7e744SRichard Henderson return have_vec && TCG_TARGET_HAS_roti_vec; 167323850a74SRichard Henderson case INDEX_op_rotls_vec: 167423850a74SRichard Henderson return have_vec && TCG_TARGET_HAS_rots_vec; 16755d0ceda9SRichard Henderson case INDEX_op_rotlv_vec: 16765d0ceda9SRichard Henderson case INDEX_op_rotrv_vec: 16775d0ceda9SRichard Henderson return have_vec && TCG_TARGET_HAS_rotv_vec; 16788afaf050SRichard Henderson case INDEX_op_ssadd_vec: 16798afaf050SRichard Henderson case INDEX_op_usadd_vec: 16808afaf050SRichard Henderson case INDEX_op_sssub_vec: 16818afaf050SRichard Henderson case INDEX_op_ussub_vec: 16828afaf050SRichard Henderson return have_vec && TCG_TARGET_HAS_sat_vec; 1683dd0a0fcdSRichard Henderson case INDEX_op_smin_vec: 1684dd0a0fcdSRichard Henderson case INDEX_op_umin_vec: 1685dd0a0fcdSRichard Henderson case INDEX_op_smax_vec: 1686dd0a0fcdSRichard Henderson case INDEX_op_umax_vec: 1687dd0a0fcdSRichard Henderson return have_vec && TCG_TARGET_HAS_minmax_vec; 168838dc1294SRichard Henderson case INDEX_op_bitsel_vec: 168938dc1294SRichard Henderson return have_vec && TCG_TARGET_HAS_bitsel_vec; 1690f75da298SRichard Henderson case INDEX_op_cmpsel_vec: 1691f75da298SRichard Henderson return have_vec && TCG_TARGET_HAS_cmpsel_vec; 1692d2fd745fSRichard Henderson 1693db432672SRichard Henderson default: 1694db432672SRichard Henderson tcg_debug_assert(op > INDEX_op_last_generic && op < NB_OPS); 1695db432672SRichard Henderson return true; 1696be0f34b5SRichard Henderson } 1697be0f34b5SRichard Henderson } 1698be0f34b5SRichard Henderson 169939cf05d3Sbellard /* Note: we convert the 64 bit args to 32 bit and do some alignment 170039cf05d3Sbellard and endian swap. Maybe it would be better to do the alignment 170139cf05d3Sbellard and endian swap in tcg_reg_alloc_call(). */ 1702ae8b75dcSRichard Henderson void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args) 1703c896fe29Sbellard { 170475e8b9b7SRichard Henderson int i, real_args, nb_rets, pi; 1705bbb8a1b4SRichard Henderson unsigned sizemask, flags; 1706afb49896SRichard Henderson TCGHelperInfo *info; 170775e8b9b7SRichard Henderson TCGOp *op; 1708afb49896SRichard Henderson 1709619205fdSEmilio G. Cota info = g_hash_table_lookup(helper_table, (gpointer)func); 1710bbb8a1b4SRichard Henderson flags = info->flags; 1711bbb8a1b4SRichard Henderson sizemask = info->sizemask; 17122bece2c8SRichard Henderson 171338b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN 171438b47b19SEmilio G. Cota /* detect non-plugin helpers */ 171538b47b19SEmilio G. Cota if (tcg_ctx->plugin_insn && unlikely(strncmp(info->name, "plugin_", 7))) { 171638b47b19SEmilio G. Cota tcg_ctx->plugin_insn->calls_helpers = true; 171738b47b19SEmilio G. Cota } 171838b47b19SEmilio G. Cota #endif 171938b47b19SEmilio G. Cota 172034b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \ 172134b1a49cSRichard Henderson && !defined(CONFIG_TCG_INTERPRETER) 172234b1a49cSRichard Henderson /* We have 64-bit values in one register, but need to pass as two 172334b1a49cSRichard Henderson separate parameters. Split them. */ 172434b1a49cSRichard Henderson int orig_sizemask = sizemask; 172534b1a49cSRichard Henderson int orig_nargs = nargs; 172634b1a49cSRichard Henderson TCGv_i64 retl, reth; 1727ae8b75dcSRichard Henderson TCGTemp *split_args[MAX_OPC_PARAM]; 172834b1a49cSRichard Henderson 1729f764718dSRichard Henderson retl = NULL; 1730f764718dSRichard Henderson reth = NULL; 173134b1a49cSRichard Henderson if (sizemask != 0) { 173234b1a49cSRichard Henderson for (i = real_args = 0; i < nargs; ++i) { 173334b1a49cSRichard Henderson int is_64bit = sizemask & (1 << (i+1)*2); 173434b1a49cSRichard Henderson if (is_64bit) { 1735085272b3SRichard Henderson TCGv_i64 orig = temp_tcgv_i64(args[i]); 173634b1a49cSRichard Henderson TCGv_i32 h = tcg_temp_new_i32(); 173734b1a49cSRichard Henderson TCGv_i32 l = tcg_temp_new_i32(); 173834b1a49cSRichard Henderson tcg_gen_extr_i64_i32(l, h, orig); 1739ae8b75dcSRichard Henderson split_args[real_args++] = tcgv_i32_temp(h); 1740ae8b75dcSRichard Henderson split_args[real_args++] = tcgv_i32_temp(l); 174134b1a49cSRichard Henderson } else { 174234b1a49cSRichard Henderson split_args[real_args++] = args[i]; 174334b1a49cSRichard Henderson } 174434b1a49cSRichard Henderson } 174534b1a49cSRichard Henderson nargs = real_args; 174634b1a49cSRichard Henderson args = split_args; 174734b1a49cSRichard Henderson sizemask = 0; 174834b1a49cSRichard Henderson } 174934b1a49cSRichard Henderson #elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64 17502bece2c8SRichard Henderson for (i = 0; i < nargs; ++i) { 17512bece2c8SRichard Henderson int is_64bit = sizemask & (1 << (i+1)*2); 17522bece2c8SRichard Henderson int is_signed = sizemask & (2 << (i+1)*2); 17532bece2c8SRichard Henderson if (!is_64bit) { 17542bece2c8SRichard Henderson TCGv_i64 temp = tcg_temp_new_i64(); 1755085272b3SRichard Henderson TCGv_i64 orig = temp_tcgv_i64(args[i]); 17562bece2c8SRichard Henderson if (is_signed) { 17572bece2c8SRichard Henderson tcg_gen_ext32s_i64(temp, orig); 17582bece2c8SRichard Henderson } else { 17592bece2c8SRichard Henderson tcg_gen_ext32u_i64(temp, orig); 17602bece2c8SRichard Henderson } 1761ae8b75dcSRichard Henderson args[i] = tcgv_i64_temp(temp); 17622bece2c8SRichard Henderson } 17632bece2c8SRichard Henderson } 17642bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */ 17652bece2c8SRichard Henderson 176615fa08f8SRichard Henderson op = tcg_emit_op(INDEX_op_call); 176775e8b9b7SRichard Henderson 176875e8b9b7SRichard Henderson pi = 0; 1769ae8b75dcSRichard Henderson if (ret != NULL) { 177034b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \ 177134b1a49cSRichard Henderson && !defined(CONFIG_TCG_INTERPRETER) 177234b1a49cSRichard Henderson if (orig_sizemask & 1) { 177334b1a49cSRichard Henderson /* The 32-bit ABI is going to return the 64-bit value in 177434b1a49cSRichard Henderson the %o0/%o1 register pair. Prepare for this by using 177534b1a49cSRichard Henderson two return temporaries, and reassemble below. */ 177634b1a49cSRichard Henderson retl = tcg_temp_new_i64(); 177734b1a49cSRichard Henderson reth = tcg_temp_new_i64(); 1778ae8b75dcSRichard Henderson op->args[pi++] = tcgv_i64_arg(reth); 1779ae8b75dcSRichard Henderson op->args[pi++] = tcgv_i64_arg(retl); 178034b1a49cSRichard Henderson nb_rets = 2; 178134b1a49cSRichard Henderson } else { 1782ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(ret); 178334b1a49cSRichard Henderson nb_rets = 1; 178434b1a49cSRichard Henderson } 178534b1a49cSRichard Henderson #else 178634b1a49cSRichard Henderson if (TCG_TARGET_REG_BITS < 64 && (sizemask & 1)) { 178702eb19d0SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN 1788ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(ret + 1); 1789ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(ret); 1790a7812ae4Spbrook #else 1791ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(ret); 1792ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(ret + 1); 1793a7812ae4Spbrook #endif 1794a7812ae4Spbrook nb_rets = 2; 179534b1a49cSRichard Henderson } else { 1796ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(ret); 1797a7812ae4Spbrook nb_rets = 1; 1798a7812ae4Spbrook } 179934b1a49cSRichard Henderson #endif 1800a7812ae4Spbrook } else { 1801a7812ae4Spbrook nb_rets = 0; 1802a7812ae4Spbrook } 1803cd9090aaSRichard Henderson TCGOP_CALLO(op) = nb_rets; 180475e8b9b7SRichard Henderson 1805a7812ae4Spbrook real_args = 0; 1806a7812ae4Spbrook for (i = 0; i < nargs; i++) { 18072bece2c8SRichard Henderson int is_64bit = sizemask & (1 << (i+1)*2); 1808bbb8a1b4SRichard Henderson if (TCG_TARGET_REG_BITS < 64 && is_64bit) { 180939cf05d3Sbellard #ifdef TCG_TARGET_CALL_ALIGN_ARGS 181039cf05d3Sbellard /* some targets want aligned 64 bit args */ 1811ebd486d5Smalc if (real_args & 1) { 181275e8b9b7SRichard Henderson op->args[pi++] = TCG_CALL_DUMMY_ARG; 1813ebd486d5Smalc real_args++; 181439cf05d3Sbellard } 181539cf05d3Sbellard #endif 18163f90f252SRichard Henderson /* If stack grows up, then we will be placing successive 18173f90f252SRichard Henderson arguments at lower addresses, which means we need to 18183f90f252SRichard Henderson reverse the order compared to how we would normally 18193f90f252SRichard Henderson treat either big or little-endian. For those arguments 18203f90f252SRichard Henderson that will wind up in registers, this still works for 18213f90f252SRichard Henderson HPPA (the only current STACK_GROWSUP target) since the 18223f90f252SRichard Henderson argument registers are *also* allocated in decreasing 18233f90f252SRichard Henderson order. If another such target is added, this logic may 18243f90f252SRichard Henderson have to get more complicated to differentiate between 18253f90f252SRichard Henderson stack arguments and register arguments. */ 182602eb19d0SRichard Henderson #if defined(HOST_WORDS_BIGENDIAN) != defined(TCG_TARGET_STACK_GROWSUP) 1827ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(args[i] + 1); 1828ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(args[i]); 1829c896fe29Sbellard #else 1830ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(args[i]); 1831ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(args[i] + 1); 1832c896fe29Sbellard #endif 1833a7812ae4Spbrook real_args += 2; 18342bece2c8SRichard Henderson continue; 18352bece2c8SRichard Henderson } 18362bece2c8SRichard Henderson 1837ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(args[i]); 1838a7812ae4Spbrook real_args++; 1839c896fe29Sbellard } 184075e8b9b7SRichard Henderson op->args[pi++] = (uintptr_t)func; 184175e8b9b7SRichard Henderson op->args[pi++] = flags; 1842cd9090aaSRichard Henderson TCGOP_CALLI(op) = real_args; 1843a7812ae4Spbrook 184475e8b9b7SRichard Henderson /* Make sure the fields didn't overflow. */ 1845cd9090aaSRichard Henderson tcg_debug_assert(TCGOP_CALLI(op) == real_args); 184675e8b9b7SRichard Henderson tcg_debug_assert(pi <= ARRAY_SIZE(op->args)); 18472bece2c8SRichard Henderson 184834b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \ 184934b1a49cSRichard Henderson && !defined(CONFIG_TCG_INTERPRETER) 185034b1a49cSRichard Henderson /* Free all of the parts we allocated above. */ 185134b1a49cSRichard Henderson for (i = real_args = 0; i < orig_nargs; ++i) { 185234b1a49cSRichard Henderson int is_64bit = orig_sizemask & (1 << (i+1)*2); 185334b1a49cSRichard Henderson if (is_64bit) { 1854085272b3SRichard Henderson tcg_temp_free_internal(args[real_args++]); 1855085272b3SRichard Henderson tcg_temp_free_internal(args[real_args++]); 185634b1a49cSRichard Henderson } else { 185734b1a49cSRichard Henderson real_args++; 185834b1a49cSRichard Henderson } 185934b1a49cSRichard Henderson } 186034b1a49cSRichard Henderson if (orig_sizemask & 1) { 186134b1a49cSRichard Henderson /* The 32-bit ABI returned two 32-bit pieces. Re-assemble them. 186234b1a49cSRichard Henderson Note that describing these as TCGv_i64 eliminates an unnecessary 186334b1a49cSRichard Henderson zero-extension that tcg_gen_concat_i32_i64 would create. */ 1864085272b3SRichard Henderson tcg_gen_concat32_i64(temp_tcgv_i64(ret), retl, reth); 186534b1a49cSRichard Henderson tcg_temp_free_i64(retl); 186634b1a49cSRichard Henderson tcg_temp_free_i64(reth); 186734b1a49cSRichard Henderson } 186834b1a49cSRichard Henderson #elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64 18692bece2c8SRichard Henderson for (i = 0; i < nargs; ++i) { 18702bece2c8SRichard Henderson int is_64bit = sizemask & (1 << (i+1)*2); 18712bece2c8SRichard Henderson if (!is_64bit) { 1872085272b3SRichard Henderson tcg_temp_free_internal(args[i]); 18732bece2c8SRichard Henderson } 18742bece2c8SRichard Henderson } 18752bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */ 1876a7812ae4Spbrook } 1877c896fe29Sbellard 18788fcd3692Sblueswir1 static void tcg_reg_alloc_start(TCGContext *s) 1879c896fe29Sbellard { 1880ac3b8891SRichard Henderson int i, n; 1881c896fe29Sbellard TCGTemp *ts; 1882ac3b8891SRichard Henderson 1883ac3b8891SRichard Henderson for (i = 0, n = s->nb_globals; i < n; i++) { 1884c896fe29Sbellard ts = &s->temps[i]; 1885ac3b8891SRichard Henderson ts->val_type = (ts->fixed_reg ? TEMP_VAL_REG : TEMP_VAL_MEM); 1886c896fe29Sbellard } 1887ac3b8891SRichard Henderson for (n = s->nb_temps; i < n; i++) { 1888e8996ee0Sbellard ts = &s->temps[i]; 1889ac3b8891SRichard Henderson ts->val_type = (ts->temp_local ? TEMP_VAL_MEM : TEMP_VAL_DEAD); 1890e8996ee0Sbellard ts->mem_allocated = 0; 1891e8996ee0Sbellard ts->fixed_reg = 0; 1892e8996ee0Sbellard } 1893f8b2f202SRichard Henderson 1894f8b2f202SRichard Henderson memset(s->reg_to_temp, 0, sizeof(s->reg_to_temp)); 1895c896fe29Sbellard } 1896c896fe29Sbellard 1897f8b2f202SRichard Henderson static char *tcg_get_arg_str_ptr(TCGContext *s, char *buf, int buf_size, 1898f8b2f202SRichard Henderson TCGTemp *ts) 1899c896fe29Sbellard { 19001807f4c4SRichard Henderson int idx = temp_idx(ts); 1901ac56dd48Spbrook 1902fa477d25SRichard Henderson if (ts->temp_global) { 1903ac56dd48Spbrook pstrcpy(buf, buf_size, ts->name); 1904f8b2f202SRichard Henderson } else if (ts->temp_local) { 1905641d5fbeSbellard snprintf(buf, buf_size, "loc%d", idx - s->nb_globals); 1906f8b2f202SRichard Henderson } else { 1907ac56dd48Spbrook snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals); 1908c896fe29Sbellard } 1909c896fe29Sbellard return buf; 1910c896fe29Sbellard } 1911c896fe29Sbellard 191243439139SRichard Henderson static char *tcg_get_arg_str(TCGContext *s, char *buf, 191343439139SRichard Henderson int buf_size, TCGArg arg) 1914f8b2f202SRichard Henderson { 191543439139SRichard Henderson return tcg_get_arg_str_ptr(s, buf, buf_size, arg_temp(arg)); 1916f8b2f202SRichard Henderson } 1917f8b2f202SRichard Henderson 19186e085f72SRichard Henderson /* Find helper name. */ 19196e085f72SRichard Henderson static inline const char *tcg_find_helper(TCGContext *s, uintptr_t val) 1920e8996ee0Sbellard { 19216e085f72SRichard Henderson const char *ret = NULL; 1922619205fdSEmilio G. Cota if (helper_table) { 1923619205fdSEmilio G. Cota TCGHelperInfo *info = g_hash_table_lookup(helper_table, (gpointer)val); 192472866e82SRichard Henderson if (info) { 192572866e82SRichard Henderson ret = info->name; 192672866e82SRichard Henderson } 1927e8996ee0Sbellard } 19286e085f72SRichard Henderson return ret; 19294dc81f28Sbellard } 19304dc81f28Sbellard 1931f48f3edeSblueswir1 static const char * const cond_name[] = 1932f48f3edeSblueswir1 { 19330aed257fSRichard Henderson [TCG_COND_NEVER] = "never", 19340aed257fSRichard Henderson [TCG_COND_ALWAYS] = "always", 1935f48f3edeSblueswir1 [TCG_COND_EQ] = "eq", 1936f48f3edeSblueswir1 [TCG_COND_NE] = "ne", 1937f48f3edeSblueswir1 [TCG_COND_LT] = "lt", 1938f48f3edeSblueswir1 [TCG_COND_GE] = "ge", 1939f48f3edeSblueswir1 [TCG_COND_LE] = "le", 1940f48f3edeSblueswir1 [TCG_COND_GT] = "gt", 1941f48f3edeSblueswir1 [TCG_COND_LTU] = "ltu", 1942f48f3edeSblueswir1 [TCG_COND_GEU] = "geu", 1943f48f3edeSblueswir1 [TCG_COND_LEU] = "leu", 1944f48f3edeSblueswir1 [TCG_COND_GTU] = "gtu" 1945f48f3edeSblueswir1 }; 1946f48f3edeSblueswir1 1947f713d6adSRichard Henderson static const char * const ldst_name[] = 1948f713d6adSRichard Henderson { 1949f713d6adSRichard Henderson [MO_UB] = "ub", 1950f713d6adSRichard Henderson [MO_SB] = "sb", 1951f713d6adSRichard Henderson [MO_LEUW] = "leuw", 1952f713d6adSRichard Henderson [MO_LESW] = "lesw", 1953f713d6adSRichard Henderson [MO_LEUL] = "leul", 1954f713d6adSRichard Henderson [MO_LESL] = "lesl", 1955f713d6adSRichard Henderson [MO_LEQ] = "leq", 1956f713d6adSRichard Henderson [MO_BEUW] = "beuw", 1957f713d6adSRichard Henderson [MO_BESW] = "besw", 1958f713d6adSRichard Henderson [MO_BEUL] = "beul", 1959f713d6adSRichard Henderson [MO_BESL] = "besl", 1960f713d6adSRichard Henderson [MO_BEQ] = "beq", 1961f713d6adSRichard Henderson }; 1962f713d6adSRichard Henderson 19631f00b27fSSergey Sorokin static const char * const alignment_name[(MO_AMASK >> MO_ASHIFT) + 1] = { 196452bf9771Stony.nguyen@bt.com #ifdef TARGET_ALIGNED_ONLY 19651f00b27fSSergey Sorokin [MO_UNALN >> MO_ASHIFT] = "un+", 19661f00b27fSSergey Sorokin [MO_ALIGN >> MO_ASHIFT] = "", 19671f00b27fSSergey Sorokin #else 19681f00b27fSSergey Sorokin [MO_UNALN >> MO_ASHIFT] = "", 19691f00b27fSSergey Sorokin [MO_ALIGN >> MO_ASHIFT] = "al+", 19701f00b27fSSergey Sorokin #endif 19711f00b27fSSergey Sorokin [MO_ALIGN_2 >> MO_ASHIFT] = "al2+", 19721f00b27fSSergey Sorokin [MO_ALIGN_4 >> MO_ASHIFT] = "al4+", 19731f00b27fSSergey Sorokin [MO_ALIGN_8 >> MO_ASHIFT] = "al8+", 19741f00b27fSSergey Sorokin [MO_ALIGN_16 >> MO_ASHIFT] = "al16+", 19751f00b27fSSergey Sorokin [MO_ALIGN_32 >> MO_ASHIFT] = "al32+", 19761f00b27fSSergey Sorokin [MO_ALIGN_64 >> MO_ASHIFT] = "al64+", 19771f00b27fSSergey Sorokin }; 19781f00b27fSSergey Sorokin 1979b016486eSRichard Henderson static inline bool tcg_regset_single(TCGRegSet d) 1980b016486eSRichard Henderson { 1981b016486eSRichard Henderson return (d & (d - 1)) == 0; 1982b016486eSRichard Henderson } 1983b016486eSRichard Henderson 1984b016486eSRichard Henderson static inline TCGReg tcg_regset_first(TCGRegSet d) 1985b016486eSRichard Henderson { 1986b016486eSRichard Henderson if (TCG_TARGET_NB_REGS <= 32) { 1987b016486eSRichard Henderson return ctz32(d); 1988b016486eSRichard Henderson } else { 1989b016486eSRichard Henderson return ctz64(d); 1990b016486eSRichard Henderson } 1991b016486eSRichard Henderson } 1992b016486eSRichard Henderson 19931894f69aSRichard Henderson static void tcg_dump_ops(TCGContext *s, bool have_prefs) 1994c896fe29Sbellard { 1995c896fe29Sbellard char buf[128]; 1996c45cb8bbSRichard Henderson TCGOp *op; 1997c896fe29Sbellard 199815fa08f8SRichard Henderson QTAILQ_FOREACH(op, &s->ops, link) { 1999c45cb8bbSRichard Henderson int i, k, nb_oargs, nb_iargs, nb_cargs; 2000c45cb8bbSRichard Henderson const TCGOpDef *def; 2001c45cb8bbSRichard Henderson TCGOpcode c; 2002bdfb460eSRichard Henderson int col = 0; 2003c45cb8bbSRichard Henderson 2004c45cb8bbSRichard Henderson c = op->opc; 2005c896fe29Sbellard def = &tcg_op_defs[c]; 2006c45cb8bbSRichard Henderson 2007765b842aSRichard Henderson if (c == INDEX_op_insn_start) { 2008b016486eSRichard Henderson nb_oargs = 0; 200915fa08f8SRichard Henderson col += qemu_log("\n ----"); 20109aef40edSRichard Henderson 20119aef40edSRichard Henderson for (i = 0; i < TARGET_INSN_START_WORDS; ++i) { 20129aef40edSRichard Henderson target_ulong a; 20137e4597d7Sbellard #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS 2014efee3746SRichard Henderson a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]); 20157e4597d7Sbellard #else 2016efee3746SRichard Henderson a = op->args[i]; 20177e4597d7Sbellard #endif 2018bdfb460eSRichard Henderson col += qemu_log(" " TARGET_FMT_lx, a); 2019eeacee4dSBlue Swirl } 20207e4597d7Sbellard } else if (c == INDEX_op_call) { 2021c896fe29Sbellard /* variable number of arguments */ 2022cd9090aaSRichard Henderson nb_oargs = TCGOP_CALLO(op); 2023cd9090aaSRichard Henderson nb_iargs = TCGOP_CALLI(op); 2024c896fe29Sbellard nb_cargs = def->nb_cargs; 2025b03cce8eSbellard 2026cf066674SRichard Henderson /* function name, flags, out args */ 2027bdfb460eSRichard Henderson col += qemu_log(" %s %s,$0x%" TCG_PRIlx ",$%d", def->name, 2028efee3746SRichard Henderson tcg_find_helper(s, op->args[nb_oargs + nb_iargs]), 2029efee3746SRichard Henderson op->args[nb_oargs + nb_iargs + 1], nb_oargs); 2030b03cce8eSbellard for (i = 0; i < nb_oargs; i++) { 203143439139SRichard Henderson col += qemu_log(",%s", tcg_get_arg_str(s, buf, sizeof(buf), 2032efee3746SRichard Henderson op->args[i])); 2033b03cce8eSbellard } 2034cf066674SRichard Henderson for (i = 0; i < nb_iargs; i++) { 2035efee3746SRichard Henderson TCGArg arg = op->args[nb_oargs + i]; 2036cf066674SRichard Henderson const char *t = "<dummy>"; 2037cf066674SRichard Henderson if (arg != TCG_CALL_DUMMY_ARG) { 203843439139SRichard Henderson t = tcg_get_arg_str(s, buf, sizeof(buf), arg); 2039b03cce8eSbellard } 2040bdfb460eSRichard Henderson col += qemu_log(",%s", t); 2041e8996ee0Sbellard } 2042b03cce8eSbellard } else { 2043bdfb460eSRichard Henderson col += qemu_log(" %s ", def->name); 2044c45cb8bbSRichard Henderson 2045c896fe29Sbellard nb_oargs = def->nb_oargs; 2046c896fe29Sbellard nb_iargs = def->nb_iargs; 2047c896fe29Sbellard nb_cargs = def->nb_cargs; 2048c896fe29Sbellard 2049d2fd745fSRichard Henderson if (def->flags & TCG_OPF_VECTOR) { 2050d2fd745fSRichard Henderson col += qemu_log("v%d,e%d,", 64 << TCGOP_VECL(op), 2051d2fd745fSRichard Henderson 8 << TCGOP_VECE(op)); 2052d2fd745fSRichard Henderson } 2053d2fd745fSRichard Henderson 2054c896fe29Sbellard k = 0; 2055c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 2056eeacee4dSBlue Swirl if (k != 0) { 2057bdfb460eSRichard Henderson col += qemu_log(","); 2058eeacee4dSBlue Swirl } 205943439139SRichard Henderson col += qemu_log("%s", tcg_get_arg_str(s, buf, sizeof(buf), 2060efee3746SRichard Henderson op->args[k++])); 2061c896fe29Sbellard } 2062c896fe29Sbellard for (i = 0; i < nb_iargs; i++) { 2063eeacee4dSBlue Swirl if (k != 0) { 2064bdfb460eSRichard Henderson col += qemu_log(","); 2065eeacee4dSBlue Swirl } 206643439139SRichard Henderson col += qemu_log("%s", tcg_get_arg_str(s, buf, sizeof(buf), 2067efee3746SRichard Henderson op->args[k++])); 2068c896fe29Sbellard } 2069be210acbSRichard Henderson switch (c) { 2070be210acbSRichard Henderson case INDEX_op_brcond_i32: 2071ffc5ea09SRichard Henderson case INDEX_op_setcond_i32: 2072ffc5ea09SRichard Henderson case INDEX_op_movcond_i32: 2073be210acbSRichard Henderson case INDEX_op_brcond2_i32: 2074be210acbSRichard Henderson case INDEX_op_setcond2_i32: 2075ffc5ea09SRichard Henderson case INDEX_op_brcond_i64: 2076be210acbSRichard Henderson case INDEX_op_setcond_i64: 2077ffc5ea09SRichard Henderson case INDEX_op_movcond_i64: 2078212be173SRichard Henderson case INDEX_op_cmp_vec: 2079f75da298SRichard Henderson case INDEX_op_cmpsel_vec: 2080efee3746SRichard Henderson if (op->args[k] < ARRAY_SIZE(cond_name) 2081efee3746SRichard Henderson && cond_name[op->args[k]]) { 2082efee3746SRichard Henderson col += qemu_log(",%s", cond_name[op->args[k++]]); 2083eeacee4dSBlue Swirl } else { 2084efee3746SRichard Henderson col += qemu_log(",$0x%" TCG_PRIlx, op->args[k++]); 2085eeacee4dSBlue Swirl } 2086f48f3edeSblueswir1 i = 1; 2087be210acbSRichard Henderson break; 2088f713d6adSRichard Henderson case INDEX_op_qemu_ld_i32: 2089f713d6adSRichard Henderson case INDEX_op_qemu_st_i32: 2090f713d6adSRichard Henderson case INDEX_op_qemu_ld_i64: 2091f713d6adSRichard Henderson case INDEX_op_qemu_st_i64: 209259227d5dSRichard Henderson { 2093efee3746SRichard Henderson TCGMemOpIdx oi = op->args[k++]; 209414776ab5STony Nguyen MemOp op = get_memop(oi); 209559227d5dSRichard Henderson unsigned ix = get_mmuidx(oi); 209659227d5dSRichard Henderson 209759c4b7e8SRichard Henderson if (op & ~(MO_AMASK | MO_BSWAP | MO_SSIZE)) { 2098bdfb460eSRichard Henderson col += qemu_log(",$0x%x,%u", op, ix); 209959c4b7e8SRichard Henderson } else { 21001f00b27fSSergey Sorokin const char *s_al, *s_op; 21011f00b27fSSergey Sorokin s_al = alignment_name[(op & MO_AMASK) >> MO_ASHIFT]; 210259c4b7e8SRichard Henderson s_op = ldst_name[op & (MO_BSWAP | MO_SSIZE)]; 2103bdfb460eSRichard Henderson col += qemu_log(",%s%s,%u", s_al, s_op, ix); 2104f713d6adSRichard Henderson } 2105f713d6adSRichard Henderson i = 1; 210659227d5dSRichard Henderson } 2107f713d6adSRichard Henderson break; 2108be210acbSRichard Henderson default: 2109f48f3edeSblueswir1 i = 0; 2110be210acbSRichard Henderson break; 2111be210acbSRichard Henderson } 211251e3972cSRichard Henderson switch (c) { 211351e3972cSRichard Henderson case INDEX_op_set_label: 211451e3972cSRichard Henderson case INDEX_op_br: 211551e3972cSRichard Henderson case INDEX_op_brcond_i32: 211651e3972cSRichard Henderson case INDEX_op_brcond_i64: 211751e3972cSRichard Henderson case INDEX_op_brcond2_i32: 2118efee3746SRichard Henderson col += qemu_log("%s$L%d", k ? "," : "", 2119efee3746SRichard Henderson arg_label(op->args[k])->id); 212051e3972cSRichard Henderson i++, k++; 212151e3972cSRichard Henderson break; 212251e3972cSRichard Henderson default: 212351e3972cSRichard Henderson break; 2124eeacee4dSBlue Swirl } 212551e3972cSRichard Henderson for (; i < nb_cargs; i++, k++) { 2126efee3746SRichard Henderson col += qemu_log("%s$0x%" TCG_PRIlx, k ? "," : "", op->args[k]); 2127bdfb460eSRichard Henderson } 2128bdfb460eSRichard Henderson } 2129bdfb460eSRichard Henderson 21301894f69aSRichard Henderson if (have_prefs || op->life) { 21317606488cSRobert Foley 21327606488cSRobert Foley QemuLogFile *logfile; 21337606488cSRobert Foley 21347606488cSRobert Foley rcu_read_lock(); 2135d73415a3SStefan Hajnoczi logfile = qatomic_rcu_read(&qemu_logfile); 21367606488cSRobert Foley if (logfile) { 21371894f69aSRichard Henderson for (; col < 40; ++col) { 21387606488cSRobert Foley putc(' ', logfile->fd); 2139bdfb460eSRichard Henderson } 21401894f69aSRichard Henderson } 21417606488cSRobert Foley rcu_read_unlock(); 21427606488cSRobert Foley } 21431894f69aSRichard Henderson 21441894f69aSRichard Henderson if (op->life) { 21451894f69aSRichard Henderson unsigned life = op->life; 2146bdfb460eSRichard Henderson 2147bdfb460eSRichard Henderson if (life & (SYNC_ARG * 3)) { 2148bdfb460eSRichard Henderson qemu_log(" sync:"); 2149bdfb460eSRichard Henderson for (i = 0; i < 2; ++i) { 2150bdfb460eSRichard Henderson if (life & (SYNC_ARG << i)) { 2151bdfb460eSRichard Henderson qemu_log(" %d", i); 2152bdfb460eSRichard Henderson } 2153bdfb460eSRichard Henderson } 2154bdfb460eSRichard Henderson } 2155bdfb460eSRichard Henderson life /= DEAD_ARG; 2156bdfb460eSRichard Henderson if (life) { 2157bdfb460eSRichard Henderson qemu_log(" dead:"); 2158bdfb460eSRichard Henderson for (i = 0; life; ++i, life >>= 1) { 2159bdfb460eSRichard Henderson if (life & 1) { 2160bdfb460eSRichard Henderson qemu_log(" %d", i); 2161bdfb460eSRichard Henderson } 2162bdfb460eSRichard Henderson } 2163c896fe29Sbellard } 2164b03cce8eSbellard } 21651894f69aSRichard Henderson 21661894f69aSRichard Henderson if (have_prefs) { 21671894f69aSRichard Henderson for (i = 0; i < nb_oargs; ++i) { 21681894f69aSRichard Henderson TCGRegSet set = op->output_pref[i]; 21691894f69aSRichard Henderson 21701894f69aSRichard Henderson if (i == 0) { 21711894f69aSRichard Henderson qemu_log(" pref="); 21721894f69aSRichard Henderson } else { 21731894f69aSRichard Henderson qemu_log(","); 21741894f69aSRichard Henderson } 21751894f69aSRichard Henderson if (set == 0) { 21761894f69aSRichard Henderson qemu_log("none"); 21771894f69aSRichard Henderson } else if (set == MAKE_64BIT_MASK(0, TCG_TARGET_NB_REGS)) { 21781894f69aSRichard Henderson qemu_log("all"); 21791894f69aSRichard Henderson #ifdef CONFIG_DEBUG_TCG 21801894f69aSRichard Henderson } else if (tcg_regset_single(set)) { 21811894f69aSRichard Henderson TCGReg reg = tcg_regset_first(set); 21821894f69aSRichard Henderson qemu_log("%s", tcg_target_reg_names[reg]); 21831894f69aSRichard Henderson #endif 21841894f69aSRichard Henderson } else if (TCG_TARGET_NB_REGS <= 32) { 21851894f69aSRichard Henderson qemu_log("%#x", (uint32_t)set); 21861894f69aSRichard Henderson } else { 21871894f69aSRichard Henderson qemu_log("%#" PRIx64, (uint64_t)set); 21881894f69aSRichard Henderson } 21891894f69aSRichard Henderson } 21901894f69aSRichard Henderson } 21911894f69aSRichard Henderson 2192eeacee4dSBlue Swirl qemu_log("\n"); 2193c896fe29Sbellard } 2194c896fe29Sbellard } 2195c896fe29Sbellard 2196c896fe29Sbellard /* we give more priority to constraints with less registers */ 2197c896fe29Sbellard static int get_constraint_priority(const TCGOpDef *def, int k) 2198c896fe29Sbellard { 219974a11790SRichard Henderson const TCGArgConstraint *arg_ct = &def->args_ct[k]; 220074a11790SRichard Henderson int n; 2201c896fe29Sbellard 2202bc2b17e6SRichard Henderson if (arg_ct->oalias) { 2203c896fe29Sbellard /* an alias is equivalent to a single register */ 2204c896fe29Sbellard n = 1; 2205c896fe29Sbellard } else { 220674a11790SRichard Henderson n = ctpop64(arg_ct->regs); 2207c896fe29Sbellard } 2208c896fe29Sbellard return TCG_TARGET_NB_REGS - n + 1; 2209c896fe29Sbellard } 2210c896fe29Sbellard 2211c896fe29Sbellard /* sort from highest priority to lowest */ 2212c896fe29Sbellard static void sort_constraints(TCGOpDef *def, int start, int n) 2213c896fe29Sbellard { 221466792f90SRichard Henderson int i, j; 221566792f90SRichard Henderson TCGArgConstraint *a = def->args_ct; 2216c896fe29Sbellard 221766792f90SRichard Henderson for (i = 0; i < n; i++) { 221866792f90SRichard Henderson a[start + i].sort_index = start + i; 221966792f90SRichard Henderson } 222066792f90SRichard Henderson if (n <= 1) { 2221c896fe29Sbellard return; 222266792f90SRichard Henderson } 2223c896fe29Sbellard for (i = 0; i < n - 1; i++) { 2224c896fe29Sbellard for (j = i + 1; j < n; j++) { 222566792f90SRichard Henderson int p1 = get_constraint_priority(def, a[start + i].sort_index); 222666792f90SRichard Henderson int p2 = get_constraint_priority(def, a[start + j].sort_index); 2227c896fe29Sbellard if (p1 < p2) { 222866792f90SRichard Henderson int tmp = a[start + i].sort_index; 222966792f90SRichard Henderson a[start + i].sort_index = a[start + j].sort_index; 223066792f90SRichard Henderson a[start + j].sort_index = tmp; 2231c896fe29Sbellard } 2232c896fe29Sbellard } 2233c896fe29Sbellard } 2234c896fe29Sbellard } 2235c896fe29Sbellard 2236f69d277eSRichard Henderson static void process_op_defs(TCGContext *s) 2237c896fe29Sbellard { 2238a9751609SRichard Henderson TCGOpcode op; 2239c896fe29Sbellard 2240f69d277eSRichard Henderson for (op = 0; op < NB_OPS; op++) { 2241f69d277eSRichard Henderson TCGOpDef *def = &tcg_op_defs[op]; 2242f69d277eSRichard Henderson const TCGTargetOpDef *tdefs; 2243069ea736SRichard Henderson TCGType type; 2244069ea736SRichard Henderson int i, nb_args; 2245f69d277eSRichard Henderson 2246f69d277eSRichard Henderson if (def->flags & TCG_OPF_NOT_PRESENT) { 2247f69d277eSRichard Henderson continue; 2248f69d277eSRichard Henderson } 2249f69d277eSRichard Henderson 2250c896fe29Sbellard nb_args = def->nb_iargs + def->nb_oargs; 2251f69d277eSRichard Henderson if (nb_args == 0) { 2252f69d277eSRichard Henderson continue; 2253f69d277eSRichard Henderson } 2254f69d277eSRichard Henderson 2255f69d277eSRichard Henderson tdefs = tcg_target_op_def(op); 2256f69d277eSRichard Henderson /* Missing TCGTargetOpDef entry. */ 2257f69d277eSRichard Henderson tcg_debug_assert(tdefs != NULL); 2258f69d277eSRichard Henderson 2259069ea736SRichard Henderson type = (def->flags & TCG_OPF_64BIT ? TCG_TYPE_I64 : TCG_TYPE_I32); 2260c896fe29Sbellard for (i = 0; i < nb_args; i++) { 2261f69d277eSRichard Henderson const char *ct_str = tdefs->args_ct_str[i]; 2262f69d277eSRichard Henderson /* Incomplete TCGTargetOpDef entry. */ 2263eabb7b91SAurelien Jarno tcg_debug_assert(ct_str != NULL); 2264f69d277eSRichard Henderson 226517280ff4SRichard Henderson while (*ct_str != '\0') { 226617280ff4SRichard Henderson switch(*ct_str) { 226717280ff4SRichard Henderson case '0' ... '9': 226817280ff4SRichard Henderson { 226917280ff4SRichard Henderson int oarg = *ct_str - '0'; 227017280ff4SRichard Henderson tcg_debug_assert(ct_str == tdefs->args_ct_str[i]); 2271eabb7b91SAurelien Jarno tcg_debug_assert(oarg < def->nb_oargs); 227274a11790SRichard Henderson tcg_debug_assert(def->args_ct[oarg].regs != 0); 2273c896fe29Sbellard def->args_ct[i] = def->args_ct[oarg]; 2274bc2b17e6SRichard Henderson /* The output sets oalias. */ 2275bc2b17e6SRichard Henderson def->args_ct[oarg].oalias = true; 22765ff9d6a4Sbellard def->args_ct[oarg].alias_index = i; 2277bc2b17e6SRichard Henderson /* The input sets ialias. */ 2278bc2b17e6SRichard Henderson def->args_ct[i].ialias = true; 22795ff9d6a4Sbellard def->args_ct[i].alias_index = oarg; 228017280ff4SRichard Henderson } 228117280ff4SRichard Henderson ct_str++; 2282c896fe29Sbellard break; 228382790a87SRichard Henderson case '&': 2284bc2b17e6SRichard Henderson def->args_ct[i].newreg = true; 228582790a87SRichard Henderson ct_str++; 228682790a87SRichard Henderson break; 2287c896fe29Sbellard case 'i': 2288c896fe29Sbellard def->args_ct[i].ct |= TCG_CT_CONST; 2289c896fe29Sbellard ct_str++; 2290c896fe29Sbellard break; 2291c896fe29Sbellard default: 2292069ea736SRichard Henderson ct_str = target_parse_constraint(&def->args_ct[i], 2293069ea736SRichard Henderson ct_str, type); 2294f69d277eSRichard Henderson /* Typo in TCGTargetOpDef constraint. */ 2295069ea736SRichard Henderson tcg_debug_assert(ct_str != NULL); 2296c896fe29Sbellard } 2297c896fe29Sbellard } 2298c896fe29Sbellard } 2299c896fe29Sbellard 2300c68aaa18SStefan Weil /* TCGTargetOpDef entry with too much information? */ 2301eabb7b91SAurelien Jarno tcg_debug_assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL); 2302c68aaa18SStefan Weil 2303c896fe29Sbellard /* sort the constraints (XXX: this is just an heuristic) */ 2304c896fe29Sbellard sort_constraints(def, 0, def->nb_oargs); 2305c896fe29Sbellard sort_constraints(def, def->nb_oargs, def->nb_iargs); 2306c896fe29Sbellard } 2307c896fe29Sbellard } 2308c896fe29Sbellard 23090c627cdcSRichard Henderson void tcg_op_remove(TCGContext *s, TCGOp *op) 23100c627cdcSRichard Henderson { 2311d88a117eSRichard Henderson TCGLabel *label; 2312d88a117eSRichard Henderson 2313d88a117eSRichard Henderson switch (op->opc) { 2314d88a117eSRichard Henderson case INDEX_op_br: 2315d88a117eSRichard Henderson label = arg_label(op->args[0]); 2316d88a117eSRichard Henderson label->refs--; 2317d88a117eSRichard Henderson break; 2318d88a117eSRichard Henderson case INDEX_op_brcond_i32: 2319d88a117eSRichard Henderson case INDEX_op_brcond_i64: 2320d88a117eSRichard Henderson label = arg_label(op->args[3]); 2321d88a117eSRichard Henderson label->refs--; 2322d88a117eSRichard Henderson break; 2323d88a117eSRichard Henderson case INDEX_op_brcond2_i32: 2324d88a117eSRichard Henderson label = arg_label(op->args[5]); 2325d88a117eSRichard Henderson label->refs--; 2326d88a117eSRichard Henderson break; 2327d88a117eSRichard Henderson default: 2328d88a117eSRichard Henderson break; 2329d88a117eSRichard Henderson } 2330d88a117eSRichard Henderson 233115fa08f8SRichard Henderson QTAILQ_REMOVE(&s->ops, op, link); 233215fa08f8SRichard Henderson QTAILQ_INSERT_TAIL(&s->free_ops, op, link); 2333abebf925SRichard Henderson s->nb_ops--; 23340c627cdcSRichard Henderson 23350c627cdcSRichard Henderson #ifdef CONFIG_PROFILER 2336d73415a3SStefan Hajnoczi qatomic_set(&s->prof.del_op_count, s->prof.del_op_count + 1); 23370c627cdcSRichard Henderson #endif 23380c627cdcSRichard Henderson } 23390c627cdcSRichard Henderson 234015fa08f8SRichard Henderson static TCGOp *tcg_op_alloc(TCGOpcode opc) 234115fa08f8SRichard Henderson { 234215fa08f8SRichard Henderson TCGContext *s = tcg_ctx; 234315fa08f8SRichard Henderson TCGOp *op; 234415fa08f8SRichard Henderson 234515fa08f8SRichard Henderson if (likely(QTAILQ_EMPTY(&s->free_ops))) { 234615fa08f8SRichard Henderson op = tcg_malloc(sizeof(TCGOp)); 234715fa08f8SRichard Henderson } else { 234815fa08f8SRichard Henderson op = QTAILQ_FIRST(&s->free_ops); 234915fa08f8SRichard Henderson QTAILQ_REMOVE(&s->free_ops, op, link); 235015fa08f8SRichard Henderson } 235115fa08f8SRichard Henderson memset(op, 0, offsetof(TCGOp, link)); 235215fa08f8SRichard Henderson op->opc = opc; 2353abebf925SRichard Henderson s->nb_ops++; 235415fa08f8SRichard Henderson 235515fa08f8SRichard Henderson return op; 235615fa08f8SRichard Henderson } 235715fa08f8SRichard Henderson 235815fa08f8SRichard Henderson TCGOp *tcg_emit_op(TCGOpcode opc) 235915fa08f8SRichard Henderson { 236015fa08f8SRichard Henderson TCGOp *op = tcg_op_alloc(opc); 236115fa08f8SRichard Henderson QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link); 236215fa08f8SRichard Henderson return op; 236315fa08f8SRichard Henderson } 236415fa08f8SRichard Henderson 2365ac1043f6SEmilio G. Cota TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op, TCGOpcode opc) 23665a18407fSRichard Henderson { 236715fa08f8SRichard Henderson TCGOp *new_op = tcg_op_alloc(opc); 236815fa08f8SRichard Henderson QTAILQ_INSERT_BEFORE(old_op, new_op, link); 23695a18407fSRichard Henderson return new_op; 23705a18407fSRichard Henderson } 23715a18407fSRichard Henderson 2372ac1043f6SEmilio G. Cota TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op, TCGOpcode opc) 23735a18407fSRichard Henderson { 237415fa08f8SRichard Henderson TCGOp *new_op = tcg_op_alloc(opc); 237515fa08f8SRichard Henderson QTAILQ_INSERT_AFTER(&s->ops, old_op, new_op, link); 23765a18407fSRichard Henderson return new_op; 23775a18407fSRichard Henderson } 23785a18407fSRichard Henderson 2379b4fc67c7SRichard Henderson /* Reachable analysis : remove unreachable code. */ 2380b4fc67c7SRichard Henderson static void reachable_code_pass(TCGContext *s) 2381b4fc67c7SRichard Henderson { 2382b4fc67c7SRichard Henderson TCGOp *op, *op_next; 2383b4fc67c7SRichard Henderson bool dead = false; 2384b4fc67c7SRichard Henderson 2385b4fc67c7SRichard Henderson QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) { 2386b4fc67c7SRichard Henderson bool remove = dead; 2387b4fc67c7SRichard Henderson TCGLabel *label; 2388b4fc67c7SRichard Henderson int call_flags; 2389b4fc67c7SRichard Henderson 2390b4fc67c7SRichard Henderson switch (op->opc) { 2391b4fc67c7SRichard Henderson case INDEX_op_set_label: 2392b4fc67c7SRichard Henderson label = arg_label(op->args[0]); 2393b4fc67c7SRichard Henderson if (label->refs == 0) { 2394b4fc67c7SRichard Henderson /* 2395b4fc67c7SRichard Henderson * While there is an occasional backward branch, virtually 2396b4fc67c7SRichard Henderson * all branches generated by the translators are forward. 2397b4fc67c7SRichard Henderson * Which means that generally we will have already removed 2398b4fc67c7SRichard Henderson * all references to the label that will be, and there is 2399b4fc67c7SRichard Henderson * little to be gained by iterating. 2400b4fc67c7SRichard Henderson */ 2401b4fc67c7SRichard Henderson remove = true; 2402b4fc67c7SRichard Henderson } else { 2403b4fc67c7SRichard Henderson /* Once we see a label, insns become live again. */ 2404b4fc67c7SRichard Henderson dead = false; 2405b4fc67c7SRichard Henderson remove = false; 2406b4fc67c7SRichard Henderson 2407b4fc67c7SRichard Henderson /* 2408b4fc67c7SRichard Henderson * Optimization can fold conditional branches to unconditional. 2409b4fc67c7SRichard Henderson * If we find a label with one reference which is preceded by 2410b4fc67c7SRichard Henderson * an unconditional branch to it, remove both. This needed to 2411b4fc67c7SRichard Henderson * wait until the dead code in between them was removed. 2412b4fc67c7SRichard Henderson */ 2413b4fc67c7SRichard Henderson if (label->refs == 1) { 2414eae3eb3eSPaolo Bonzini TCGOp *op_prev = QTAILQ_PREV(op, link); 2415b4fc67c7SRichard Henderson if (op_prev->opc == INDEX_op_br && 2416b4fc67c7SRichard Henderson label == arg_label(op_prev->args[0])) { 2417b4fc67c7SRichard Henderson tcg_op_remove(s, op_prev); 2418b4fc67c7SRichard Henderson remove = true; 2419b4fc67c7SRichard Henderson } 2420b4fc67c7SRichard Henderson } 2421b4fc67c7SRichard Henderson } 2422b4fc67c7SRichard Henderson break; 2423b4fc67c7SRichard Henderson 2424b4fc67c7SRichard Henderson case INDEX_op_br: 2425b4fc67c7SRichard Henderson case INDEX_op_exit_tb: 2426b4fc67c7SRichard Henderson case INDEX_op_goto_ptr: 2427b4fc67c7SRichard Henderson /* Unconditional branches; everything following is dead. */ 2428b4fc67c7SRichard Henderson dead = true; 2429b4fc67c7SRichard Henderson break; 2430b4fc67c7SRichard Henderson 2431b4fc67c7SRichard Henderson case INDEX_op_call: 2432b4fc67c7SRichard Henderson /* Notice noreturn helper calls, raising exceptions. */ 2433b4fc67c7SRichard Henderson call_flags = op->args[TCGOP_CALLO(op) + TCGOP_CALLI(op) + 1]; 2434b4fc67c7SRichard Henderson if (call_flags & TCG_CALL_NO_RETURN) { 2435b4fc67c7SRichard Henderson dead = true; 2436b4fc67c7SRichard Henderson } 2437b4fc67c7SRichard Henderson break; 2438b4fc67c7SRichard Henderson 2439b4fc67c7SRichard Henderson case INDEX_op_insn_start: 2440b4fc67c7SRichard Henderson /* Never remove -- we need to keep these for unwind. */ 2441b4fc67c7SRichard Henderson remove = false; 2442b4fc67c7SRichard Henderson break; 2443b4fc67c7SRichard Henderson 2444b4fc67c7SRichard Henderson default: 2445b4fc67c7SRichard Henderson break; 2446b4fc67c7SRichard Henderson } 2447b4fc67c7SRichard Henderson 2448b4fc67c7SRichard Henderson if (remove) { 2449b4fc67c7SRichard Henderson tcg_op_remove(s, op); 2450b4fc67c7SRichard Henderson } 2451b4fc67c7SRichard Henderson } 2452b4fc67c7SRichard Henderson } 2453b4fc67c7SRichard Henderson 2454c70fbf0aSRichard Henderson #define TS_DEAD 1 2455c70fbf0aSRichard Henderson #define TS_MEM 2 2456c70fbf0aSRichard Henderson 24575a18407fSRichard Henderson #define IS_DEAD_ARG(n) (arg_life & (DEAD_ARG << (n))) 24585a18407fSRichard Henderson #define NEED_SYNC_ARG(n) (arg_life & (SYNC_ARG << (n))) 24595a18407fSRichard Henderson 246025f49c5fSRichard Henderson /* For liveness_pass_1, the register preferences for a given temp. */ 246125f49c5fSRichard Henderson static inline TCGRegSet *la_temp_pref(TCGTemp *ts) 246225f49c5fSRichard Henderson { 246325f49c5fSRichard Henderson return ts->state_ptr; 246425f49c5fSRichard Henderson } 246525f49c5fSRichard Henderson 246625f49c5fSRichard Henderson /* For liveness_pass_1, reset the preferences for a given temp to the 246725f49c5fSRichard Henderson * maximal regset for its type. 246825f49c5fSRichard Henderson */ 246925f49c5fSRichard Henderson static inline void la_reset_pref(TCGTemp *ts) 247025f49c5fSRichard Henderson { 247125f49c5fSRichard Henderson *la_temp_pref(ts) 247225f49c5fSRichard Henderson = (ts->state == TS_DEAD ? 0 : tcg_target_available_regs[ts->type]); 247325f49c5fSRichard Henderson } 247425f49c5fSRichard Henderson 24759c43b68dSAurelien Jarno /* liveness analysis: end of function: all temps are dead, and globals 24769c43b68dSAurelien Jarno should be in memory. */ 24772616c808SRichard Henderson static void la_func_end(TCGContext *s, int ng, int nt) 2478c896fe29Sbellard { 2479b83eabeaSRichard Henderson int i; 2480b83eabeaSRichard Henderson 2481b83eabeaSRichard Henderson for (i = 0; i < ng; ++i) { 2482b83eabeaSRichard Henderson s->temps[i].state = TS_DEAD | TS_MEM; 248325f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 2484b83eabeaSRichard Henderson } 2485b83eabeaSRichard Henderson for (i = ng; i < nt; ++i) { 2486b83eabeaSRichard Henderson s->temps[i].state = TS_DEAD; 248725f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 2488b83eabeaSRichard Henderson } 2489c896fe29Sbellard } 2490c896fe29Sbellard 24919c43b68dSAurelien Jarno /* liveness analysis: end of basic block: all temps are dead, globals 24929c43b68dSAurelien Jarno and local temps should be in memory. */ 24932616c808SRichard Henderson static void la_bb_end(TCGContext *s, int ng, int nt) 2494641d5fbeSbellard { 2495b83eabeaSRichard Henderson int i; 2496641d5fbeSbellard 2497b83eabeaSRichard Henderson for (i = 0; i < ng; ++i) { 2498b83eabeaSRichard Henderson s->temps[i].state = TS_DEAD | TS_MEM; 249925f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 2500c70fbf0aSRichard Henderson } 2501b83eabeaSRichard Henderson for (i = ng; i < nt; ++i) { 2502b83eabeaSRichard Henderson s->temps[i].state = (s->temps[i].temp_local 2503b83eabeaSRichard Henderson ? TS_DEAD | TS_MEM 2504b83eabeaSRichard Henderson : TS_DEAD); 250525f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 2506641d5fbeSbellard } 2507641d5fbeSbellard } 2508641d5fbeSbellard 2509f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory. */ 2510f65a061cSRichard Henderson static void la_global_sync(TCGContext *s, int ng) 2511f65a061cSRichard Henderson { 2512f65a061cSRichard Henderson int i; 2513f65a061cSRichard Henderson 2514f65a061cSRichard Henderson for (i = 0; i < ng; ++i) { 251525f49c5fSRichard Henderson int state = s->temps[i].state; 251625f49c5fSRichard Henderson s->temps[i].state = state | TS_MEM; 251725f49c5fSRichard Henderson if (state == TS_DEAD) { 251825f49c5fSRichard Henderson /* If the global was previously dead, reset prefs. */ 251925f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 252025f49c5fSRichard Henderson } 2521f65a061cSRichard Henderson } 2522f65a061cSRichard Henderson } 2523f65a061cSRichard Henderson 2524b4cb76e6SRichard Henderson /* 2525b4cb76e6SRichard Henderson * liveness analysis: conditional branch: all temps are dead, 2526b4cb76e6SRichard Henderson * globals and local temps should be synced. 2527b4cb76e6SRichard Henderson */ 2528b4cb76e6SRichard Henderson static void la_bb_sync(TCGContext *s, int ng, int nt) 2529b4cb76e6SRichard Henderson { 2530b4cb76e6SRichard Henderson la_global_sync(s, ng); 2531b4cb76e6SRichard Henderson 2532b4cb76e6SRichard Henderson for (int i = ng; i < nt; ++i) { 2533b4cb76e6SRichard Henderson if (s->temps[i].temp_local) { 2534b4cb76e6SRichard Henderson int state = s->temps[i].state; 2535b4cb76e6SRichard Henderson s->temps[i].state = state | TS_MEM; 2536b4cb76e6SRichard Henderson if (state != TS_DEAD) { 2537b4cb76e6SRichard Henderson continue; 2538b4cb76e6SRichard Henderson } 2539b4cb76e6SRichard Henderson } else { 2540b4cb76e6SRichard Henderson s->temps[i].state = TS_DEAD; 2541b4cb76e6SRichard Henderson } 2542b4cb76e6SRichard Henderson la_reset_pref(&s->temps[i]); 2543b4cb76e6SRichard Henderson } 2544b4cb76e6SRichard Henderson } 2545b4cb76e6SRichard Henderson 2546f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory and kill. */ 2547f65a061cSRichard Henderson static void la_global_kill(TCGContext *s, int ng) 2548f65a061cSRichard Henderson { 2549f65a061cSRichard Henderson int i; 2550f65a061cSRichard Henderson 2551f65a061cSRichard Henderson for (i = 0; i < ng; i++) { 2552f65a061cSRichard Henderson s->temps[i].state = TS_DEAD | TS_MEM; 255325f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 255425f49c5fSRichard Henderson } 255525f49c5fSRichard Henderson } 255625f49c5fSRichard Henderson 255725f49c5fSRichard Henderson /* liveness analysis: note live globals crossing calls. */ 255825f49c5fSRichard Henderson static void la_cross_call(TCGContext *s, int nt) 255925f49c5fSRichard Henderson { 256025f49c5fSRichard Henderson TCGRegSet mask = ~tcg_target_call_clobber_regs; 256125f49c5fSRichard Henderson int i; 256225f49c5fSRichard Henderson 256325f49c5fSRichard Henderson for (i = 0; i < nt; i++) { 256425f49c5fSRichard Henderson TCGTemp *ts = &s->temps[i]; 256525f49c5fSRichard Henderson if (!(ts->state & TS_DEAD)) { 256625f49c5fSRichard Henderson TCGRegSet *pset = la_temp_pref(ts); 256725f49c5fSRichard Henderson TCGRegSet set = *pset; 256825f49c5fSRichard Henderson 256925f49c5fSRichard Henderson set &= mask; 257025f49c5fSRichard Henderson /* If the combination is not possible, restart. */ 257125f49c5fSRichard Henderson if (set == 0) { 257225f49c5fSRichard Henderson set = tcg_target_available_regs[ts->type] & mask; 257325f49c5fSRichard Henderson } 257425f49c5fSRichard Henderson *pset = set; 257525f49c5fSRichard Henderson } 2576f65a061cSRichard Henderson } 2577f65a061cSRichard Henderson } 2578f65a061cSRichard Henderson 2579a1b3c48dSRichard Henderson /* Liveness analysis : update the opc_arg_life array to tell if a 2580c896fe29Sbellard given input arguments is dead. Instructions updating dead 2581c896fe29Sbellard temporaries are removed. */ 2582b83eabeaSRichard Henderson static void liveness_pass_1(TCGContext *s) 2583c896fe29Sbellard { 2584c70fbf0aSRichard Henderson int nb_globals = s->nb_globals; 25852616c808SRichard Henderson int nb_temps = s->nb_temps; 258615fa08f8SRichard Henderson TCGOp *op, *op_prev; 258725f49c5fSRichard Henderson TCGRegSet *prefs; 258825f49c5fSRichard Henderson int i; 258925f49c5fSRichard Henderson 259025f49c5fSRichard Henderson prefs = tcg_malloc(sizeof(TCGRegSet) * nb_temps); 259125f49c5fSRichard Henderson for (i = 0; i < nb_temps; ++i) { 259225f49c5fSRichard Henderson s->temps[i].state_ptr = prefs + i; 259325f49c5fSRichard Henderson } 2594c896fe29Sbellard 2595ae36a246SRichard Henderson /* ??? Should be redundant with the exit_tb that ends the TB. */ 25962616c808SRichard Henderson la_func_end(s, nb_globals, nb_temps); 2597c896fe29Sbellard 2598eae3eb3eSPaolo Bonzini QTAILQ_FOREACH_REVERSE_SAFE(op, &s->ops, link, op_prev) { 259925f49c5fSRichard Henderson int nb_iargs, nb_oargs; 2600c45cb8bbSRichard Henderson TCGOpcode opc_new, opc_new2; 2601c45cb8bbSRichard Henderson bool have_opc_new2; 2602a1b3c48dSRichard Henderson TCGLifeData arg_life = 0; 260325f49c5fSRichard Henderson TCGTemp *ts; 2604c45cb8bbSRichard Henderson TCGOpcode opc = op->opc; 2605c45cb8bbSRichard Henderson const TCGOpDef *def = &tcg_op_defs[opc]; 2606c45cb8bbSRichard Henderson 2607c45cb8bbSRichard Henderson switch (opc) { 2608c896fe29Sbellard case INDEX_op_call: 2609c6e113f5Sbellard { 2610c6e113f5Sbellard int call_flags; 261125f49c5fSRichard Henderson int nb_call_regs; 2612c6e113f5Sbellard 2613cd9090aaSRichard Henderson nb_oargs = TCGOP_CALLO(op); 2614cd9090aaSRichard Henderson nb_iargs = TCGOP_CALLI(op); 2615efee3746SRichard Henderson call_flags = op->args[nb_oargs + nb_iargs + 1]; 2616c6e113f5Sbellard 2617c45cb8bbSRichard Henderson /* pure functions can be removed if their result is unused */ 261878505279SAurelien Jarno if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) { 2619c6e113f5Sbellard for (i = 0; i < nb_oargs; i++) { 262025f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 262125f49c5fSRichard Henderson if (ts->state != TS_DEAD) { 2622c6e113f5Sbellard goto do_not_remove_call; 2623c6e113f5Sbellard } 26249c43b68dSAurelien Jarno } 2625c45cb8bbSRichard Henderson goto do_remove; 2626152c35aaSRichard Henderson } 2627c6e113f5Sbellard do_not_remove_call: 2628c896fe29Sbellard 262925f49c5fSRichard Henderson /* Output args are dead. */ 2630c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 263125f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 263225f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 2633a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 26346b64b624SAurelien Jarno } 263525f49c5fSRichard Henderson if (ts->state & TS_MEM) { 2636a1b3c48dSRichard Henderson arg_life |= SYNC_ARG << i; 26379c43b68dSAurelien Jarno } 263825f49c5fSRichard Henderson ts->state = TS_DEAD; 263925f49c5fSRichard Henderson la_reset_pref(ts); 264025f49c5fSRichard Henderson 264125f49c5fSRichard Henderson /* Not used -- it will be tcg_target_call_oarg_regs[i]. */ 264225f49c5fSRichard Henderson op->output_pref[i] = 0; 2643c896fe29Sbellard } 2644c896fe29Sbellard 264578505279SAurelien Jarno if (!(call_flags & (TCG_CALL_NO_WRITE_GLOBALS | 264678505279SAurelien Jarno TCG_CALL_NO_READ_GLOBALS))) { 2647f65a061cSRichard Henderson la_global_kill(s, nb_globals); 2648c70fbf0aSRichard Henderson } else if (!(call_flags & TCG_CALL_NO_READ_GLOBALS)) { 2649f65a061cSRichard Henderson la_global_sync(s, nb_globals); 2650b9c18f56Saurel32 } 2651c896fe29Sbellard 265225f49c5fSRichard Henderson /* Record arguments that die in this helper. */ 2653866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 265425f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 265525f49c5fSRichard Henderson if (ts && ts->state & TS_DEAD) { 2656a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 2657c896fe29Sbellard } 2658c896fe29Sbellard } 265925f49c5fSRichard Henderson 266025f49c5fSRichard Henderson /* For all live registers, remove call-clobbered prefs. */ 266125f49c5fSRichard Henderson la_cross_call(s, nb_temps); 266225f49c5fSRichard Henderson 266325f49c5fSRichard Henderson nb_call_regs = ARRAY_SIZE(tcg_target_call_iarg_regs); 266425f49c5fSRichard Henderson 266525f49c5fSRichard Henderson /* Input arguments are live for preceding opcodes. */ 266625f49c5fSRichard Henderson for (i = 0; i < nb_iargs; i++) { 266725f49c5fSRichard Henderson ts = arg_temp(op->args[i + nb_oargs]); 266825f49c5fSRichard Henderson if (ts && ts->state & TS_DEAD) { 266925f49c5fSRichard Henderson /* For those arguments that die, and will be allocated 267025f49c5fSRichard Henderson * in registers, clear the register set for that arg, 267125f49c5fSRichard Henderson * to be filled in below. For args that will be on 267225f49c5fSRichard Henderson * the stack, reset to any available reg. 267325f49c5fSRichard Henderson */ 267425f49c5fSRichard Henderson *la_temp_pref(ts) 267525f49c5fSRichard Henderson = (i < nb_call_regs ? 0 : 267625f49c5fSRichard Henderson tcg_target_available_regs[ts->type]); 267725f49c5fSRichard Henderson ts->state &= ~TS_DEAD; 267825f49c5fSRichard Henderson } 267925f49c5fSRichard Henderson } 268025f49c5fSRichard Henderson 268125f49c5fSRichard Henderson /* For each input argument, add its input register to prefs. 268225f49c5fSRichard Henderson If a temp is used once, this produces a single set bit. */ 268325f49c5fSRichard Henderson for (i = 0; i < MIN(nb_call_regs, nb_iargs); i++) { 268425f49c5fSRichard Henderson ts = arg_temp(op->args[i + nb_oargs]); 268525f49c5fSRichard Henderson if (ts) { 268625f49c5fSRichard Henderson tcg_regset_set_reg(*la_temp_pref(ts), 268725f49c5fSRichard Henderson tcg_target_call_iarg_regs[i]); 2688c70fbf0aSRichard Henderson } 2689c19f47bfSAurelien Jarno } 2690c6e113f5Sbellard } 2691c896fe29Sbellard break; 2692765b842aSRichard Henderson case INDEX_op_insn_start: 2693c896fe29Sbellard break; 26945ff9d6a4Sbellard case INDEX_op_discard: 26955ff9d6a4Sbellard /* mark the temporary as dead */ 269625f49c5fSRichard Henderson ts = arg_temp(op->args[0]); 269725f49c5fSRichard Henderson ts->state = TS_DEAD; 269825f49c5fSRichard Henderson la_reset_pref(ts); 26995ff9d6a4Sbellard break; 27001305c451SRichard Henderson 27011305c451SRichard Henderson case INDEX_op_add2_i32: 2702c45cb8bbSRichard Henderson opc_new = INDEX_op_add_i32; 2703f1fae40cSRichard Henderson goto do_addsub2; 27041305c451SRichard Henderson case INDEX_op_sub2_i32: 2705c45cb8bbSRichard Henderson opc_new = INDEX_op_sub_i32; 2706f1fae40cSRichard Henderson goto do_addsub2; 2707f1fae40cSRichard Henderson case INDEX_op_add2_i64: 2708c45cb8bbSRichard Henderson opc_new = INDEX_op_add_i64; 2709f1fae40cSRichard Henderson goto do_addsub2; 2710f1fae40cSRichard Henderson case INDEX_op_sub2_i64: 2711c45cb8bbSRichard Henderson opc_new = INDEX_op_sub_i64; 2712f1fae40cSRichard Henderson do_addsub2: 27131305c451SRichard Henderson nb_iargs = 4; 27141305c451SRichard Henderson nb_oargs = 2; 27151305c451SRichard Henderson /* Test if the high part of the operation is dead, but not 27161305c451SRichard Henderson the low part. The result can be optimized to a simple 27171305c451SRichard Henderson add or sub. This happens often for x86_64 guest when the 27181305c451SRichard Henderson cpu mode is set to 32 bit. */ 2719b83eabeaSRichard Henderson if (arg_temp(op->args[1])->state == TS_DEAD) { 2720b83eabeaSRichard Henderson if (arg_temp(op->args[0])->state == TS_DEAD) { 27211305c451SRichard Henderson goto do_remove; 27221305c451SRichard Henderson } 2723c45cb8bbSRichard Henderson /* Replace the opcode and adjust the args in place, 2724c45cb8bbSRichard Henderson leaving 3 unused args at the end. */ 2725c45cb8bbSRichard Henderson op->opc = opc = opc_new; 2726efee3746SRichard Henderson op->args[1] = op->args[2]; 2727efee3746SRichard Henderson op->args[2] = op->args[4]; 27281305c451SRichard Henderson /* Fall through and mark the single-word operation live. */ 27291305c451SRichard Henderson nb_iargs = 2; 27301305c451SRichard Henderson nb_oargs = 1; 27311305c451SRichard Henderson } 27321305c451SRichard Henderson goto do_not_remove; 27331305c451SRichard Henderson 27341414968aSRichard Henderson case INDEX_op_mulu2_i32: 2735c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i32; 2736c45cb8bbSRichard Henderson opc_new2 = INDEX_op_muluh_i32; 2737c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_muluh_i32; 273803271524SRichard Henderson goto do_mul2; 2739f1fae40cSRichard Henderson case INDEX_op_muls2_i32: 2740c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i32; 2741c45cb8bbSRichard Henderson opc_new2 = INDEX_op_mulsh_i32; 2742c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_mulsh_i32; 2743f1fae40cSRichard Henderson goto do_mul2; 2744f1fae40cSRichard Henderson case INDEX_op_mulu2_i64: 2745c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i64; 2746c45cb8bbSRichard Henderson opc_new2 = INDEX_op_muluh_i64; 2747c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_muluh_i64; 274803271524SRichard Henderson goto do_mul2; 2749f1fae40cSRichard Henderson case INDEX_op_muls2_i64: 2750c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i64; 2751c45cb8bbSRichard Henderson opc_new2 = INDEX_op_mulsh_i64; 2752c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_mulsh_i64; 275303271524SRichard Henderson goto do_mul2; 2754f1fae40cSRichard Henderson do_mul2: 27551414968aSRichard Henderson nb_iargs = 2; 27561414968aSRichard Henderson nb_oargs = 2; 2757b83eabeaSRichard Henderson if (arg_temp(op->args[1])->state == TS_DEAD) { 2758b83eabeaSRichard Henderson if (arg_temp(op->args[0])->state == TS_DEAD) { 275903271524SRichard Henderson /* Both parts of the operation are dead. */ 27601414968aSRichard Henderson goto do_remove; 27611414968aSRichard Henderson } 276203271524SRichard Henderson /* The high part of the operation is dead; generate the low. */ 2763c45cb8bbSRichard Henderson op->opc = opc = opc_new; 2764efee3746SRichard Henderson op->args[1] = op->args[2]; 2765efee3746SRichard Henderson op->args[2] = op->args[3]; 2766b83eabeaSRichard Henderson } else if (arg_temp(op->args[0])->state == TS_DEAD && have_opc_new2) { 276703271524SRichard Henderson /* The low part of the operation is dead; generate the high. */ 2768c45cb8bbSRichard Henderson op->opc = opc = opc_new2; 2769efee3746SRichard Henderson op->args[0] = op->args[1]; 2770efee3746SRichard Henderson op->args[1] = op->args[2]; 2771efee3746SRichard Henderson op->args[2] = op->args[3]; 277203271524SRichard Henderson } else { 277303271524SRichard Henderson goto do_not_remove; 277403271524SRichard Henderson } 277503271524SRichard Henderson /* Mark the single-word operation live. */ 27761414968aSRichard Henderson nb_oargs = 1; 27771414968aSRichard Henderson goto do_not_remove; 27781414968aSRichard Henderson 2779c896fe29Sbellard default: 27801305c451SRichard Henderson /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */ 2781c896fe29Sbellard nb_iargs = def->nb_iargs; 2782c896fe29Sbellard nb_oargs = def->nb_oargs; 2783c896fe29Sbellard 2784c896fe29Sbellard /* Test if the operation can be removed because all 27855ff9d6a4Sbellard its outputs are dead. We assume that nb_oargs == 0 27865ff9d6a4Sbellard implies side effects */ 27875ff9d6a4Sbellard if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) { 2788c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 2789b83eabeaSRichard Henderson if (arg_temp(op->args[i])->state != TS_DEAD) { 2790c896fe29Sbellard goto do_not_remove; 2791c896fe29Sbellard } 27929c43b68dSAurelien Jarno } 2793152c35aaSRichard Henderson goto do_remove; 2794152c35aaSRichard Henderson } 2795152c35aaSRichard Henderson goto do_not_remove; 2796152c35aaSRichard Henderson 27971305c451SRichard Henderson do_remove: 27980c627cdcSRichard Henderson tcg_op_remove(s, op); 2799152c35aaSRichard Henderson break; 2800152c35aaSRichard Henderson 2801c896fe29Sbellard do_not_remove: 2802c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 280325f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 280425f49c5fSRichard Henderson 280525f49c5fSRichard Henderson /* Remember the preference of the uses that followed. */ 280625f49c5fSRichard Henderson op->output_pref[i] = *la_temp_pref(ts); 280725f49c5fSRichard Henderson 280825f49c5fSRichard Henderson /* Output args are dead. */ 280925f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 2810a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 28116b64b624SAurelien Jarno } 281225f49c5fSRichard Henderson if (ts->state & TS_MEM) { 2813a1b3c48dSRichard Henderson arg_life |= SYNC_ARG << i; 28149c43b68dSAurelien Jarno } 281525f49c5fSRichard Henderson ts->state = TS_DEAD; 281625f49c5fSRichard Henderson la_reset_pref(ts); 2817c896fe29Sbellard } 2818c896fe29Sbellard 281925f49c5fSRichard Henderson /* If end of basic block, update. */ 2820ae36a246SRichard Henderson if (def->flags & TCG_OPF_BB_EXIT) { 2821ae36a246SRichard Henderson la_func_end(s, nb_globals, nb_temps); 2822b4cb76e6SRichard Henderson } else if (def->flags & TCG_OPF_COND_BRANCH) { 2823b4cb76e6SRichard Henderson la_bb_sync(s, nb_globals, nb_temps); 2824ae36a246SRichard Henderson } else if (def->flags & TCG_OPF_BB_END) { 28252616c808SRichard Henderson la_bb_end(s, nb_globals, nb_temps); 28263d5c5f87SAurelien Jarno } else if (def->flags & TCG_OPF_SIDE_EFFECTS) { 2827f65a061cSRichard Henderson la_global_sync(s, nb_globals); 282825f49c5fSRichard Henderson if (def->flags & TCG_OPF_CALL_CLOBBER) { 282925f49c5fSRichard Henderson la_cross_call(s, nb_temps); 283025f49c5fSRichard Henderson } 2831c896fe29Sbellard } 2832c896fe29Sbellard 283325f49c5fSRichard Henderson /* Record arguments that die in this opcode. */ 2834866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 283525f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 283625f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 2837a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 2838c896fe29Sbellard } 2839c19f47bfSAurelien Jarno } 284025f49c5fSRichard Henderson 284125f49c5fSRichard Henderson /* Input arguments are live for preceding opcodes. */ 2842c19f47bfSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 284325f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 284425f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 284525f49c5fSRichard Henderson /* For operands that were dead, initially allow 284625f49c5fSRichard Henderson all regs for the type. */ 284725f49c5fSRichard Henderson *la_temp_pref(ts) = tcg_target_available_regs[ts->type]; 284825f49c5fSRichard Henderson ts->state &= ~TS_DEAD; 284925f49c5fSRichard Henderson } 285025f49c5fSRichard Henderson } 285125f49c5fSRichard Henderson 285225f49c5fSRichard Henderson /* Incorporate constraints for this operand. */ 285325f49c5fSRichard Henderson switch (opc) { 285425f49c5fSRichard Henderson case INDEX_op_mov_i32: 285525f49c5fSRichard Henderson case INDEX_op_mov_i64: 285625f49c5fSRichard Henderson /* Note that these are TCG_OPF_NOT_PRESENT and do not 285725f49c5fSRichard Henderson have proper constraints. That said, special case 285825f49c5fSRichard Henderson moves to propagate preferences backward. */ 285925f49c5fSRichard Henderson if (IS_DEAD_ARG(1)) { 286025f49c5fSRichard Henderson *la_temp_pref(arg_temp(op->args[0])) 286125f49c5fSRichard Henderson = *la_temp_pref(arg_temp(op->args[1])); 286225f49c5fSRichard Henderson } 286325f49c5fSRichard Henderson break; 286425f49c5fSRichard Henderson 286525f49c5fSRichard Henderson default: 286625f49c5fSRichard Henderson for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 286725f49c5fSRichard Henderson const TCGArgConstraint *ct = &def->args_ct[i]; 286825f49c5fSRichard Henderson TCGRegSet set, *pset; 286925f49c5fSRichard Henderson 287025f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 287125f49c5fSRichard Henderson pset = la_temp_pref(ts); 287225f49c5fSRichard Henderson set = *pset; 287325f49c5fSRichard Henderson 28749be0d080SRichard Henderson set &= ct->regs; 2875bc2b17e6SRichard Henderson if (ct->ialias) { 287625f49c5fSRichard Henderson set &= op->output_pref[ct->alias_index]; 287725f49c5fSRichard Henderson } 287825f49c5fSRichard Henderson /* If the combination is not possible, restart. */ 287925f49c5fSRichard Henderson if (set == 0) { 28809be0d080SRichard Henderson set = ct->regs; 288125f49c5fSRichard Henderson } 288225f49c5fSRichard Henderson *pset = set; 288325f49c5fSRichard Henderson } 288425f49c5fSRichard Henderson break; 2885c896fe29Sbellard } 2886c896fe29Sbellard break; 2887c896fe29Sbellard } 2888bee158cbSRichard Henderson op->life = arg_life; 2889c896fe29Sbellard } 28901ff0a2c5SEvgeny Voevodin } 2891c896fe29Sbellard 28925a18407fSRichard Henderson /* Liveness analysis: Convert indirect regs to direct temporaries. */ 2893b83eabeaSRichard Henderson static bool liveness_pass_2(TCGContext *s) 28945a18407fSRichard Henderson { 28955a18407fSRichard Henderson int nb_globals = s->nb_globals; 289615fa08f8SRichard Henderson int nb_temps, i; 28975a18407fSRichard Henderson bool changes = false; 289815fa08f8SRichard Henderson TCGOp *op, *op_next; 28995a18407fSRichard Henderson 29005a18407fSRichard Henderson /* Create a temporary for each indirect global. */ 29015a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) { 29025a18407fSRichard Henderson TCGTemp *its = &s->temps[i]; 29035a18407fSRichard Henderson if (its->indirect_reg) { 29045a18407fSRichard Henderson TCGTemp *dts = tcg_temp_alloc(s); 29055a18407fSRichard Henderson dts->type = its->type; 29065a18407fSRichard Henderson dts->base_type = its->base_type; 2907b83eabeaSRichard Henderson its->state_ptr = dts; 2908b83eabeaSRichard Henderson } else { 2909b83eabeaSRichard Henderson its->state_ptr = NULL; 29105a18407fSRichard Henderson } 2911b83eabeaSRichard Henderson /* All globals begin dead. */ 2912b83eabeaSRichard Henderson its->state = TS_DEAD; 29135a18407fSRichard Henderson } 2914b83eabeaSRichard Henderson for (nb_temps = s->nb_temps; i < nb_temps; ++i) { 2915b83eabeaSRichard Henderson TCGTemp *its = &s->temps[i]; 2916b83eabeaSRichard Henderson its->state_ptr = NULL; 2917b83eabeaSRichard Henderson its->state = TS_DEAD; 2918b83eabeaSRichard Henderson } 29195a18407fSRichard Henderson 292015fa08f8SRichard Henderson QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) { 29215a18407fSRichard Henderson TCGOpcode opc = op->opc; 29225a18407fSRichard Henderson const TCGOpDef *def = &tcg_op_defs[opc]; 29235a18407fSRichard Henderson TCGLifeData arg_life = op->life; 29245a18407fSRichard Henderson int nb_iargs, nb_oargs, call_flags; 2925b83eabeaSRichard Henderson TCGTemp *arg_ts, *dir_ts; 29265a18407fSRichard Henderson 29275a18407fSRichard Henderson if (opc == INDEX_op_call) { 2928cd9090aaSRichard Henderson nb_oargs = TCGOP_CALLO(op); 2929cd9090aaSRichard Henderson nb_iargs = TCGOP_CALLI(op); 2930efee3746SRichard Henderson call_flags = op->args[nb_oargs + nb_iargs + 1]; 29315a18407fSRichard Henderson } else { 29325a18407fSRichard Henderson nb_iargs = def->nb_iargs; 29335a18407fSRichard Henderson nb_oargs = def->nb_oargs; 29345a18407fSRichard Henderson 29355a18407fSRichard Henderson /* Set flags similar to how calls require. */ 2936b4cb76e6SRichard Henderson if (def->flags & TCG_OPF_COND_BRANCH) { 2937b4cb76e6SRichard Henderson /* Like reading globals: sync_globals */ 2938b4cb76e6SRichard Henderson call_flags = TCG_CALL_NO_WRITE_GLOBALS; 2939b4cb76e6SRichard Henderson } else if (def->flags & TCG_OPF_BB_END) { 29405a18407fSRichard Henderson /* Like writing globals: save_globals */ 29415a18407fSRichard Henderson call_flags = 0; 29425a18407fSRichard Henderson } else if (def->flags & TCG_OPF_SIDE_EFFECTS) { 29435a18407fSRichard Henderson /* Like reading globals: sync_globals */ 29445a18407fSRichard Henderson call_flags = TCG_CALL_NO_WRITE_GLOBALS; 29455a18407fSRichard Henderson } else { 29465a18407fSRichard Henderson /* No effect on globals. */ 29475a18407fSRichard Henderson call_flags = (TCG_CALL_NO_READ_GLOBALS | 29485a18407fSRichard Henderson TCG_CALL_NO_WRITE_GLOBALS); 29495a18407fSRichard Henderson } 29505a18407fSRichard Henderson } 29515a18407fSRichard Henderson 29525a18407fSRichard Henderson /* Make sure that input arguments are available. */ 29535a18407fSRichard Henderson for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 2954b83eabeaSRichard Henderson arg_ts = arg_temp(op->args[i]); 2955b83eabeaSRichard Henderson if (arg_ts) { 2956b83eabeaSRichard Henderson dir_ts = arg_ts->state_ptr; 2957b83eabeaSRichard Henderson if (dir_ts && arg_ts->state == TS_DEAD) { 2958b83eabeaSRichard Henderson TCGOpcode lopc = (arg_ts->type == TCG_TYPE_I32 29595a18407fSRichard Henderson ? INDEX_op_ld_i32 29605a18407fSRichard Henderson : INDEX_op_ld_i64); 2961ac1043f6SEmilio G. Cota TCGOp *lop = tcg_op_insert_before(s, op, lopc); 29625a18407fSRichard Henderson 2963b83eabeaSRichard Henderson lop->args[0] = temp_arg(dir_ts); 2964b83eabeaSRichard Henderson lop->args[1] = temp_arg(arg_ts->mem_base); 2965b83eabeaSRichard Henderson lop->args[2] = arg_ts->mem_offset; 29665a18407fSRichard Henderson 29675a18407fSRichard Henderson /* Loaded, but synced with memory. */ 2968b83eabeaSRichard Henderson arg_ts->state = TS_MEM; 29695a18407fSRichard Henderson } 29705a18407fSRichard Henderson } 29715a18407fSRichard Henderson } 29725a18407fSRichard Henderson 29735a18407fSRichard Henderson /* Perform input replacement, and mark inputs that became dead. 29745a18407fSRichard Henderson No action is required except keeping temp_state up to date 29755a18407fSRichard Henderson so that we reload when needed. */ 29765a18407fSRichard Henderson for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 2977b83eabeaSRichard Henderson arg_ts = arg_temp(op->args[i]); 2978b83eabeaSRichard Henderson if (arg_ts) { 2979b83eabeaSRichard Henderson dir_ts = arg_ts->state_ptr; 2980b83eabeaSRichard Henderson if (dir_ts) { 2981b83eabeaSRichard Henderson op->args[i] = temp_arg(dir_ts); 29825a18407fSRichard Henderson changes = true; 29835a18407fSRichard Henderson if (IS_DEAD_ARG(i)) { 2984b83eabeaSRichard Henderson arg_ts->state = TS_DEAD; 29855a18407fSRichard Henderson } 29865a18407fSRichard Henderson } 29875a18407fSRichard Henderson } 29885a18407fSRichard Henderson } 29895a18407fSRichard Henderson 29905a18407fSRichard Henderson /* Liveness analysis should ensure that the following are 29915a18407fSRichard Henderson all correct, for call sites and basic block end points. */ 29925a18407fSRichard Henderson if (call_flags & TCG_CALL_NO_READ_GLOBALS) { 29935a18407fSRichard Henderson /* Nothing to do */ 29945a18407fSRichard Henderson } else if (call_flags & TCG_CALL_NO_WRITE_GLOBALS) { 29955a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) { 29965a18407fSRichard Henderson /* Liveness should see that globals are synced back, 29975a18407fSRichard Henderson that is, either TS_DEAD or TS_MEM. */ 2998b83eabeaSRichard Henderson arg_ts = &s->temps[i]; 2999b83eabeaSRichard Henderson tcg_debug_assert(arg_ts->state_ptr == 0 3000b83eabeaSRichard Henderson || arg_ts->state != 0); 30015a18407fSRichard Henderson } 30025a18407fSRichard Henderson } else { 30035a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) { 30045a18407fSRichard Henderson /* Liveness should see that globals are saved back, 30055a18407fSRichard Henderson that is, TS_DEAD, waiting to be reloaded. */ 3006b83eabeaSRichard Henderson arg_ts = &s->temps[i]; 3007b83eabeaSRichard Henderson tcg_debug_assert(arg_ts->state_ptr == 0 3008b83eabeaSRichard Henderson || arg_ts->state == TS_DEAD); 30095a18407fSRichard Henderson } 30105a18407fSRichard Henderson } 30115a18407fSRichard Henderson 30125a18407fSRichard Henderson /* Outputs become available. */ 301361f15c48SRichard Henderson if (opc == INDEX_op_mov_i32 || opc == INDEX_op_mov_i64) { 301461f15c48SRichard Henderson arg_ts = arg_temp(op->args[0]); 301561f15c48SRichard Henderson dir_ts = arg_ts->state_ptr; 301661f15c48SRichard Henderson if (dir_ts) { 301761f15c48SRichard Henderson op->args[0] = temp_arg(dir_ts); 301861f15c48SRichard Henderson changes = true; 301961f15c48SRichard Henderson 302061f15c48SRichard Henderson /* The output is now live and modified. */ 302161f15c48SRichard Henderson arg_ts->state = 0; 302261f15c48SRichard Henderson 302361f15c48SRichard Henderson if (NEED_SYNC_ARG(0)) { 302461f15c48SRichard Henderson TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32 302561f15c48SRichard Henderson ? INDEX_op_st_i32 302661f15c48SRichard Henderson : INDEX_op_st_i64); 302761f15c48SRichard Henderson TCGOp *sop = tcg_op_insert_after(s, op, sopc); 302861f15c48SRichard Henderson TCGTemp *out_ts = dir_ts; 302961f15c48SRichard Henderson 303061f15c48SRichard Henderson if (IS_DEAD_ARG(0)) { 303161f15c48SRichard Henderson out_ts = arg_temp(op->args[1]); 303261f15c48SRichard Henderson arg_ts->state = TS_DEAD; 303361f15c48SRichard Henderson tcg_op_remove(s, op); 303461f15c48SRichard Henderson } else { 303561f15c48SRichard Henderson arg_ts->state = TS_MEM; 303661f15c48SRichard Henderson } 303761f15c48SRichard Henderson 303861f15c48SRichard Henderson sop->args[0] = temp_arg(out_ts); 303961f15c48SRichard Henderson sop->args[1] = temp_arg(arg_ts->mem_base); 304061f15c48SRichard Henderson sop->args[2] = arg_ts->mem_offset; 304161f15c48SRichard Henderson } else { 304261f15c48SRichard Henderson tcg_debug_assert(!IS_DEAD_ARG(0)); 304361f15c48SRichard Henderson } 304461f15c48SRichard Henderson } 304561f15c48SRichard Henderson } else { 30465a18407fSRichard Henderson for (i = 0; i < nb_oargs; i++) { 3047b83eabeaSRichard Henderson arg_ts = arg_temp(op->args[i]); 3048b83eabeaSRichard Henderson dir_ts = arg_ts->state_ptr; 3049b83eabeaSRichard Henderson if (!dir_ts) { 30505a18407fSRichard Henderson continue; 30515a18407fSRichard Henderson } 3052b83eabeaSRichard Henderson op->args[i] = temp_arg(dir_ts); 30535a18407fSRichard Henderson changes = true; 30545a18407fSRichard Henderson 30555a18407fSRichard Henderson /* The output is now live and modified. */ 3056b83eabeaSRichard Henderson arg_ts->state = 0; 30575a18407fSRichard Henderson 30585a18407fSRichard Henderson /* Sync outputs upon their last write. */ 30595a18407fSRichard Henderson if (NEED_SYNC_ARG(i)) { 3060b83eabeaSRichard Henderson TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32 30615a18407fSRichard Henderson ? INDEX_op_st_i32 30625a18407fSRichard Henderson : INDEX_op_st_i64); 3063ac1043f6SEmilio G. Cota TCGOp *sop = tcg_op_insert_after(s, op, sopc); 30645a18407fSRichard Henderson 3065b83eabeaSRichard Henderson sop->args[0] = temp_arg(dir_ts); 3066b83eabeaSRichard Henderson sop->args[1] = temp_arg(arg_ts->mem_base); 3067b83eabeaSRichard Henderson sop->args[2] = arg_ts->mem_offset; 30685a18407fSRichard Henderson 3069b83eabeaSRichard Henderson arg_ts->state = TS_MEM; 30705a18407fSRichard Henderson } 30715a18407fSRichard Henderson /* Drop outputs that are dead. */ 30725a18407fSRichard Henderson if (IS_DEAD_ARG(i)) { 3073b83eabeaSRichard Henderson arg_ts->state = TS_DEAD; 30745a18407fSRichard Henderson } 30755a18407fSRichard Henderson } 30765a18407fSRichard Henderson } 307761f15c48SRichard Henderson } 30785a18407fSRichard Henderson 30795a18407fSRichard Henderson return changes; 30805a18407fSRichard Henderson } 30815a18407fSRichard Henderson 30828d8fdbaeSAurelien Jarno #ifdef CONFIG_DEBUG_TCG 3083c896fe29Sbellard static void dump_regs(TCGContext *s) 3084c896fe29Sbellard { 3085c896fe29Sbellard TCGTemp *ts; 3086c896fe29Sbellard int i; 3087c896fe29Sbellard char buf[64]; 3088c896fe29Sbellard 3089c896fe29Sbellard for(i = 0; i < s->nb_temps; i++) { 3090c896fe29Sbellard ts = &s->temps[i]; 309143439139SRichard Henderson printf(" %10s: ", tcg_get_arg_str_ptr(s, buf, sizeof(buf), ts)); 3092c896fe29Sbellard switch(ts->val_type) { 3093c896fe29Sbellard case TEMP_VAL_REG: 3094c896fe29Sbellard printf("%s", tcg_target_reg_names[ts->reg]); 3095c896fe29Sbellard break; 3096c896fe29Sbellard case TEMP_VAL_MEM: 3097b3a62939SRichard Henderson printf("%d(%s)", (int)ts->mem_offset, 3098b3a62939SRichard Henderson tcg_target_reg_names[ts->mem_base->reg]); 3099c896fe29Sbellard break; 3100c896fe29Sbellard case TEMP_VAL_CONST: 3101c896fe29Sbellard printf("$0x%" TCG_PRIlx, ts->val); 3102c896fe29Sbellard break; 3103c896fe29Sbellard case TEMP_VAL_DEAD: 3104c896fe29Sbellard printf("D"); 3105c896fe29Sbellard break; 3106c896fe29Sbellard default: 3107c896fe29Sbellard printf("???"); 3108c896fe29Sbellard break; 3109c896fe29Sbellard } 3110c896fe29Sbellard printf("\n"); 3111c896fe29Sbellard } 3112c896fe29Sbellard 3113c896fe29Sbellard for(i = 0; i < TCG_TARGET_NB_REGS; i++) { 3114f8b2f202SRichard Henderson if (s->reg_to_temp[i] != NULL) { 3115c896fe29Sbellard printf("%s: %s\n", 3116c896fe29Sbellard tcg_target_reg_names[i], 3117f8b2f202SRichard Henderson tcg_get_arg_str_ptr(s, buf, sizeof(buf), s->reg_to_temp[i])); 3118c896fe29Sbellard } 3119c896fe29Sbellard } 3120c896fe29Sbellard } 3121c896fe29Sbellard 3122c896fe29Sbellard static void check_regs(TCGContext *s) 3123c896fe29Sbellard { 3124869938aeSRichard Henderson int reg; 3125b6638662SRichard Henderson int k; 3126c896fe29Sbellard TCGTemp *ts; 3127c896fe29Sbellard char buf[64]; 3128c896fe29Sbellard 3129c896fe29Sbellard for (reg = 0; reg < TCG_TARGET_NB_REGS; reg++) { 3130f8b2f202SRichard Henderson ts = s->reg_to_temp[reg]; 3131f8b2f202SRichard Henderson if (ts != NULL) { 3132f8b2f202SRichard Henderson if (ts->val_type != TEMP_VAL_REG || ts->reg != reg) { 3133c896fe29Sbellard printf("Inconsistency for register %s:\n", 3134c896fe29Sbellard tcg_target_reg_names[reg]); 3135b03cce8eSbellard goto fail; 3136c896fe29Sbellard } 3137c896fe29Sbellard } 3138c896fe29Sbellard } 3139c896fe29Sbellard for (k = 0; k < s->nb_temps; k++) { 3140c896fe29Sbellard ts = &s->temps[k]; 3141f8b2f202SRichard Henderson if (ts->val_type == TEMP_VAL_REG && !ts->fixed_reg 3142f8b2f202SRichard Henderson && s->reg_to_temp[ts->reg] != ts) { 3143c896fe29Sbellard printf("Inconsistency for temp %s:\n", 3144f8b2f202SRichard Henderson tcg_get_arg_str_ptr(s, buf, sizeof(buf), ts)); 3145b03cce8eSbellard fail: 3146c896fe29Sbellard printf("reg state:\n"); 3147c896fe29Sbellard dump_regs(s); 3148c896fe29Sbellard tcg_abort(); 3149c896fe29Sbellard } 3150c896fe29Sbellard } 3151c896fe29Sbellard } 3152c896fe29Sbellard #endif 3153c896fe29Sbellard 31542272e4a7SRichard Henderson static void temp_allocate_frame(TCGContext *s, TCGTemp *ts) 3155c896fe29Sbellard { 31569b9c37c3SRichard Henderson #if !(defined(__sparc__) && TCG_TARGET_REG_BITS == 64) 31579b9c37c3SRichard Henderson /* Sparc64 stack is accessed with offset of 2047 */ 3158b591dc59SBlue Swirl s->current_frame_offset = (s->current_frame_offset + 3159b591dc59SBlue Swirl (tcg_target_long)sizeof(tcg_target_long) - 1) & 3160b591dc59SBlue Swirl ~(sizeof(tcg_target_long) - 1); 3161f44c9960SBlue Swirl #endif 3162b591dc59SBlue Swirl if (s->current_frame_offset + (tcg_target_long)sizeof(tcg_target_long) > 3163b591dc59SBlue Swirl s->frame_end) { 31645ff9d6a4Sbellard tcg_abort(); 3165b591dc59SBlue Swirl } 3166c896fe29Sbellard ts->mem_offset = s->current_frame_offset; 3167b3a62939SRichard Henderson ts->mem_base = s->frame_temp; 3168c896fe29Sbellard ts->mem_allocated = 1; 3169e2c6d1b4SRichard Henderson s->current_frame_offset += sizeof(tcg_target_long); 3170c896fe29Sbellard } 3171c896fe29Sbellard 3172b722452aSRichard Henderson static void temp_load(TCGContext *, TCGTemp *, TCGRegSet, TCGRegSet, TCGRegSet); 3173b3915dbbSRichard Henderson 317459d7c14eSRichard Henderson /* Mark a temporary as free or dead. If 'free_or_dead' is negative, 317559d7c14eSRichard Henderson mark it free; otherwise mark it dead. */ 317659d7c14eSRichard Henderson static void temp_free_or_dead(TCGContext *s, TCGTemp *ts, int free_or_dead) 3177c896fe29Sbellard { 317859d7c14eSRichard Henderson if (ts->fixed_reg) { 317959d7c14eSRichard Henderson return; 318059d7c14eSRichard Henderson } 318159d7c14eSRichard Henderson if (ts->val_type == TEMP_VAL_REG) { 318259d7c14eSRichard Henderson s->reg_to_temp[ts->reg] = NULL; 318359d7c14eSRichard Henderson } 318459d7c14eSRichard Henderson ts->val_type = (free_or_dead < 0 318559d7c14eSRichard Henderson || ts->temp_local 3186fa477d25SRichard Henderson || ts->temp_global 318759d7c14eSRichard Henderson ? TEMP_VAL_MEM : TEMP_VAL_DEAD); 318859d7c14eSRichard Henderson } 3189c896fe29Sbellard 319059d7c14eSRichard Henderson /* Mark a temporary as dead. */ 319159d7c14eSRichard Henderson static inline void temp_dead(TCGContext *s, TCGTemp *ts) 319259d7c14eSRichard Henderson { 319359d7c14eSRichard Henderson temp_free_or_dead(s, ts, 1); 319459d7c14eSRichard Henderson } 319559d7c14eSRichard Henderson 319659d7c14eSRichard Henderson /* Sync a temporary to memory. 'allocated_regs' is used in case a temporary 319759d7c14eSRichard Henderson registers needs to be allocated to store a constant. If 'free_or_dead' 319859d7c14eSRichard Henderson is non-zero, subsequently release the temporary; if it is positive, the 319959d7c14eSRichard Henderson temp is dead; if it is negative, the temp is free. */ 320098b4e186SRichard Henderson static void temp_sync(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs, 320198b4e186SRichard Henderson TCGRegSet preferred_regs, int free_or_dead) 320259d7c14eSRichard Henderson { 320359d7c14eSRichard Henderson if (ts->fixed_reg) { 320459d7c14eSRichard Henderson return; 320559d7c14eSRichard Henderson } 320659d7c14eSRichard Henderson if (!ts->mem_coherent) { 32077f6ceedfSAurelien Jarno if (!ts->mem_allocated) { 32082272e4a7SRichard Henderson temp_allocate_frame(s, ts); 320959d7c14eSRichard Henderson } 321059d7c14eSRichard Henderson switch (ts->val_type) { 321159d7c14eSRichard Henderson case TEMP_VAL_CONST: 321259d7c14eSRichard Henderson /* If we're going to free the temp immediately, then we won't 321359d7c14eSRichard Henderson require it later in a register, so attempt to store the 321459d7c14eSRichard Henderson constant to memory directly. */ 321559d7c14eSRichard Henderson if (free_or_dead 321659d7c14eSRichard Henderson && tcg_out_sti(s, ts->type, ts->val, 321759d7c14eSRichard Henderson ts->mem_base->reg, ts->mem_offset)) { 321859d7c14eSRichard Henderson break; 321959d7c14eSRichard Henderson } 322059d7c14eSRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], 322198b4e186SRichard Henderson allocated_regs, preferred_regs); 322259d7c14eSRichard Henderson /* fallthrough */ 322359d7c14eSRichard Henderson 322459d7c14eSRichard Henderson case TEMP_VAL_REG: 322559d7c14eSRichard Henderson tcg_out_st(s, ts->type, ts->reg, 322659d7c14eSRichard Henderson ts->mem_base->reg, ts->mem_offset); 322759d7c14eSRichard Henderson break; 322859d7c14eSRichard Henderson 322959d7c14eSRichard Henderson case TEMP_VAL_MEM: 323059d7c14eSRichard Henderson break; 323159d7c14eSRichard Henderson 323259d7c14eSRichard Henderson case TEMP_VAL_DEAD: 323359d7c14eSRichard Henderson default: 323459d7c14eSRichard Henderson tcg_abort(); 3235c896fe29Sbellard } 32367f6ceedfSAurelien Jarno ts->mem_coherent = 1; 32377f6ceedfSAurelien Jarno } 323859d7c14eSRichard Henderson if (free_or_dead) { 323959d7c14eSRichard Henderson temp_free_or_dead(s, ts, free_or_dead); 324059d7c14eSRichard Henderson } 324159d7c14eSRichard Henderson } 32427f6ceedfSAurelien Jarno 32437f6ceedfSAurelien Jarno /* free register 'reg' by spilling the corresponding temporary if necessary */ 3244b3915dbbSRichard Henderson static void tcg_reg_free(TCGContext *s, TCGReg reg, TCGRegSet allocated_regs) 32457f6ceedfSAurelien Jarno { 3246f8b2f202SRichard Henderson TCGTemp *ts = s->reg_to_temp[reg]; 3247f8b2f202SRichard Henderson if (ts != NULL) { 324898b4e186SRichard Henderson temp_sync(s, ts, allocated_regs, 0, -1); 3249c896fe29Sbellard } 3250c896fe29Sbellard } 3251c896fe29Sbellard 3252b016486eSRichard Henderson /** 3253b016486eSRichard Henderson * tcg_reg_alloc: 3254b016486eSRichard Henderson * @required_regs: Set of registers in which we must allocate. 3255b016486eSRichard Henderson * @allocated_regs: Set of registers which must be avoided. 3256b016486eSRichard Henderson * @preferred_regs: Set of registers we should prefer. 3257b016486eSRichard Henderson * @rev: True if we search the registers in "indirect" order. 3258b016486eSRichard Henderson * 3259b016486eSRichard Henderson * The allocated register must be in @required_regs & ~@allocated_regs, 3260b016486eSRichard Henderson * but if we can put it in @preferred_regs we may save a move later. 3261b016486eSRichard Henderson */ 3262b016486eSRichard Henderson static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet required_regs, 3263b016486eSRichard Henderson TCGRegSet allocated_regs, 3264b016486eSRichard Henderson TCGRegSet preferred_regs, bool rev) 3265c896fe29Sbellard { 3266b016486eSRichard Henderson int i, j, f, n = ARRAY_SIZE(tcg_target_reg_alloc_order); 3267b016486eSRichard Henderson TCGRegSet reg_ct[2]; 326891478cefSRichard Henderson const int *order; 3269c896fe29Sbellard 3270b016486eSRichard Henderson reg_ct[1] = required_regs & ~allocated_regs; 3271b016486eSRichard Henderson tcg_debug_assert(reg_ct[1] != 0); 3272b016486eSRichard Henderson reg_ct[0] = reg_ct[1] & preferred_regs; 3273b016486eSRichard Henderson 3274b016486eSRichard Henderson /* Skip the preferred_regs option if it cannot be satisfied, 3275b016486eSRichard Henderson or if the preference made no difference. */ 3276b016486eSRichard Henderson f = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1]; 3277b016486eSRichard Henderson 327891478cefSRichard Henderson order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order; 3279c896fe29Sbellard 3280b016486eSRichard Henderson /* Try free registers, preferences first. */ 3281b016486eSRichard Henderson for (j = f; j < 2; j++) { 3282b016486eSRichard Henderson TCGRegSet set = reg_ct[j]; 3283b016486eSRichard Henderson 3284b016486eSRichard Henderson if (tcg_regset_single(set)) { 3285b016486eSRichard Henderson /* One register in the set. */ 3286b016486eSRichard Henderson TCGReg reg = tcg_regset_first(set); 3287b016486eSRichard Henderson if (s->reg_to_temp[reg] == NULL) { 3288c896fe29Sbellard return reg; 3289c896fe29Sbellard } 3290b016486eSRichard Henderson } else { 329191478cefSRichard Henderson for (i = 0; i < n; i++) { 3292b016486eSRichard Henderson TCGReg reg = order[i]; 3293b016486eSRichard Henderson if (s->reg_to_temp[reg] == NULL && 3294b016486eSRichard Henderson tcg_regset_test_reg(set, reg)) { 3295b016486eSRichard Henderson return reg; 3296b016486eSRichard Henderson } 3297b016486eSRichard Henderson } 3298b016486eSRichard Henderson } 3299b016486eSRichard Henderson } 3300b016486eSRichard Henderson 3301b016486eSRichard Henderson /* We must spill something. */ 3302b016486eSRichard Henderson for (j = f; j < 2; j++) { 3303b016486eSRichard Henderson TCGRegSet set = reg_ct[j]; 3304b016486eSRichard Henderson 3305b016486eSRichard Henderson if (tcg_regset_single(set)) { 3306b016486eSRichard Henderson /* One register in the set. */ 3307b016486eSRichard Henderson TCGReg reg = tcg_regset_first(set); 3308b3915dbbSRichard Henderson tcg_reg_free(s, reg, allocated_regs); 3309c896fe29Sbellard return reg; 3310b016486eSRichard Henderson } else { 3311b016486eSRichard Henderson for (i = 0; i < n; i++) { 3312b016486eSRichard Henderson TCGReg reg = order[i]; 3313b016486eSRichard Henderson if (tcg_regset_test_reg(set, reg)) { 3314b016486eSRichard Henderson tcg_reg_free(s, reg, allocated_regs); 3315b016486eSRichard Henderson return reg; 3316b016486eSRichard Henderson } 3317b016486eSRichard Henderson } 3318c896fe29Sbellard } 3319c896fe29Sbellard } 3320c896fe29Sbellard 3321c896fe29Sbellard tcg_abort(); 3322c896fe29Sbellard } 3323c896fe29Sbellard 332440ae5c62SRichard Henderson /* Make sure the temporary is in a register. If needed, allocate the register 332540ae5c62SRichard Henderson from DESIRED while avoiding ALLOCATED. */ 332640ae5c62SRichard Henderson static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs, 3327b722452aSRichard Henderson TCGRegSet allocated_regs, TCGRegSet preferred_regs) 332840ae5c62SRichard Henderson { 332940ae5c62SRichard Henderson TCGReg reg; 333040ae5c62SRichard Henderson 333140ae5c62SRichard Henderson switch (ts->val_type) { 333240ae5c62SRichard Henderson case TEMP_VAL_REG: 333340ae5c62SRichard Henderson return; 333440ae5c62SRichard Henderson case TEMP_VAL_CONST: 3335b016486eSRichard Henderson reg = tcg_reg_alloc(s, desired_regs, allocated_regs, 3336b722452aSRichard Henderson preferred_regs, ts->indirect_base); 333740ae5c62SRichard Henderson tcg_out_movi(s, ts->type, reg, ts->val); 333840ae5c62SRichard Henderson ts->mem_coherent = 0; 333940ae5c62SRichard Henderson break; 334040ae5c62SRichard Henderson case TEMP_VAL_MEM: 3341b016486eSRichard Henderson reg = tcg_reg_alloc(s, desired_regs, allocated_regs, 3342b722452aSRichard Henderson preferred_regs, ts->indirect_base); 334340ae5c62SRichard Henderson tcg_out_ld(s, ts->type, reg, ts->mem_base->reg, ts->mem_offset); 334440ae5c62SRichard Henderson ts->mem_coherent = 1; 334540ae5c62SRichard Henderson break; 334640ae5c62SRichard Henderson case TEMP_VAL_DEAD: 334740ae5c62SRichard Henderson default: 334840ae5c62SRichard Henderson tcg_abort(); 334940ae5c62SRichard Henderson } 335040ae5c62SRichard Henderson ts->reg = reg; 335140ae5c62SRichard Henderson ts->val_type = TEMP_VAL_REG; 335240ae5c62SRichard Henderson s->reg_to_temp[reg] = ts; 335340ae5c62SRichard Henderson } 335440ae5c62SRichard Henderson 335559d7c14eSRichard Henderson /* Save a temporary to memory. 'allocated_regs' is used in case a 3356e8996ee0Sbellard temporary registers needs to be allocated to store a constant. */ 335759d7c14eSRichard Henderson static void temp_save(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs) 33581ad80729SAurelien Jarno { 33592c0366f0SAurelien Jarno /* The liveness analysis already ensures that globals are back 3360eabb7b91SAurelien Jarno in memory. Keep an tcg_debug_assert for safety. */ 3361f8bf00f1SRichard Henderson tcg_debug_assert(ts->val_type == TEMP_VAL_MEM || ts->fixed_reg); 33621ad80729SAurelien Jarno } 33631ad80729SAurelien Jarno 33649814dd27SDong Xu Wang /* save globals to their canonical location and assume they can be 3365641d5fbeSbellard modified be the following code. 'allocated_regs' is used in case a 3366641d5fbeSbellard temporary registers needs to be allocated to store a constant. */ 3367641d5fbeSbellard static void save_globals(TCGContext *s, TCGRegSet allocated_regs) 3368641d5fbeSbellard { 3369ac3b8891SRichard Henderson int i, n; 3370641d5fbeSbellard 3371ac3b8891SRichard Henderson for (i = 0, n = s->nb_globals; i < n; i++) { 3372b13eb728SRichard Henderson temp_save(s, &s->temps[i], allocated_regs); 3373641d5fbeSbellard } 3374e5097dc8Sbellard } 3375e5097dc8Sbellard 33763d5c5f87SAurelien Jarno /* sync globals to their canonical location and assume they can be 33773d5c5f87SAurelien Jarno read by the following code. 'allocated_regs' is used in case a 33783d5c5f87SAurelien Jarno temporary registers needs to be allocated to store a constant. */ 33793d5c5f87SAurelien Jarno static void sync_globals(TCGContext *s, TCGRegSet allocated_regs) 33803d5c5f87SAurelien Jarno { 3381ac3b8891SRichard Henderson int i, n; 33823d5c5f87SAurelien Jarno 3383ac3b8891SRichard Henderson for (i = 0, n = s->nb_globals; i < n; i++) { 338412b9b11aSRichard Henderson TCGTemp *ts = &s->temps[i]; 338512b9b11aSRichard Henderson tcg_debug_assert(ts->val_type != TEMP_VAL_REG 338612b9b11aSRichard Henderson || ts->fixed_reg 338712b9b11aSRichard Henderson || ts->mem_coherent); 33883d5c5f87SAurelien Jarno } 33893d5c5f87SAurelien Jarno } 33903d5c5f87SAurelien Jarno 3391e5097dc8Sbellard /* at the end of a basic block, we assume all temporaries are dead and 3392e8996ee0Sbellard all globals are stored at their canonical location. */ 3393e8996ee0Sbellard static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs) 3394e5097dc8Sbellard { 3395e5097dc8Sbellard int i; 3396e5097dc8Sbellard 3397c896fe29Sbellard for (i = s->nb_globals; i < s->nb_temps; i++) { 3398b13eb728SRichard Henderson TCGTemp *ts = &s->temps[i]; 3399641d5fbeSbellard if (ts->temp_local) { 3400b13eb728SRichard Henderson temp_save(s, ts, allocated_regs); 3401641d5fbeSbellard } else { 34022c0366f0SAurelien Jarno /* The liveness analysis already ensures that temps are dead. 3403eabb7b91SAurelien Jarno Keep an tcg_debug_assert for safety. */ 3404eabb7b91SAurelien Jarno tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD); 3405c896fe29Sbellard } 3406641d5fbeSbellard } 3407e8996ee0Sbellard 3408e8996ee0Sbellard save_globals(s, allocated_regs); 3409c896fe29Sbellard } 3410c896fe29Sbellard 3411bab1671fSRichard Henderson /* 3412b4cb76e6SRichard Henderson * At a conditional branch, we assume all temporaries are dead and 3413b4cb76e6SRichard Henderson * all globals and local temps are synced to their location. 3414b4cb76e6SRichard Henderson */ 3415b4cb76e6SRichard Henderson static void tcg_reg_alloc_cbranch(TCGContext *s, TCGRegSet allocated_regs) 3416b4cb76e6SRichard Henderson { 3417b4cb76e6SRichard Henderson sync_globals(s, allocated_regs); 3418b4cb76e6SRichard Henderson 3419b4cb76e6SRichard Henderson for (int i = s->nb_globals; i < s->nb_temps; i++) { 3420b4cb76e6SRichard Henderson TCGTemp *ts = &s->temps[i]; 3421b4cb76e6SRichard Henderson /* 3422b4cb76e6SRichard Henderson * The liveness analysis already ensures that temps are dead. 3423b4cb76e6SRichard Henderson * Keep tcg_debug_asserts for safety. 3424b4cb76e6SRichard Henderson */ 3425b4cb76e6SRichard Henderson if (ts->temp_local) { 3426b4cb76e6SRichard Henderson tcg_debug_assert(ts->val_type != TEMP_VAL_REG || ts->mem_coherent); 3427b4cb76e6SRichard Henderson } else { 3428b4cb76e6SRichard Henderson tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD); 3429b4cb76e6SRichard Henderson } 3430b4cb76e6SRichard Henderson } 3431b4cb76e6SRichard Henderson } 3432b4cb76e6SRichard Henderson 3433b4cb76e6SRichard Henderson /* 3434bab1671fSRichard Henderson * Specialized code generation for INDEX_op_movi_*. 3435bab1671fSRichard Henderson */ 34360fe4fca4SPaolo Bonzini static void tcg_reg_alloc_do_movi(TCGContext *s, TCGTemp *ots, 3437ba87719cSRichard Henderson tcg_target_ulong val, TCGLifeData arg_life, 3438ba87719cSRichard Henderson TCGRegSet preferred_regs) 3439e8996ee0Sbellard { 3440d63e3b6eSRichard Henderson /* ENV should not be modified. */ 3441d63e3b6eSRichard Henderson tcg_debug_assert(!ots->fixed_reg); 344259d7c14eSRichard Henderson 344359d7c14eSRichard Henderson /* The movi is not explicitly generated here. */ 3444f8b2f202SRichard Henderson if (ots->val_type == TEMP_VAL_REG) { 3445f8b2f202SRichard Henderson s->reg_to_temp[ots->reg] = NULL; 3446f8b2f202SRichard Henderson } 3447e8996ee0Sbellard ots->val_type = TEMP_VAL_CONST; 3448e8996ee0Sbellard ots->val = val; 344959d7c14eSRichard Henderson ots->mem_coherent = 0; 3450ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(0)) { 3451ba87719cSRichard Henderson temp_sync(s, ots, s->reserved_regs, preferred_regs, IS_DEAD_ARG(0)); 345259d7c14eSRichard Henderson } else if (IS_DEAD_ARG(0)) { 3453f8bf00f1SRichard Henderson temp_dead(s, ots); 34544c4e1ab2SAurelien Jarno } 3455e8996ee0Sbellard } 3456e8996ee0Sbellard 3457dd186292SRichard Henderson static void tcg_reg_alloc_movi(TCGContext *s, const TCGOp *op) 34580fe4fca4SPaolo Bonzini { 345943439139SRichard Henderson TCGTemp *ots = arg_temp(op->args[0]); 3460dd186292SRichard Henderson tcg_target_ulong val = op->args[1]; 34610fe4fca4SPaolo Bonzini 346269e3706dSRichard Henderson tcg_reg_alloc_do_movi(s, ots, val, op->life, op->output_pref[0]); 34630fe4fca4SPaolo Bonzini } 34640fe4fca4SPaolo Bonzini 3465bab1671fSRichard Henderson /* 3466bab1671fSRichard Henderson * Specialized code generation for INDEX_op_mov_*. 3467bab1671fSRichard Henderson */ 3468dd186292SRichard Henderson static void tcg_reg_alloc_mov(TCGContext *s, const TCGOp *op) 3469c896fe29Sbellard { 3470dd186292SRichard Henderson const TCGLifeData arg_life = op->life; 347169e3706dSRichard Henderson TCGRegSet allocated_regs, preferred_regs; 3472c896fe29Sbellard TCGTemp *ts, *ots; 3473450445d5SRichard Henderson TCGType otype, itype; 3474c896fe29Sbellard 3475d21369f5SRichard Henderson allocated_regs = s->reserved_regs; 347669e3706dSRichard Henderson preferred_regs = op->output_pref[0]; 347743439139SRichard Henderson ots = arg_temp(op->args[0]); 347843439139SRichard Henderson ts = arg_temp(op->args[1]); 3479450445d5SRichard Henderson 3480d63e3b6eSRichard Henderson /* ENV should not be modified. */ 3481d63e3b6eSRichard Henderson tcg_debug_assert(!ots->fixed_reg); 3482d63e3b6eSRichard Henderson 3483450445d5SRichard Henderson /* Note that otype != itype for no-op truncation. */ 3484450445d5SRichard Henderson otype = ots->type; 3485450445d5SRichard Henderson itype = ts->type; 3486c896fe29Sbellard 34870fe4fca4SPaolo Bonzini if (ts->val_type == TEMP_VAL_CONST) { 34880fe4fca4SPaolo Bonzini /* propagate constant or generate sti */ 34890fe4fca4SPaolo Bonzini tcg_target_ulong val = ts->val; 34900fe4fca4SPaolo Bonzini if (IS_DEAD_ARG(1)) { 34910fe4fca4SPaolo Bonzini temp_dead(s, ts); 34920fe4fca4SPaolo Bonzini } 349369e3706dSRichard Henderson tcg_reg_alloc_do_movi(s, ots, val, arg_life, preferred_regs); 34940fe4fca4SPaolo Bonzini return; 34950fe4fca4SPaolo Bonzini } 34960fe4fca4SPaolo Bonzini 34970fe4fca4SPaolo Bonzini /* If the source value is in memory we're going to be forced 34980fe4fca4SPaolo Bonzini to have it in a register in order to perform the copy. Copy 34990fe4fca4SPaolo Bonzini the SOURCE value into its own register first, that way we 35000fe4fca4SPaolo Bonzini don't have to reload SOURCE the next time it is used. */ 35010fe4fca4SPaolo Bonzini if (ts->val_type == TEMP_VAL_MEM) { 350269e3706dSRichard Henderson temp_load(s, ts, tcg_target_available_regs[itype], 350369e3706dSRichard Henderson allocated_regs, preferred_regs); 3504c29c1d7eSAurelien Jarno } 3505c29c1d7eSAurelien Jarno 35060fe4fca4SPaolo Bonzini tcg_debug_assert(ts->val_type == TEMP_VAL_REG); 3507d63e3b6eSRichard Henderson if (IS_DEAD_ARG(0)) { 3508c29c1d7eSAurelien Jarno /* mov to a non-saved dead register makes no sense (even with 3509c29c1d7eSAurelien Jarno liveness analysis disabled). */ 3510eabb7b91SAurelien Jarno tcg_debug_assert(NEED_SYNC_ARG(0)); 3511c29c1d7eSAurelien Jarno if (!ots->mem_allocated) { 35122272e4a7SRichard Henderson temp_allocate_frame(s, ots); 3513c29c1d7eSAurelien Jarno } 3514b3a62939SRichard Henderson tcg_out_st(s, otype, ts->reg, ots->mem_base->reg, ots->mem_offset); 3515c29c1d7eSAurelien Jarno if (IS_DEAD_ARG(1)) { 3516f8bf00f1SRichard Henderson temp_dead(s, ts); 3517c29c1d7eSAurelien Jarno } 3518f8bf00f1SRichard Henderson temp_dead(s, ots); 3519e8996ee0Sbellard } else { 3520d63e3b6eSRichard Henderson if (IS_DEAD_ARG(1) && !ts->fixed_reg) { 3521c29c1d7eSAurelien Jarno /* the mov can be suppressed */ 3522c29c1d7eSAurelien Jarno if (ots->val_type == TEMP_VAL_REG) { 3523f8b2f202SRichard Henderson s->reg_to_temp[ots->reg] = NULL; 3524c896fe29Sbellard } 3525c29c1d7eSAurelien Jarno ots->reg = ts->reg; 3526f8bf00f1SRichard Henderson temp_dead(s, ts); 3527c29c1d7eSAurelien Jarno } else { 3528c29c1d7eSAurelien Jarno if (ots->val_type != TEMP_VAL_REG) { 3529c29c1d7eSAurelien Jarno /* When allocating a new register, make sure to not spill the 3530c29c1d7eSAurelien Jarno input one. */ 3531c29c1d7eSAurelien Jarno tcg_regset_set_reg(allocated_regs, ts->reg); 3532450445d5SRichard Henderson ots->reg = tcg_reg_alloc(s, tcg_target_available_regs[otype], 353369e3706dSRichard Henderson allocated_regs, preferred_regs, 3534b016486eSRichard Henderson ots->indirect_base); 3535c29c1d7eSAurelien Jarno } 353678113e83SRichard Henderson if (!tcg_out_mov(s, otype, ots->reg, ts->reg)) { 3537240c08d0SRichard Henderson /* 3538240c08d0SRichard Henderson * Cross register class move not supported. 3539240c08d0SRichard Henderson * Store the source register into the destination slot 3540240c08d0SRichard Henderson * and leave the destination temp as TEMP_VAL_MEM. 3541240c08d0SRichard Henderson */ 3542240c08d0SRichard Henderson assert(!ots->fixed_reg); 3543240c08d0SRichard Henderson if (!ts->mem_allocated) { 3544240c08d0SRichard Henderson temp_allocate_frame(s, ots); 3545240c08d0SRichard Henderson } 3546240c08d0SRichard Henderson tcg_out_st(s, ts->type, ts->reg, 3547240c08d0SRichard Henderson ots->mem_base->reg, ots->mem_offset); 3548240c08d0SRichard Henderson ots->mem_coherent = 1; 3549240c08d0SRichard Henderson temp_free_or_dead(s, ots, -1); 3550240c08d0SRichard Henderson return; 355178113e83SRichard Henderson } 3552c29c1d7eSAurelien Jarno } 3553c896fe29Sbellard ots->val_type = TEMP_VAL_REG; 3554c896fe29Sbellard ots->mem_coherent = 0; 3555f8b2f202SRichard Henderson s->reg_to_temp[ots->reg] = ots; 3556ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(0)) { 355798b4e186SRichard Henderson temp_sync(s, ots, allocated_regs, 0, 0); 3558c29c1d7eSAurelien Jarno } 3559ec7a869dSAurelien Jarno } 3560c896fe29Sbellard } 3561c896fe29Sbellard 3562bab1671fSRichard Henderson /* 3563bab1671fSRichard Henderson * Specialized code generation for INDEX_op_dup_vec. 3564bab1671fSRichard Henderson */ 3565bab1671fSRichard Henderson static void tcg_reg_alloc_dup(TCGContext *s, const TCGOp *op) 3566bab1671fSRichard Henderson { 3567bab1671fSRichard Henderson const TCGLifeData arg_life = op->life; 3568bab1671fSRichard Henderson TCGRegSet dup_out_regs, dup_in_regs; 3569bab1671fSRichard Henderson TCGTemp *its, *ots; 3570bab1671fSRichard Henderson TCGType itype, vtype; 3571d6ecb4a9SRichard Henderson intptr_t endian_fixup; 3572bab1671fSRichard Henderson unsigned vece; 3573bab1671fSRichard Henderson bool ok; 3574bab1671fSRichard Henderson 3575bab1671fSRichard Henderson ots = arg_temp(op->args[0]); 3576bab1671fSRichard Henderson its = arg_temp(op->args[1]); 3577bab1671fSRichard Henderson 3578bab1671fSRichard Henderson /* ENV should not be modified. */ 3579bab1671fSRichard Henderson tcg_debug_assert(!ots->fixed_reg); 3580bab1671fSRichard Henderson 3581bab1671fSRichard Henderson itype = its->type; 3582bab1671fSRichard Henderson vece = TCGOP_VECE(op); 3583bab1671fSRichard Henderson vtype = TCGOP_VECL(op) + TCG_TYPE_V64; 3584bab1671fSRichard Henderson 3585bab1671fSRichard Henderson if (its->val_type == TEMP_VAL_CONST) { 3586bab1671fSRichard Henderson /* Propagate constant via movi -> dupi. */ 3587bab1671fSRichard Henderson tcg_target_ulong val = its->val; 3588bab1671fSRichard Henderson if (IS_DEAD_ARG(1)) { 3589bab1671fSRichard Henderson temp_dead(s, its); 3590bab1671fSRichard Henderson } 3591bab1671fSRichard Henderson tcg_reg_alloc_do_movi(s, ots, val, arg_life, op->output_pref[0]); 3592bab1671fSRichard Henderson return; 3593bab1671fSRichard Henderson } 3594bab1671fSRichard Henderson 35959be0d080SRichard Henderson dup_out_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[0].regs; 35969be0d080SRichard Henderson dup_in_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[1].regs; 3597bab1671fSRichard Henderson 3598bab1671fSRichard Henderson /* Allocate the output register now. */ 3599bab1671fSRichard Henderson if (ots->val_type != TEMP_VAL_REG) { 3600bab1671fSRichard Henderson TCGRegSet allocated_regs = s->reserved_regs; 3601bab1671fSRichard Henderson 3602bab1671fSRichard Henderson if (!IS_DEAD_ARG(1) && its->val_type == TEMP_VAL_REG) { 3603bab1671fSRichard Henderson /* Make sure to not spill the input register. */ 3604bab1671fSRichard Henderson tcg_regset_set_reg(allocated_regs, its->reg); 3605bab1671fSRichard Henderson } 3606bab1671fSRichard Henderson ots->reg = tcg_reg_alloc(s, dup_out_regs, allocated_regs, 3607bab1671fSRichard Henderson op->output_pref[0], ots->indirect_base); 3608bab1671fSRichard Henderson ots->val_type = TEMP_VAL_REG; 3609bab1671fSRichard Henderson ots->mem_coherent = 0; 3610bab1671fSRichard Henderson s->reg_to_temp[ots->reg] = ots; 3611bab1671fSRichard Henderson } 3612bab1671fSRichard Henderson 3613bab1671fSRichard Henderson switch (its->val_type) { 3614bab1671fSRichard Henderson case TEMP_VAL_REG: 3615bab1671fSRichard Henderson /* 3616bab1671fSRichard Henderson * The dup constriaints must be broad, covering all possible VECE. 3617bab1671fSRichard Henderson * However, tcg_op_dup_vec() gets to see the VECE and we allow it 3618bab1671fSRichard Henderson * to fail, indicating that extra moves are required for that case. 3619bab1671fSRichard Henderson */ 3620bab1671fSRichard Henderson if (tcg_regset_test_reg(dup_in_regs, its->reg)) { 3621bab1671fSRichard Henderson if (tcg_out_dup_vec(s, vtype, vece, ots->reg, its->reg)) { 3622bab1671fSRichard Henderson goto done; 3623bab1671fSRichard Henderson } 3624bab1671fSRichard Henderson /* Try again from memory or a vector input register. */ 3625bab1671fSRichard Henderson } 3626bab1671fSRichard Henderson if (!its->mem_coherent) { 3627bab1671fSRichard Henderson /* 3628bab1671fSRichard Henderson * The input register is not synced, and so an extra store 3629bab1671fSRichard Henderson * would be required to use memory. Attempt an integer-vector 3630bab1671fSRichard Henderson * register move first. We do not have a TCGRegSet for this. 3631bab1671fSRichard Henderson */ 3632bab1671fSRichard Henderson if (tcg_out_mov(s, itype, ots->reg, its->reg)) { 3633bab1671fSRichard Henderson break; 3634bab1671fSRichard Henderson } 3635bab1671fSRichard Henderson /* Sync the temp back to its slot and load from there. */ 3636bab1671fSRichard Henderson temp_sync(s, its, s->reserved_regs, 0, 0); 3637bab1671fSRichard Henderson } 3638bab1671fSRichard Henderson /* fall through */ 3639bab1671fSRichard Henderson 3640bab1671fSRichard Henderson case TEMP_VAL_MEM: 3641d6ecb4a9SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN 3642d6ecb4a9SRichard Henderson endian_fixup = itype == TCG_TYPE_I32 ? 4 : 8; 3643d6ecb4a9SRichard Henderson endian_fixup -= 1 << vece; 3644d6ecb4a9SRichard Henderson #else 3645d6ecb4a9SRichard Henderson endian_fixup = 0; 3646d6ecb4a9SRichard Henderson #endif 3647d6ecb4a9SRichard Henderson if (tcg_out_dupm_vec(s, vtype, vece, ots->reg, its->mem_base->reg, 3648d6ecb4a9SRichard Henderson its->mem_offset + endian_fixup)) { 3649d6ecb4a9SRichard Henderson goto done; 3650d6ecb4a9SRichard Henderson } 3651bab1671fSRichard Henderson tcg_out_ld(s, itype, ots->reg, its->mem_base->reg, its->mem_offset); 3652bab1671fSRichard Henderson break; 3653bab1671fSRichard Henderson 3654bab1671fSRichard Henderson default: 3655bab1671fSRichard Henderson g_assert_not_reached(); 3656bab1671fSRichard Henderson } 3657bab1671fSRichard Henderson 3658bab1671fSRichard Henderson /* We now have a vector input register, so dup must succeed. */ 3659bab1671fSRichard Henderson ok = tcg_out_dup_vec(s, vtype, vece, ots->reg, ots->reg); 3660bab1671fSRichard Henderson tcg_debug_assert(ok); 3661bab1671fSRichard Henderson 3662bab1671fSRichard Henderson done: 3663bab1671fSRichard Henderson if (IS_DEAD_ARG(1)) { 3664bab1671fSRichard Henderson temp_dead(s, its); 3665bab1671fSRichard Henderson } 3666bab1671fSRichard Henderson if (NEED_SYNC_ARG(0)) { 3667bab1671fSRichard Henderson temp_sync(s, ots, s->reserved_regs, 0, 0); 3668bab1671fSRichard Henderson } 3669bab1671fSRichard Henderson if (IS_DEAD_ARG(0)) { 3670bab1671fSRichard Henderson temp_dead(s, ots); 3671bab1671fSRichard Henderson } 3672bab1671fSRichard Henderson } 3673bab1671fSRichard Henderson 3674dd186292SRichard Henderson static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) 3675c896fe29Sbellard { 3676dd186292SRichard Henderson const TCGLifeData arg_life = op->life; 3677dd186292SRichard Henderson const TCGOpDef * const def = &tcg_op_defs[op->opc]; 367882790a87SRichard Henderson TCGRegSet i_allocated_regs; 367982790a87SRichard Henderson TCGRegSet o_allocated_regs; 3680b6638662SRichard Henderson int i, k, nb_iargs, nb_oargs; 3681b6638662SRichard Henderson TCGReg reg; 3682c896fe29Sbellard TCGArg arg; 3683c896fe29Sbellard const TCGArgConstraint *arg_ct; 3684c896fe29Sbellard TCGTemp *ts; 3685c896fe29Sbellard TCGArg new_args[TCG_MAX_OP_ARGS]; 3686c896fe29Sbellard int const_args[TCG_MAX_OP_ARGS]; 3687c896fe29Sbellard 3688c896fe29Sbellard nb_oargs = def->nb_oargs; 3689c896fe29Sbellard nb_iargs = def->nb_iargs; 3690c896fe29Sbellard 3691c896fe29Sbellard /* copy constants */ 3692c896fe29Sbellard memcpy(new_args + nb_oargs + nb_iargs, 3693dd186292SRichard Henderson op->args + nb_oargs + nb_iargs, 3694c896fe29Sbellard sizeof(TCGArg) * def->nb_cargs); 3695c896fe29Sbellard 3696d21369f5SRichard Henderson i_allocated_regs = s->reserved_regs; 3697d21369f5SRichard Henderson o_allocated_regs = s->reserved_regs; 369882790a87SRichard Henderson 3699c896fe29Sbellard /* satisfy input constraints */ 3700c896fe29Sbellard for (k = 0; k < nb_iargs; k++) { 3701d62816f2SRichard Henderson TCGRegSet i_preferred_regs, o_preferred_regs; 3702d62816f2SRichard Henderson 370366792f90SRichard Henderson i = def->args_ct[nb_oargs + k].sort_index; 3704dd186292SRichard Henderson arg = op->args[i]; 3705c896fe29Sbellard arg_ct = &def->args_ct[i]; 370643439139SRichard Henderson ts = arg_temp(arg); 370740ae5c62SRichard Henderson 370840ae5c62SRichard Henderson if (ts->val_type == TEMP_VAL_CONST 370940ae5c62SRichard Henderson && tcg_target_const_match(ts->val, ts->type, arg_ct)) { 3710c896fe29Sbellard /* constant is OK for instruction */ 3711c896fe29Sbellard const_args[i] = 1; 3712c896fe29Sbellard new_args[i] = ts->val; 3713d62816f2SRichard Henderson continue; 3714c896fe29Sbellard } 371540ae5c62SRichard Henderson 3716d62816f2SRichard Henderson i_preferred_regs = o_preferred_regs = 0; 3717bc2b17e6SRichard Henderson if (arg_ct->ialias) { 3718d62816f2SRichard Henderson o_preferred_regs = op->output_pref[arg_ct->alias_index]; 37195ff9d6a4Sbellard if (ts->fixed_reg) { 37205ff9d6a4Sbellard /* if fixed register, we must allocate a new register 37215ff9d6a4Sbellard if the alias is not the same register */ 3722d62816f2SRichard Henderson if (arg != op->args[arg_ct->alias_index]) { 37235ff9d6a4Sbellard goto allocate_in_reg; 3724d62816f2SRichard Henderson } 37255ff9d6a4Sbellard } else { 3726c896fe29Sbellard /* if the input is aliased to an output and if it is 3727c896fe29Sbellard not dead after the instruction, we must allocate 3728c896fe29Sbellard a new register and move it */ 3729866cb6cbSAurelien Jarno if (!IS_DEAD_ARG(i)) { 3730c896fe29Sbellard goto allocate_in_reg; 3731c896fe29Sbellard } 3732d62816f2SRichard Henderson 37337e1df267SAurelien Jarno /* check if the current register has already been allocated 37347e1df267SAurelien Jarno for another input aliased to an output */ 3735d62816f2SRichard Henderson if (ts->val_type == TEMP_VAL_REG) { 37367e1df267SAurelien Jarno int k2, i2; 3737d62816f2SRichard Henderson reg = ts->reg; 37387e1df267SAurelien Jarno for (k2 = 0 ; k2 < k ; k2++) { 373966792f90SRichard Henderson i2 = def->args_ct[nb_oargs + k2].sort_index; 3740bc2b17e6SRichard Henderson if (def->args_ct[i2].ialias && reg == new_args[i2]) { 37417e1df267SAurelien Jarno goto allocate_in_reg; 37427e1df267SAurelien Jarno } 37437e1df267SAurelien Jarno } 37445ff9d6a4Sbellard } 3745d62816f2SRichard Henderson i_preferred_regs = o_preferred_regs; 3746866cb6cbSAurelien Jarno } 3747d62816f2SRichard Henderson } 3748d62816f2SRichard Henderson 37499be0d080SRichard Henderson temp_load(s, ts, arg_ct->regs, i_allocated_regs, i_preferred_regs); 3750c896fe29Sbellard reg = ts->reg; 3751d62816f2SRichard Henderson 37529be0d080SRichard Henderson if (tcg_regset_test_reg(arg_ct->regs, reg)) { 3753c896fe29Sbellard /* nothing to do : the constraint is satisfied */ 3754c896fe29Sbellard } else { 3755c896fe29Sbellard allocate_in_reg: 3756c896fe29Sbellard /* allocate a new register matching the constraint 3757c896fe29Sbellard and move the temporary register into it */ 3758d62816f2SRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], 3759d62816f2SRichard Henderson i_allocated_regs, 0); 37609be0d080SRichard Henderson reg = tcg_reg_alloc(s, arg_ct->regs, i_allocated_regs, 3761d62816f2SRichard Henderson o_preferred_regs, ts->indirect_base); 376278113e83SRichard Henderson if (!tcg_out_mov(s, ts->type, reg, ts->reg)) { 3763240c08d0SRichard Henderson /* 3764240c08d0SRichard Henderson * Cross register class move not supported. Sync the 3765240c08d0SRichard Henderson * temp back to its slot and load from there. 3766240c08d0SRichard Henderson */ 3767240c08d0SRichard Henderson temp_sync(s, ts, i_allocated_regs, 0, 0); 3768240c08d0SRichard Henderson tcg_out_ld(s, ts->type, reg, 3769240c08d0SRichard Henderson ts->mem_base->reg, ts->mem_offset); 377078113e83SRichard Henderson } 3771c896fe29Sbellard } 3772c896fe29Sbellard new_args[i] = reg; 3773c896fe29Sbellard const_args[i] = 0; 377482790a87SRichard Henderson tcg_regset_set_reg(i_allocated_regs, reg); 3775c896fe29Sbellard } 3776c896fe29Sbellard 3777c896fe29Sbellard /* mark dead temporaries and free the associated registers */ 3778866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 3779866cb6cbSAurelien Jarno if (IS_DEAD_ARG(i)) { 378043439139SRichard Henderson temp_dead(s, arg_temp(op->args[i])); 3781c896fe29Sbellard } 3782c896fe29Sbellard } 3783c896fe29Sbellard 3784b4cb76e6SRichard Henderson if (def->flags & TCG_OPF_COND_BRANCH) { 3785b4cb76e6SRichard Henderson tcg_reg_alloc_cbranch(s, i_allocated_regs); 3786b4cb76e6SRichard Henderson } else if (def->flags & TCG_OPF_BB_END) { 378782790a87SRichard Henderson tcg_reg_alloc_bb_end(s, i_allocated_regs); 3788a52ad07eSAurelien Jarno } else { 3789c896fe29Sbellard if (def->flags & TCG_OPF_CALL_CLOBBER) { 3790b03cce8eSbellard /* XXX: permit generic clobber register list ? */ 3791c8074023SRichard Henderson for (i = 0; i < TCG_TARGET_NB_REGS; i++) { 3792c8074023SRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) { 379382790a87SRichard Henderson tcg_reg_free(s, i, i_allocated_regs); 3794c896fe29Sbellard } 3795c896fe29Sbellard } 37963d5c5f87SAurelien Jarno } 37973d5c5f87SAurelien Jarno if (def->flags & TCG_OPF_SIDE_EFFECTS) { 37983d5c5f87SAurelien Jarno /* sync globals if the op has side effects and might trigger 37993d5c5f87SAurelien Jarno an exception. */ 380082790a87SRichard Henderson sync_globals(s, i_allocated_regs); 3801c896fe29Sbellard } 3802c896fe29Sbellard 3803c896fe29Sbellard /* satisfy the output constraints */ 3804c896fe29Sbellard for(k = 0; k < nb_oargs; k++) { 380566792f90SRichard Henderson i = def->args_ct[k].sort_index; 3806dd186292SRichard Henderson arg = op->args[i]; 3807c896fe29Sbellard arg_ct = &def->args_ct[i]; 380843439139SRichard Henderson ts = arg_temp(arg); 3809d63e3b6eSRichard Henderson 3810d63e3b6eSRichard Henderson /* ENV should not be modified. */ 3811d63e3b6eSRichard Henderson tcg_debug_assert(!ts->fixed_reg); 3812d63e3b6eSRichard Henderson 3813bc2b17e6SRichard Henderson if (arg_ct->oalias && !const_args[arg_ct->alias_index]) { 38145ff9d6a4Sbellard reg = new_args[arg_ct->alias_index]; 3815bc2b17e6SRichard Henderson } else if (arg_ct->newreg) { 38169be0d080SRichard Henderson reg = tcg_reg_alloc(s, arg_ct->regs, 381782790a87SRichard Henderson i_allocated_regs | o_allocated_regs, 381869e3706dSRichard Henderson op->output_pref[k], ts->indirect_base); 3819c896fe29Sbellard } else { 38209be0d080SRichard Henderson reg = tcg_reg_alloc(s, arg_ct->regs, o_allocated_regs, 382169e3706dSRichard Henderson op->output_pref[k], ts->indirect_base); 3822c896fe29Sbellard } 382382790a87SRichard Henderson tcg_regset_set_reg(o_allocated_regs, reg); 3824639368ddSAurelien Jarno if (ts->val_type == TEMP_VAL_REG) { 3825f8b2f202SRichard Henderson s->reg_to_temp[ts->reg] = NULL; 3826639368ddSAurelien Jarno } 3827c896fe29Sbellard ts->val_type = TEMP_VAL_REG; 3828c896fe29Sbellard ts->reg = reg; 3829d63e3b6eSRichard Henderson /* 3830d63e3b6eSRichard Henderson * Temp value is modified, so the value kept in memory is 3831d63e3b6eSRichard Henderson * potentially not the same. 3832d63e3b6eSRichard Henderson */ 3833c896fe29Sbellard ts->mem_coherent = 0; 3834f8b2f202SRichard Henderson s->reg_to_temp[reg] = ts; 3835c896fe29Sbellard new_args[i] = reg; 3836c896fe29Sbellard } 3837e8996ee0Sbellard } 3838c896fe29Sbellard 3839c896fe29Sbellard /* emit instruction */ 3840d2fd745fSRichard Henderson if (def->flags & TCG_OPF_VECTOR) { 3841d2fd745fSRichard Henderson tcg_out_vec_op(s, op->opc, TCGOP_VECL(op), TCGOP_VECE(op), 3842d2fd745fSRichard Henderson new_args, const_args); 3843d2fd745fSRichard Henderson } else { 3844dd186292SRichard Henderson tcg_out_op(s, op->opc, new_args, const_args); 3845d2fd745fSRichard Henderson } 3846c896fe29Sbellard 3847c896fe29Sbellard /* move the outputs in the correct register if needed */ 3848c896fe29Sbellard for(i = 0; i < nb_oargs; i++) { 384943439139SRichard Henderson ts = arg_temp(op->args[i]); 3850d63e3b6eSRichard Henderson 3851d63e3b6eSRichard Henderson /* ENV should not be modified. */ 3852d63e3b6eSRichard Henderson tcg_debug_assert(!ts->fixed_reg); 3853d63e3b6eSRichard Henderson 3854ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(i)) { 385598b4e186SRichard Henderson temp_sync(s, ts, o_allocated_regs, 0, IS_DEAD_ARG(i)); 385659d7c14eSRichard Henderson } else if (IS_DEAD_ARG(i)) { 3857f8bf00f1SRichard Henderson temp_dead(s, ts); 3858ec7a869dSAurelien Jarno } 3859c896fe29Sbellard } 3860c896fe29Sbellard } 3861c896fe29Sbellard 3862b03cce8eSbellard #ifdef TCG_TARGET_STACK_GROWSUP 3863b03cce8eSbellard #define STACK_DIR(x) (-(x)) 3864b03cce8eSbellard #else 3865b03cce8eSbellard #define STACK_DIR(x) (x) 3866b03cce8eSbellard #endif 3867b03cce8eSbellard 3868dd186292SRichard Henderson static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op) 3869c896fe29Sbellard { 3870cd9090aaSRichard Henderson const int nb_oargs = TCGOP_CALLO(op); 3871cd9090aaSRichard Henderson const int nb_iargs = TCGOP_CALLI(op); 3872dd186292SRichard Henderson const TCGLifeData arg_life = op->life; 3873b6638662SRichard Henderson int flags, nb_regs, i; 3874b6638662SRichard Henderson TCGReg reg; 3875cf066674SRichard Henderson TCGArg arg; 3876c896fe29Sbellard TCGTemp *ts; 3877d3452f1fSRichard Henderson intptr_t stack_offset; 3878d3452f1fSRichard Henderson size_t call_stack_size; 3879cf066674SRichard Henderson tcg_insn_unit *func_addr; 3880cf066674SRichard Henderson int allocate_args; 3881c896fe29Sbellard TCGRegSet allocated_regs; 3882c896fe29Sbellard 3883dd186292SRichard Henderson func_addr = (tcg_insn_unit *)(intptr_t)op->args[nb_oargs + nb_iargs]; 3884dd186292SRichard Henderson flags = op->args[nb_oargs + nb_iargs + 1]; 3885c896fe29Sbellard 38866e17d0c5SStefan Weil nb_regs = ARRAY_SIZE(tcg_target_call_iarg_regs); 3887c45cb8bbSRichard Henderson if (nb_regs > nb_iargs) { 3888c45cb8bbSRichard Henderson nb_regs = nb_iargs; 3889cf066674SRichard Henderson } 3890c896fe29Sbellard 3891c896fe29Sbellard /* assign stack slots first */ 3892c45cb8bbSRichard Henderson call_stack_size = (nb_iargs - nb_regs) * sizeof(tcg_target_long); 3893c896fe29Sbellard call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) & 3894c896fe29Sbellard ~(TCG_TARGET_STACK_ALIGN - 1); 3895b03cce8eSbellard allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE); 3896b03cce8eSbellard if (allocate_args) { 3897345649c0SBlue Swirl /* XXX: if more than TCG_STATIC_CALL_ARGS_SIZE is needed, 3898345649c0SBlue Swirl preallocate call stack */ 3899345649c0SBlue Swirl tcg_abort(); 3900b03cce8eSbellard } 390139cf05d3Sbellard 390239cf05d3Sbellard stack_offset = TCG_TARGET_CALL_STACK_OFFSET; 3903c45cb8bbSRichard Henderson for (i = nb_regs; i < nb_iargs; i++) { 3904dd186292SRichard Henderson arg = op->args[nb_oargs + i]; 390539cf05d3Sbellard #ifdef TCG_TARGET_STACK_GROWSUP 390639cf05d3Sbellard stack_offset -= sizeof(tcg_target_long); 390739cf05d3Sbellard #endif 390839cf05d3Sbellard if (arg != TCG_CALL_DUMMY_ARG) { 390943439139SRichard Henderson ts = arg_temp(arg); 391040ae5c62SRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], 3911b722452aSRichard Henderson s->reserved_regs, 0); 3912e4d5434cSblueswir1 tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, stack_offset); 391339cf05d3Sbellard } 391439cf05d3Sbellard #ifndef TCG_TARGET_STACK_GROWSUP 391539cf05d3Sbellard stack_offset += sizeof(tcg_target_long); 391639cf05d3Sbellard #endif 3917c896fe29Sbellard } 3918c896fe29Sbellard 3919c896fe29Sbellard /* assign input registers */ 3920d21369f5SRichard Henderson allocated_regs = s->reserved_regs; 3921c896fe29Sbellard for (i = 0; i < nb_regs; i++) { 3922dd186292SRichard Henderson arg = op->args[nb_oargs + i]; 392339cf05d3Sbellard if (arg != TCG_CALL_DUMMY_ARG) { 392443439139SRichard Henderson ts = arg_temp(arg); 3925c896fe29Sbellard reg = tcg_target_call_iarg_regs[i]; 392640ae5c62SRichard Henderson 3927c896fe29Sbellard if (ts->val_type == TEMP_VAL_REG) { 3928c896fe29Sbellard if (ts->reg != reg) { 39294250da10SRichard Henderson tcg_reg_free(s, reg, allocated_regs); 393078113e83SRichard Henderson if (!tcg_out_mov(s, ts->type, reg, ts->reg)) { 3931240c08d0SRichard Henderson /* 3932240c08d0SRichard Henderson * Cross register class move not supported. Sync the 3933240c08d0SRichard Henderson * temp back to its slot and load from there. 3934240c08d0SRichard Henderson */ 3935240c08d0SRichard Henderson temp_sync(s, ts, allocated_regs, 0, 0); 3936240c08d0SRichard Henderson tcg_out_ld(s, ts->type, reg, 3937240c08d0SRichard Henderson ts->mem_base->reg, ts->mem_offset); 393878113e83SRichard Henderson } 3939c896fe29Sbellard } 3940c896fe29Sbellard } else { 3941ccb1bb66SRichard Henderson TCGRegSet arg_set = 0; 394240ae5c62SRichard Henderson 39434250da10SRichard Henderson tcg_reg_free(s, reg, allocated_regs); 394440ae5c62SRichard Henderson tcg_regset_set_reg(arg_set, reg); 3945b722452aSRichard Henderson temp_load(s, ts, arg_set, allocated_regs, 0); 3946c896fe29Sbellard } 394740ae5c62SRichard Henderson 3948c896fe29Sbellard tcg_regset_set_reg(allocated_regs, reg); 3949c896fe29Sbellard } 395039cf05d3Sbellard } 3951c896fe29Sbellard 3952c896fe29Sbellard /* mark dead temporaries and free the associated registers */ 3953866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 3954866cb6cbSAurelien Jarno if (IS_DEAD_ARG(i)) { 395543439139SRichard Henderson temp_dead(s, arg_temp(op->args[i])); 3956c896fe29Sbellard } 3957c896fe29Sbellard } 3958c896fe29Sbellard 3959c896fe29Sbellard /* clobber call registers */ 3960c8074023SRichard Henderson for (i = 0; i < TCG_TARGET_NB_REGS; i++) { 3961c8074023SRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) { 3962b3915dbbSRichard Henderson tcg_reg_free(s, i, allocated_regs); 3963c896fe29Sbellard } 3964c896fe29Sbellard } 3965c896fe29Sbellard 396678505279SAurelien Jarno /* Save globals if they might be written by the helper, sync them if 396778505279SAurelien Jarno they might be read. */ 396878505279SAurelien Jarno if (flags & TCG_CALL_NO_READ_GLOBALS) { 396978505279SAurelien Jarno /* Nothing to do */ 397078505279SAurelien Jarno } else if (flags & TCG_CALL_NO_WRITE_GLOBALS) { 397178505279SAurelien Jarno sync_globals(s, allocated_regs); 397278505279SAurelien Jarno } else { 3973e8996ee0Sbellard save_globals(s, allocated_regs); 3974b9c18f56Saurel32 } 3975c896fe29Sbellard 3976cf066674SRichard Henderson tcg_out_call(s, func_addr); 3977c896fe29Sbellard 3978c896fe29Sbellard /* assign output registers and emit moves if needed */ 3979c896fe29Sbellard for(i = 0; i < nb_oargs; i++) { 3980dd186292SRichard Henderson arg = op->args[i]; 398143439139SRichard Henderson ts = arg_temp(arg); 3982d63e3b6eSRichard Henderson 3983d63e3b6eSRichard Henderson /* ENV should not be modified. */ 3984d63e3b6eSRichard Henderson tcg_debug_assert(!ts->fixed_reg); 3985d63e3b6eSRichard Henderson 3986c896fe29Sbellard reg = tcg_target_call_oarg_regs[i]; 3987eabb7b91SAurelien Jarno tcg_debug_assert(s->reg_to_temp[reg] == NULL); 3988639368ddSAurelien Jarno if (ts->val_type == TEMP_VAL_REG) { 3989f8b2f202SRichard Henderson s->reg_to_temp[ts->reg] = NULL; 3990639368ddSAurelien Jarno } 3991c896fe29Sbellard ts->val_type = TEMP_VAL_REG; 3992c896fe29Sbellard ts->reg = reg; 3993c896fe29Sbellard ts->mem_coherent = 0; 3994f8b2f202SRichard Henderson s->reg_to_temp[reg] = ts; 3995ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(i)) { 399698b4e186SRichard Henderson temp_sync(s, ts, allocated_regs, 0, IS_DEAD_ARG(i)); 399759d7c14eSRichard Henderson } else if (IS_DEAD_ARG(i)) { 3998f8bf00f1SRichard Henderson temp_dead(s, ts); 3999c896fe29Sbellard } 4000c896fe29Sbellard } 40018c11ad25SAurelien Jarno } 4002c896fe29Sbellard 4003c896fe29Sbellard #ifdef CONFIG_PROFILER 4004c896fe29Sbellard 4005c3fac113SEmilio G. Cota /* avoid copy/paste errors */ 4006c3fac113SEmilio G. Cota #define PROF_ADD(to, from, field) \ 4007c3fac113SEmilio G. Cota do { \ 4008d73415a3SStefan Hajnoczi (to)->field += qatomic_read(&((from)->field)); \ 4009c3fac113SEmilio G. Cota } while (0) 4010c896fe29Sbellard 4011c3fac113SEmilio G. Cota #define PROF_MAX(to, from, field) \ 4012c3fac113SEmilio G. Cota do { \ 4013d73415a3SStefan Hajnoczi typeof((from)->field) val__ = qatomic_read(&((from)->field)); \ 4014c3fac113SEmilio G. Cota if (val__ > (to)->field) { \ 4015c3fac113SEmilio G. Cota (to)->field = val__; \ 4016c3fac113SEmilio G. Cota } \ 4017c3fac113SEmilio G. Cota } while (0) 4018c3fac113SEmilio G. Cota 4019c3fac113SEmilio G. Cota /* Pass in a zero'ed @prof */ 4020c3fac113SEmilio G. Cota static inline 4021c3fac113SEmilio G. Cota void tcg_profile_snapshot(TCGProfile *prof, bool counters, bool table) 4022c896fe29Sbellard { 4023d73415a3SStefan Hajnoczi unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs); 4024c3fac113SEmilio G. Cota unsigned int i; 4025c3fac113SEmilio G. Cota 40263468b59eSEmilio G. Cota for (i = 0; i < n_ctxs; i++) { 4027d73415a3SStefan Hajnoczi TCGContext *s = qatomic_read(&tcg_ctxs[i]); 40283468b59eSEmilio G. Cota const TCGProfile *orig = &s->prof; 4029c3fac113SEmilio G. Cota 4030c3fac113SEmilio G. Cota if (counters) { 403172fd2efbSEmilio G. Cota PROF_ADD(prof, orig, cpu_exec_time); 4032c3fac113SEmilio G. Cota PROF_ADD(prof, orig, tb_count1); 4033c3fac113SEmilio G. Cota PROF_ADD(prof, orig, tb_count); 4034c3fac113SEmilio G. Cota PROF_ADD(prof, orig, op_count); 4035c3fac113SEmilio G. Cota PROF_MAX(prof, orig, op_count_max); 4036c3fac113SEmilio G. Cota PROF_ADD(prof, orig, temp_count); 4037c3fac113SEmilio G. Cota PROF_MAX(prof, orig, temp_count_max); 4038c3fac113SEmilio G. Cota PROF_ADD(prof, orig, del_op_count); 4039c3fac113SEmilio G. Cota PROF_ADD(prof, orig, code_in_len); 4040c3fac113SEmilio G. Cota PROF_ADD(prof, orig, code_out_len); 4041c3fac113SEmilio G. Cota PROF_ADD(prof, orig, search_out_len); 4042c3fac113SEmilio G. Cota PROF_ADD(prof, orig, interm_time); 4043c3fac113SEmilio G. Cota PROF_ADD(prof, orig, code_time); 4044c3fac113SEmilio G. Cota PROF_ADD(prof, orig, la_time); 4045c3fac113SEmilio G. Cota PROF_ADD(prof, orig, opt_time); 4046c3fac113SEmilio G. Cota PROF_ADD(prof, orig, restore_count); 4047c3fac113SEmilio G. Cota PROF_ADD(prof, orig, restore_time); 4048c3fac113SEmilio G. Cota } 4049c3fac113SEmilio G. Cota if (table) { 4050c896fe29Sbellard int i; 4051d70724ceSzhanghailiang 405215fc7daaSRichard Henderson for (i = 0; i < NB_OPS; i++) { 4053c3fac113SEmilio G. Cota PROF_ADD(prof, orig, table_op_count[i]); 4054c3fac113SEmilio G. Cota } 4055c3fac113SEmilio G. Cota } 4056c3fac113SEmilio G. Cota } 4057c3fac113SEmilio G. Cota } 4058c3fac113SEmilio G. Cota 4059c3fac113SEmilio G. Cota #undef PROF_ADD 4060c3fac113SEmilio G. Cota #undef PROF_MAX 4061c3fac113SEmilio G. Cota 4062c3fac113SEmilio G. Cota static void tcg_profile_snapshot_counters(TCGProfile *prof) 4063c3fac113SEmilio G. Cota { 4064c3fac113SEmilio G. Cota tcg_profile_snapshot(prof, true, false); 4065c3fac113SEmilio G. Cota } 4066c3fac113SEmilio G. Cota 4067c3fac113SEmilio G. Cota static void tcg_profile_snapshot_table(TCGProfile *prof) 4068c3fac113SEmilio G. Cota { 4069c3fac113SEmilio G. Cota tcg_profile_snapshot(prof, false, true); 4070c3fac113SEmilio G. Cota } 4071c3fac113SEmilio G. Cota 4072d4c51a0aSMarkus Armbruster void tcg_dump_op_count(void) 4073c3fac113SEmilio G. Cota { 4074c3fac113SEmilio G. Cota TCGProfile prof = {}; 4075c3fac113SEmilio G. Cota int i; 4076c3fac113SEmilio G. Cota 4077c3fac113SEmilio G. Cota tcg_profile_snapshot_table(&prof); 4078c3fac113SEmilio G. Cota for (i = 0; i < NB_OPS; i++) { 4079d4c51a0aSMarkus Armbruster qemu_printf("%s %" PRId64 "\n", tcg_op_defs[i].name, 4080c3fac113SEmilio G. Cota prof.table_op_count[i]); 4081c896fe29Sbellard } 4082c896fe29Sbellard } 408372fd2efbSEmilio G. Cota 408472fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void) 408572fd2efbSEmilio G. Cota { 4086d73415a3SStefan Hajnoczi unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs); 408772fd2efbSEmilio G. Cota unsigned int i; 408872fd2efbSEmilio G. Cota int64_t ret = 0; 408972fd2efbSEmilio G. Cota 409072fd2efbSEmilio G. Cota for (i = 0; i < n_ctxs; i++) { 4091d73415a3SStefan Hajnoczi const TCGContext *s = qatomic_read(&tcg_ctxs[i]); 409272fd2efbSEmilio G. Cota const TCGProfile *prof = &s->prof; 409372fd2efbSEmilio G. Cota 4094d73415a3SStefan Hajnoczi ret += qatomic_read(&prof->cpu_exec_time); 409572fd2efbSEmilio G. Cota } 409672fd2efbSEmilio G. Cota return ret; 409772fd2efbSEmilio G. Cota } 4098246ae24dSMax Filippov #else 4099d4c51a0aSMarkus Armbruster void tcg_dump_op_count(void) 4100246ae24dSMax Filippov { 4101d4c51a0aSMarkus Armbruster qemu_printf("[TCG profiler not compiled]\n"); 4102246ae24dSMax Filippov } 410372fd2efbSEmilio G. Cota 410472fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void) 410572fd2efbSEmilio G. Cota { 410672fd2efbSEmilio G. Cota error_report("%s: TCG profiler not compiled", __func__); 410772fd2efbSEmilio G. Cota exit(EXIT_FAILURE); 410872fd2efbSEmilio G. Cota } 4109c896fe29Sbellard #endif 4110c896fe29Sbellard 4111c896fe29Sbellard 41125bd2ec3dSAlex Bennée int tcg_gen_code(TCGContext *s, TranslationBlock *tb) 4113c896fe29Sbellard { 4114c3fac113SEmilio G. Cota #ifdef CONFIG_PROFILER 4115c3fac113SEmilio G. Cota TCGProfile *prof = &s->prof; 4116c3fac113SEmilio G. Cota #endif 411715fa08f8SRichard Henderson int i, num_insns; 411815fa08f8SRichard Henderson TCGOp *op; 4119c896fe29Sbellard 412004fe6400SRichard Henderson #ifdef CONFIG_PROFILER 412104fe6400SRichard Henderson { 4122c1f543b7SEmilio G. Cota int n = 0; 412304fe6400SRichard Henderson 412415fa08f8SRichard Henderson QTAILQ_FOREACH(op, &s->ops, link) { 412515fa08f8SRichard Henderson n++; 412615fa08f8SRichard Henderson } 4127d73415a3SStefan Hajnoczi qatomic_set(&prof->op_count, prof->op_count + n); 4128c3fac113SEmilio G. Cota if (n > prof->op_count_max) { 4129d73415a3SStefan Hajnoczi qatomic_set(&prof->op_count_max, n); 413004fe6400SRichard Henderson } 413104fe6400SRichard Henderson 413204fe6400SRichard Henderson n = s->nb_temps; 4133d73415a3SStefan Hajnoczi qatomic_set(&prof->temp_count, prof->temp_count + n); 4134c3fac113SEmilio G. Cota if (n > prof->temp_count_max) { 4135d73415a3SStefan Hajnoczi qatomic_set(&prof->temp_count_max, n); 413604fe6400SRichard Henderson } 413704fe6400SRichard Henderson } 413804fe6400SRichard Henderson #endif 413904fe6400SRichard Henderson 4140c896fe29Sbellard #ifdef DEBUG_DISAS 4141d977e1c2SAlex Bennée if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP) 4142d977e1c2SAlex Bennée && qemu_log_in_addr_range(tb->pc))) { 4143fc59d2d8SRobert Foley FILE *logfile = qemu_log_lock(); 414493fcfe39Saliguori qemu_log("OP:\n"); 41451894f69aSRichard Henderson tcg_dump_ops(s, false); 414693fcfe39Saliguori qemu_log("\n"); 4147fc59d2d8SRobert Foley qemu_log_unlock(logfile); 4148c896fe29Sbellard } 4149c896fe29Sbellard #endif 4150c896fe29Sbellard 4151bef16ab4SRichard Henderson #ifdef CONFIG_DEBUG_TCG 4152bef16ab4SRichard Henderson /* Ensure all labels referenced have been emitted. */ 4153bef16ab4SRichard Henderson { 4154bef16ab4SRichard Henderson TCGLabel *l; 4155bef16ab4SRichard Henderson bool error = false; 4156bef16ab4SRichard Henderson 4157bef16ab4SRichard Henderson QSIMPLEQ_FOREACH(l, &s->labels, next) { 4158bef16ab4SRichard Henderson if (unlikely(!l->present) && l->refs) { 4159bef16ab4SRichard Henderson qemu_log_mask(CPU_LOG_TB_OP, 4160bef16ab4SRichard Henderson "$L%d referenced but not present.\n", l->id); 4161bef16ab4SRichard Henderson error = true; 4162bef16ab4SRichard Henderson } 4163bef16ab4SRichard Henderson } 4164bef16ab4SRichard Henderson assert(!error); 4165bef16ab4SRichard Henderson } 4166bef16ab4SRichard Henderson #endif 4167bef16ab4SRichard Henderson 4168c5cc28ffSAurelien Jarno #ifdef CONFIG_PROFILER 4169d73415a3SStefan Hajnoczi qatomic_set(&prof->opt_time, prof->opt_time - profile_getclock()); 4170c5cc28ffSAurelien Jarno #endif 4171c5cc28ffSAurelien Jarno 41728f2e8c07SKirill Batuzov #ifdef USE_TCG_OPTIMIZATIONS 4173c45cb8bbSRichard Henderson tcg_optimize(s); 41748f2e8c07SKirill Batuzov #endif 41758f2e8c07SKirill Batuzov 4176a23a9ec6Sbellard #ifdef CONFIG_PROFILER 4177d73415a3SStefan Hajnoczi qatomic_set(&prof->opt_time, prof->opt_time + profile_getclock()); 4178d73415a3SStefan Hajnoczi qatomic_set(&prof->la_time, prof->la_time - profile_getclock()); 4179a23a9ec6Sbellard #endif 4180c5cc28ffSAurelien Jarno 4181b4fc67c7SRichard Henderson reachable_code_pass(s); 4182b83eabeaSRichard Henderson liveness_pass_1(s); 41835a18407fSRichard Henderson 41845a18407fSRichard Henderson if (s->nb_indirects > 0) { 41855a18407fSRichard Henderson #ifdef DEBUG_DISAS 41865a18407fSRichard Henderson if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_IND) 41875a18407fSRichard Henderson && qemu_log_in_addr_range(tb->pc))) { 4188fc59d2d8SRobert Foley FILE *logfile = qemu_log_lock(); 41895a18407fSRichard Henderson qemu_log("OP before indirect lowering:\n"); 41901894f69aSRichard Henderson tcg_dump_ops(s, false); 41915a18407fSRichard Henderson qemu_log("\n"); 4192fc59d2d8SRobert Foley qemu_log_unlock(logfile); 41935a18407fSRichard Henderson } 41945a18407fSRichard Henderson #endif 41955a18407fSRichard Henderson /* Replace indirect temps with direct temps. */ 4196b83eabeaSRichard Henderson if (liveness_pass_2(s)) { 41975a18407fSRichard Henderson /* If changes were made, re-run liveness. */ 4198b83eabeaSRichard Henderson liveness_pass_1(s); 41995a18407fSRichard Henderson } 42005a18407fSRichard Henderson } 4201c5cc28ffSAurelien Jarno 4202a23a9ec6Sbellard #ifdef CONFIG_PROFILER 4203d73415a3SStefan Hajnoczi qatomic_set(&prof->la_time, prof->la_time + profile_getclock()); 4204a23a9ec6Sbellard #endif 4205c896fe29Sbellard 4206c896fe29Sbellard #ifdef DEBUG_DISAS 4207d977e1c2SAlex Bennée if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT) 4208d977e1c2SAlex Bennée && qemu_log_in_addr_range(tb->pc))) { 4209fc59d2d8SRobert Foley FILE *logfile = qemu_log_lock(); 4210c5cc28ffSAurelien Jarno qemu_log("OP after optimization and liveness analysis:\n"); 42111894f69aSRichard Henderson tcg_dump_ops(s, true); 421293fcfe39Saliguori qemu_log("\n"); 4213fc59d2d8SRobert Foley qemu_log_unlock(logfile); 4214c896fe29Sbellard } 4215c896fe29Sbellard #endif 4216c896fe29Sbellard 4217c896fe29Sbellard tcg_reg_alloc_start(s); 4218c896fe29Sbellard 4219e7e168f4SEmilio G. Cota s->code_buf = tb->tc.ptr; 4220e7e168f4SEmilio G. Cota s->code_ptr = tb->tc.ptr; 4221c896fe29Sbellard 4222659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS 42236001f772SLaurent Vivier QSIMPLEQ_INIT(&s->ldst_labels); 4224659ef5cbSRichard Henderson #endif 422557a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS 422657a26946SRichard Henderson s->pool_labels = NULL; 422757a26946SRichard Henderson #endif 42289ecefc84SRichard Henderson 4229fca8a500SRichard Henderson num_insns = -1; 423015fa08f8SRichard Henderson QTAILQ_FOREACH(op, &s->ops, link) { 4231c45cb8bbSRichard Henderson TCGOpcode opc = op->opc; 4232b3db8758Sblueswir1 4233c896fe29Sbellard #ifdef CONFIG_PROFILER 4234d73415a3SStefan Hajnoczi qatomic_set(&prof->table_op_count[opc], prof->table_op_count[opc] + 1); 4235c896fe29Sbellard #endif 4236c45cb8bbSRichard Henderson 4237c896fe29Sbellard switch (opc) { 4238c896fe29Sbellard case INDEX_op_mov_i32: 4239c896fe29Sbellard case INDEX_op_mov_i64: 4240d2fd745fSRichard Henderson case INDEX_op_mov_vec: 4241dd186292SRichard Henderson tcg_reg_alloc_mov(s, op); 4242c896fe29Sbellard break; 4243e8996ee0Sbellard case INDEX_op_movi_i32: 4244e8996ee0Sbellard case INDEX_op_movi_i64: 4245d2fd745fSRichard Henderson case INDEX_op_dupi_vec: 4246dd186292SRichard Henderson tcg_reg_alloc_movi(s, op); 4247e8996ee0Sbellard break; 4248bab1671fSRichard Henderson case INDEX_op_dup_vec: 4249bab1671fSRichard Henderson tcg_reg_alloc_dup(s, op); 4250bab1671fSRichard Henderson break; 4251765b842aSRichard Henderson case INDEX_op_insn_start: 4252fca8a500SRichard Henderson if (num_insns >= 0) { 42539f754620SRichard Henderson size_t off = tcg_current_code_size(s); 42549f754620SRichard Henderson s->gen_insn_end_off[num_insns] = off; 42559f754620SRichard Henderson /* Assert that we do not overflow our stored offset. */ 42569f754620SRichard Henderson assert(s->gen_insn_end_off[num_insns] == off); 4257fca8a500SRichard Henderson } 4258fca8a500SRichard Henderson num_insns++; 4259bad729e2SRichard Henderson for (i = 0; i < TARGET_INSN_START_WORDS; ++i) { 4260bad729e2SRichard Henderson target_ulong a; 4261bad729e2SRichard Henderson #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS 4262efee3746SRichard Henderson a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]); 4263bad729e2SRichard Henderson #else 4264efee3746SRichard Henderson a = op->args[i]; 4265bad729e2SRichard Henderson #endif 4266fca8a500SRichard Henderson s->gen_insn_data[num_insns][i] = a; 4267bad729e2SRichard Henderson } 4268c896fe29Sbellard break; 42695ff9d6a4Sbellard case INDEX_op_discard: 427043439139SRichard Henderson temp_dead(s, arg_temp(op->args[0])); 42715ff9d6a4Sbellard break; 4272c896fe29Sbellard case INDEX_op_set_label: 4273e8996ee0Sbellard tcg_reg_alloc_bb_end(s, s->reserved_regs); 4274efee3746SRichard Henderson tcg_out_label(s, arg_label(op->args[0]), s->code_ptr); 4275c896fe29Sbellard break; 4276c896fe29Sbellard case INDEX_op_call: 4277dd186292SRichard Henderson tcg_reg_alloc_call(s, op); 4278c45cb8bbSRichard Henderson break; 4279c896fe29Sbellard default: 428025c4d9ccSRichard Henderson /* Sanity check that we've not introduced any unhandled opcodes. */ 4281be0f34b5SRichard Henderson tcg_debug_assert(tcg_op_supported(opc)); 4282c896fe29Sbellard /* Note: in order to speed up the code, it would be much 4283c896fe29Sbellard faster to have specialized register allocator functions for 4284c896fe29Sbellard some common argument patterns */ 4285dd186292SRichard Henderson tcg_reg_alloc_op(s, op); 4286c896fe29Sbellard break; 4287c896fe29Sbellard } 42888d8fdbaeSAurelien Jarno #ifdef CONFIG_DEBUG_TCG 4289c896fe29Sbellard check_regs(s); 4290c896fe29Sbellard #endif 4291b125f9dcSRichard Henderson /* Test for (pending) buffer overflow. The assumption is that any 4292b125f9dcSRichard Henderson one operation beginning below the high water mark cannot overrun 4293b125f9dcSRichard Henderson the buffer completely. Thus we can test for overflow after 4294b125f9dcSRichard Henderson generating code without having to check during generation. */ 4295644da9b3SJohn Clarke if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) { 4296b125f9dcSRichard Henderson return -1; 4297b125f9dcSRichard Henderson } 42986e6c4efeSRichard Henderson /* Test for TB overflow, as seen by gen_insn_end_off. */ 42996e6c4efeSRichard Henderson if (unlikely(tcg_current_code_size(s) > UINT16_MAX)) { 43006e6c4efeSRichard Henderson return -2; 43016e6c4efeSRichard Henderson } 4302c896fe29Sbellard } 4303fca8a500SRichard Henderson tcg_debug_assert(num_insns >= 0); 4304fca8a500SRichard Henderson s->gen_insn_end_off[num_insns] = tcg_current_code_size(s); 4305c45cb8bbSRichard Henderson 4306b76f0d8cSYeongkyoon Lee /* Generate TB finalization at the end of block */ 4307659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS 4308aeee05f5SRichard Henderson i = tcg_out_ldst_finalize(s); 4309aeee05f5SRichard Henderson if (i < 0) { 4310aeee05f5SRichard Henderson return i; 431123dceda6SRichard Henderson } 4312659ef5cbSRichard Henderson #endif 431357a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS 43141768987bSRichard Henderson i = tcg_out_pool_finalize(s); 43151768987bSRichard Henderson if (i < 0) { 43161768987bSRichard Henderson return i; 431757a26946SRichard Henderson } 431857a26946SRichard Henderson #endif 43197ecd02a0SRichard Henderson if (!tcg_resolve_relocs(s)) { 43207ecd02a0SRichard Henderson return -2; 43217ecd02a0SRichard Henderson } 4322c896fe29Sbellard 4323c896fe29Sbellard /* flush instruction cache */ 43241813e175SRichard Henderson flush_icache_range((uintptr_t)s->code_buf, (uintptr_t)s->code_ptr); 43252aeabc08SStefan Weil 43261813e175SRichard Henderson return tcg_current_code_size(s); 4327c896fe29Sbellard } 4328c896fe29Sbellard 4329a23a9ec6Sbellard #ifdef CONFIG_PROFILER 43303de2faa9SMarkus Armbruster void tcg_dump_info(void) 4331a23a9ec6Sbellard { 4332c3fac113SEmilio G. Cota TCGProfile prof = {}; 4333c3fac113SEmilio G. Cota const TCGProfile *s; 4334c3fac113SEmilio G. Cota int64_t tb_count; 4335c3fac113SEmilio G. Cota int64_t tb_div_count; 4336c3fac113SEmilio G. Cota int64_t tot; 4337c3fac113SEmilio G. Cota 4338c3fac113SEmilio G. Cota tcg_profile_snapshot_counters(&prof); 4339c3fac113SEmilio G. Cota s = &prof; 4340c3fac113SEmilio G. Cota tb_count = s->tb_count; 4341c3fac113SEmilio G. Cota tb_div_count = tb_count ? tb_count : 1; 4342c3fac113SEmilio G. Cota tot = s->interm_time + s->code_time; 4343a23a9ec6Sbellard 43443de2faa9SMarkus Armbruster qemu_printf("JIT cycles %" PRId64 " (%0.3f s at 2.4 GHz)\n", 4345a23a9ec6Sbellard tot, tot / 2.4e9); 43463de2faa9SMarkus Armbruster qemu_printf("translated TBs %" PRId64 " (aborted=%" PRId64 43473de2faa9SMarkus Armbruster " %0.1f%%)\n", 4348fca8a500SRichard Henderson tb_count, s->tb_count1 - tb_count, 4349fca8a500SRichard Henderson (double)(s->tb_count1 - s->tb_count) 4350fca8a500SRichard Henderson / (s->tb_count1 ? s->tb_count1 : 1) * 100.0); 43513de2faa9SMarkus Armbruster qemu_printf("avg ops/TB %0.1f max=%d\n", 4352fca8a500SRichard Henderson (double)s->op_count / tb_div_count, s->op_count_max); 43533de2faa9SMarkus Armbruster qemu_printf("deleted ops/TB %0.2f\n", 4354fca8a500SRichard Henderson (double)s->del_op_count / tb_div_count); 43553de2faa9SMarkus Armbruster qemu_printf("avg temps/TB %0.2f max=%d\n", 4356fca8a500SRichard Henderson (double)s->temp_count / tb_div_count, s->temp_count_max); 43573de2faa9SMarkus Armbruster qemu_printf("avg host code/TB %0.1f\n", 4358fca8a500SRichard Henderson (double)s->code_out_len / tb_div_count); 43593de2faa9SMarkus Armbruster qemu_printf("avg search data/TB %0.1f\n", 4360fca8a500SRichard Henderson (double)s->search_out_len / tb_div_count); 4361a23a9ec6Sbellard 43623de2faa9SMarkus Armbruster qemu_printf("cycles/op %0.1f\n", 4363a23a9ec6Sbellard s->op_count ? (double)tot / s->op_count : 0); 43643de2faa9SMarkus Armbruster qemu_printf("cycles/in byte %0.1f\n", 4365a23a9ec6Sbellard s->code_in_len ? (double)tot / s->code_in_len : 0); 43663de2faa9SMarkus Armbruster qemu_printf("cycles/out byte %0.1f\n", 4367a23a9ec6Sbellard s->code_out_len ? (double)tot / s->code_out_len : 0); 43683de2faa9SMarkus Armbruster qemu_printf("cycles/search byte %0.1f\n", 4369fca8a500SRichard Henderson s->search_out_len ? (double)tot / s->search_out_len : 0); 4370fca8a500SRichard Henderson if (tot == 0) { 4371a23a9ec6Sbellard tot = 1; 4372fca8a500SRichard Henderson } 43733de2faa9SMarkus Armbruster qemu_printf(" gen_interm time %0.1f%%\n", 4374a23a9ec6Sbellard (double)s->interm_time / tot * 100.0); 43753de2faa9SMarkus Armbruster qemu_printf(" gen_code time %0.1f%%\n", 4376a23a9ec6Sbellard (double)s->code_time / tot * 100.0); 43773de2faa9SMarkus Armbruster qemu_printf("optim./code time %0.1f%%\n", 4378c5cc28ffSAurelien Jarno (double)s->opt_time / (s->code_time ? s->code_time : 1) 4379c5cc28ffSAurelien Jarno * 100.0); 43803de2faa9SMarkus Armbruster qemu_printf("liveness/code time %0.1f%%\n", 4381a23a9ec6Sbellard (double)s->la_time / (s->code_time ? s->code_time : 1) * 100.0); 43823de2faa9SMarkus Armbruster qemu_printf("cpu_restore count %" PRId64 "\n", 4383a23a9ec6Sbellard s->restore_count); 43843de2faa9SMarkus Armbruster qemu_printf(" avg cycles %0.1f\n", 4385a23a9ec6Sbellard s->restore_count ? (double)s->restore_time / s->restore_count : 0); 4386a23a9ec6Sbellard } 4387a23a9ec6Sbellard #else 43883de2faa9SMarkus Armbruster void tcg_dump_info(void) 4389a23a9ec6Sbellard { 43903de2faa9SMarkus Armbruster qemu_printf("[TCG profiler not compiled]\n"); 4391a23a9ec6Sbellard } 4392a23a9ec6Sbellard #endif 4393813da627SRichard Henderson 4394813da627SRichard Henderson #ifdef ELF_HOST_MACHINE 43955872bbf2SRichard Henderson /* In order to use this feature, the backend needs to do three things: 43965872bbf2SRichard Henderson 43975872bbf2SRichard Henderson (1) Define ELF_HOST_MACHINE to indicate both what value to 43985872bbf2SRichard Henderson put into the ELF image and to indicate support for the feature. 43995872bbf2SRichard Henderson 44005872bbf2SRichard Henderson (2) Define tcg_register_jit. This should create a buffer containing 44015872bbf2SRichard Henderson the contents of a .debug_frame section that describes the post- 44025872bbf2SRichard Henderson prologue unwind info for the tcg machine. 44035872bbf2SRichard Henderson 44045872bbf2SRichard Henderson (3) Call tcg_register_jit_int, with the constructed .debug_frame. 44055872bbf2SRichard Henderson */ 4406813da627SRichard Henderson 4407813da627SRichard Henderson /* Begin GDB interface. THE FOLLOWING MUST MATCH GDB DOCS. */ 4408813da627SRichard Henderson typedef enum { 4409813da627SRichard Henderson JIT_NOACTION = 0, 4410813da627SRichard Henderson JIT_REGISTER_FN, 4411813da627SRichard Henderson JIT_UNREGISTER_FN 4412813da627SRichard Henderson } jit_actions_t; 4413813da627SRichard Henderson 4414813da627SRichard Henderson struct jit_code_entry { 4415813da627SRichard Henderson struct jit_code_entry *next_entry; 4416813da627SRichard Henderson struct jit_code_entry *prev_entry; 4417813da627SRichard Henderson const void *symfile_addr; 4418813da627SRichard Henderson uint64_t symfile_size; 4419813da627SRichard Henderson }; 4420813da627SRichard Henderson 4421813da627SRichard Henderson struct jit_descriptor { 4422813da627SRichard Henderson uint32_t version; 4423813da627SRichard Henderson uint32_t action_flag; 4424813da627SRichard Henderson struct jit_code_entry *relevant_entry; 4425813da627SRichard Henderson struct jit_code_entry *first_entry; 4426813da627SRichard Henderson }; 4427813da627SRichard Henderson 4428813da627SRichard Henderson void __jit_debug_register_code(void) __attribute__((noinline)); 4429813da627SRichard Henderson void __jit_debug_register_code(void) 4430813da627SRichard Henderson { 4431813da627SRichard Henderson asm(""); 4432813da627SRichard Henderson } 4433813da627SRichard Henderson 4434813da627SRichard Henderson /* Must statically initialize the version, because GDB may check 4435813da627SRichard Henderson the version before we can set it. */ 4436813da627SRichard Henderson struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 }; 4437813da627SRichard Henderson 4438813da627SRichard Henderson /* End GDB interface. */ 4439813da627SRichard Henderson 4440813da627SRichard Henderson static int find_string(const char *strtab, const char *str) 4441813da627SRichard Henderson { 4442813da627SRichard Henderson const char *p = strtab + 1; 4443813da627SRichard Henderson 4444813da627SRichard Henderson while (1) { 4445813da627SRichard Henderson if (strcmp(p, str) == 0) { 4446813da627SRichard Henderson return p - strtab; 4447813da627SRichard Henderson } 4448813da627SRichard Henderson p += strlen(p) + 1; 4449813da627SRichard Henderson } 4450813da627SRichard Henderson } 4451813da627SRichard Henderson 44525872bbf2SRichard Henderson static void tcg_register_jit_int(void *buf_ptr, size_t buf_size, 44532c90784aSRichard Henderson const void *debug_frame, 44542c90784aSRichard Henderson size_t debug_frame_size) 4455813da627SRichard Henderson { 44565872bbf2SRichard Henderson struct __attribute__((packed)) DebugInfo { 44575872bbf2SRichard Henderson uint32_t len; 44585872bbf2SRichard Henderson uint16_t version; 44595872bbf2SRichard Henderson uint32_t abbrev; 44605872bbf2SRichard Henderson uint8_t ptr_size; 44615872bbf2SRichard Henderson uint8_t cu_die; 44625872bbf2SRichard Henderson uint16_t cu_lang; 44635872bbf2SRichard Henderson uintptr_t cu_low_pc; 44645872bbf2SRichard Henderson uintptr_t cu_high_pc; 44655872bbf2SRichard Henderson uint8_t fn_die; 44665872bbf2SRichard Henderson char fn_name[16]; 44675872bbf2SRichard Henderson uintptr_t fn_low_pc; 44685872bbf2SRichard Henderson uintptr_t fn_high_pc; 44695872bbf2SRichard Henderson uint8_t cu_eoc; 44705872bbf2SRichard Henderson }; 4471813da627SRichard Henderson 4472813da627SRichard Henderson struct ElfImage { 4473813da627SRichard Henderson ElfW(Ehdr) ehdr; 4474813da627SRichard Henderson ElfW(Phdr) phdr; 44755872bbf2SRichard Henderson ElfW(Shdr) shdr[7]; 44765872bbf2SRichard Henderson ElfW(Sym) sym[2]; 44775872bbf2SRichard Henderson struct DebugInfo di; 44785872bbf2SRichard Henderson uint8_t da[24]; 44795872bbf2SRichard Henderson char str[80]; 44805872bbf2SRichard Henderson }; 44815872bbf2SRichard Henderson 44825872bbf2SRichard Henderson struct ElfImage *img; 44835872bbf2SRichard Henderson 44845872bbf2SRichard Henderson static const struct ElfImage img_template = { 44855872bbf2SRichard Henderson .ehdr = { 44865872bbf2SRichard Henderson .e_ident[EI_MAG0] = ELFMAG0, 44875872bbf2SRichard Henderson .e_ident[EI_MAG1] = ELFMAG1, 44885872bbf2SRichard Henderson .e_ident[EI_MAG2] = ELFMAG2, 44895872bbf2SRichard Henderson .e_ident[EI_MAG3] = ELFMAG3, 44905872bbf2SRichard Henderson .e_ident[EI_CLASS] = ELF_CLASS, 44915872bbf2SRichard Henderson .e_ident[EI_DATA] = ELF_DATA, 44925872bbf2SRichard Henderson .e_ident[EI_VERSION] = EV_CURRENT, 44935872bbf2SRichard Henderson .e_type = ET_EXEC, 44945872bbf2SRichard Henderson .e_machine = ELF_HOST_MACHINE, 44955872bbf2SRichard Henderson .e_version = EV_CURRENT, 44965872bbf2SRichard Henderson .e_phoff = offsetof(struct ElfImage, phdr), 44975872bbf2SRichard Henderson .e_shoff = offsetof(struct ElfImage, shdr), 44985872bbf2SRichard Henderson .e_ehsize = sizeof(ElfW(Shdr)), 44995872bbf2SRichard Henderson .e_phentsize = sizeof(ElfW(Phdr)), 45005872bbf2SRichard Henderson .e_phnum = 1, 45015872bbf2SRichard Henderson .e_shentsize = sizeof(ElfW(Shdr)), 45025872bbf2SRichard Henderson .e_shnum = ARRAY_SIZE(img->shdr), 45035872bbf2SRichard Henderson .e_shstrndx = ARRAY_SIZE(img->shdr) - 1, 4504abbb3eaeSRichard Henderson #ifdef ELF_HOST_FLAGS 4505abbb3eaeSRichard Henderson .e_flags = ELF_HOST_FLAGS, 4506abbb3eaeSRichard Henderson #endif 4507abbb3eaeSRichard Henderson #ifdef ELF_OSABI 4508abbb3eaeSRichard Henderson .e_ident[EI_OSABI] = ELF_OSABI, 4509abbb3eaeSRichard Henderson #endif 45105872bbf2SRichard Henderson }, 45115872bbf2SRichard Henderson .phdr = { 45125872bbf2SRichard Henderson .p_type = PT_LOAD, 45135872bbf2SRichard Henderson .p_flags = PF_X, 45145872bbf2SRichard Henderson }, 45155872bbf2SRichard Henderson .shdr = { 45165872bbf2SRichard Henderson [0] = { .sh_type = SHT_NULL }, 45175872bbf2SRichard Henderson /* Trick: The contents of code_gen_buffer are not present in 45185872bbf2SRichard Henderson this fake ELF file; that got allocated elsewhere. Therefore 45195872bbf2SRichard Henderson we mark .text as SHT_NOBITS (similar to .bss) so that readers 45205872bbf2SRichard Henderson will not look for contents. We can record any address. */ 45215872bbf2SRichard Henderson [1] = { /* .text */ 45225872bbf2SRichard Henderson .sh_type = SHT_NOBITS, 45235872bbf2SRichard Henderson .sh_flags = SHF_EXECINSTR | SHF_ALLOC, 45245872bbf2SRichard Henderson }, 45255872bbf2SRichard Henderson [2] = { /* .debug_info */ 45265872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 45275872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, di), 45285872bbf2SRichard Henderson .sh_size = sizeof(struct DebugInfo), 45295872bbf2SRichard Henderson }, 45305872bbf2SRichard Henderson [3] = { /* .debug_abbrev */ 45315872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 45325872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, da), 45335872bbf2SRichard Henderson .sh_size = sizeof(img->da), 45345872bbf2SRichard Henderson }, 45355872bbf2SRichard Henderson [4] = { /* .debug_frame */ 45365872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 45375872bbf2SRichard Henderson .sh_offset = sizeof(struct ElfImage), 45385872bbf2SRichard Henderson }, 45395872bbf2SRichard Henderson [5] = { /* .symtab */ 45405872bbf2SRichard Henderson .sh_type = SHT_SYMTAB, 45415872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, sym), 45425872bbf2SRichard Henderson .sh_size = sizeof(img->sym), 45435872bbf2SRichard Henderson .sh_info = 1, 45445872bbf2SRichard Henderson .sh_link = ARRAY_SIZE(img->shdr) - 1, 45455872bbf2SRichard Henderson .sh_entsize = sizeof(ElfW(Sym)), 45465872bbf2SRichard Henderson }, 45475872bbf2SRichard Henderson [6] = { /* .strtab */ 45485872bbf2SRichard Henderson .sh_type = SHT_STRTAB, 45495872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, str), 45505872bbf2SRichard Henderson .sh_size = sizeof(img->str), 45515872bbf2SRichard Henderson } 45525872bbf2SRichard Henderson }, 45535872bbf2SRichard Henderson .sym = { 45545872bbf2SRichard Henderson [1] = { /* code_gen_buffer */ 45555872bbf2SRichard Henderson .st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC), 45565872bbf2SRichard Henderson .st_shndx = 1, 45575872bbf2SRichard Henderson } 45585872bbf2SRichard Henderson }, 45595872bbf2SRichard Henderson .di = { 45605872bbf2SRichard Henderson .len = sizeof(struct DebugInfo) - 4, 45615872bbf2SRichard Henderson .version = 2, 45625872bbf2SRichard Henderson .ptr_size = sizeof(void *), 45635872bbf2SRichard Henderson .cu_die = 1, 45645872bbf2SRichard Henderson .cu_lang = 0x8001, /* DW_LANG_Mips_Assembler */ 45655872bbf2SRichard Henderson .fn_die = 2, 45665872bbf2SRichard Henderson .fn_name = "code_gen_buffer" 45675872bbf2SRichard Henderson }, 45685872bbf2SRichard Henderson .da = { 45695872bbf2SRichard Henderson 1, /* abbrev number (the cu) */ 45705872bbf2SRichard Henderson 0x11, 1, /* DW_TAG_compile_unit, has children */ 45715872bbf2SRichard Henderson 0x13, 0x5, /* DW_AT_language, DW_FORM_data2 */ 45725872bbf2SRichard Henderson 0x11, 0x1, /* DW_AT_low_pc, DW_FORM_addr */ 45735872bbf2SRichard Henderson 0x12, 0x1, /* DW_AT_high_pc, DW_FORM_addr */ 45745872bbf2SRichard Henderson 0, 0, /* end of abbrev */ 45755872bbf2SRichard Henderson 2, /* abbrev number (the fn) */ 45765872bbf2SRichard Henderson 0x2e, 0, /* DW_TAG_subprogram, no children */ 45775872bbf2SRichard Henderson 0x3, 0x8, /* DW_AT_name, DW_FORM_string */ 45785872bbf2SRichard Henderson 0x11, 0x1, /* DW_AT_low_pc, DW_FORM_addr */ 45795872bbf2SRichard Henderson 0x12, 0x1, /* DW_AT_high_pc, DW_FORM_addr */ 45805872bbf2SRichard Henderson 0, 0, /* end of abbrev */ 45815872bbf2SRichard Henderson 0 /* no more abbrev */ 45825872bbf2SRichard Henderson }, 45835872bbf2SRichard Henderson .str = "\0" ".text\0" ".debug_info\0" ".debug_abbrev\0" 45845872bbf2SRichard Henderson ".debug_frame\0" ".symtab\0" ".strtab\0" "code_gen_buffer", 4585813da627SRichard Henderson }; 4586813da627SRichard Henderson 4587813da627SRichard Henderson /* We only need a single jit entry; statically allocate it. */ 4588813da627SRichard Henderson static struct jit_code_entry one_entry; 4589813da627SRichard Henderson 45905872bbf2SRichard Henderson uintptr_t buf = (uintptr_t)buf_ptr; 4591813da627SRichard Henderson size_t img_size = sizeof(struct ElfImage) + debug_frame_size; 45922c90784aSRichard Henderson DebugFrameHeader *dfh; 4593813da627SRichard Henderson 45945872bbf2SRichard Henderson img = g_malloc(img_size); 45955872bbf2SRichard Henderson *img = img_template; 4596813da627SRichard Henderson 45975872bbf2SRichard Henderson img->phdr.p_vaddr = buf; 45985872bbf2SRichard Henderson img->phdr.p_paddr = buf; 45995872bbf2SRichard Henderson img->phdr.p_memsz = buf_size; 4600813da627SRichard Henderson 46015872bbf2SRichard Henderson img->shdr[1].sh_name = find_string(img->str, ".text"); 46025872bbf2SRichard Henderson img->shdr[1].sh_addr = buf; 46035872bbf2SRichard Henderson img->shdr[1].sh_size = buf_size; 4604813da627SRichard Henderson 46055872bbf2SRichard Henderson img->shdr[2].sh_name = find_string(img->str, ".debug_info"); 46065872bbf2SRichard Henderson img->shdr[3].sh_name = find_string(img->str, ".debug_abbrev"); 46075872bbf2SRichard Henderson 46085872bbf2SRichard Henderson img->shdr[4].sh_name = find_string(img->str, ".debug_frame"); 46095872bbf2SRichard Henderson img->shdr[4].sh_size = debug_frame_size; 46105872bbf2SRichard Henderson 46115872bbf2SRichard Henderson img->shdr[5].sh_name = find_string(img->str, ".symtab"); 46125872bbf2SRichard Henderson img->shdr[6].sh_name = find_string(img->str, ".strtab"); 46135872bbf2SRichard Henderson 46145872bbf2SRichard Henderson img->sym[1].st_name = find_string(img->str, "code_gen_buffer"); 46155872bbf2SRichard Henderson img->sym[1].st_value = buf; 46165872bbf2SRichard Henderson img->sym[1].st_size = buf_size; 46175872bbf2SRichard Henderson 46185872bbf2SRichard Henderson img->di.cu_low_pc = buf; 461945aba097SRichard Henderson img->di.cu_high_pc = buf + buf_size; 46205872bbf2SRichard Henderson img->di.fn_low_pc = buf; 462145aba097SRichard Henderson img->di.fn_high_pc = buf + buf_size; 4622813da627SRichard Henderson 46232c90784aSRichard Henderson dfh = (DebugFrameHeader *)(img + 1); 46242c90784aSRichard Henderson memcpy(dfh, debug_frame, debug_frame_size); 46252c90784aSRichard Henderson dfh->fde.func_start = buf; 46262c90784aSRichard Henderson dfh->fde.func_len = buf_size; 46272c90784aSRichard Henderson 4628813da627SRichard Henderson #ifdef DEBUG_JIT 4629813da627SRichard Henderson /* Enable this block to be able to debug the ELF image file creation. 4630813da627SRichard Henderson One can use readelf, objdump, or other inspection utilities. */ 4631813da627SRichard Henderson { 4632813da627SRichard Henderson FILE *f = fopen("/tmp/qemu.jit", "w+b"); 4633813da627SRichard Henderson if (f) { 46345872bbf2SRichard Henderson if (fwrite(img, img_size, 1, f) != img_size) { 4635813da627SRichard Henderson /* Avoid stupid unused return value warning for fwrite. */ 4636813da627SRichard Henderson } 4637813da627SRichard Henderson fclose(f); 4638813da627SRichard Henderson } 4639813da627SRichard Henderson } 4640813da627SRichard Henderson #endif 4641813da627SRichard Henderson 4642813da627SRichard Henderson one_entry.symfile_addr = img; 4643813da627SRichard Henderson one_entry.symfile_size = img_size; 4644813da627SRichard Henderson 4645813da627SRichard Henderson __jit_debug_descriptor.action_flag = JIT_REGISTER_FN; 4646813da627SRichard Henderson __jit_debug_descriptor.relevant_entry = &one_entry; 4647813da627SRichard Henderson __jit_debug_descriptor.first_entry = &one_entry; 4648813da627SRichard Henderson __jit_debug_register_code(); 4649813da627SRichard Henderson } 4650813da627SRichard Henderson #else 46515872bbf2SRichard Henderson /* No support for the feature. Provide the entry point expected by exec.c, 46525872bbf2SRichard Henderson and implement the internal function we declared earlier. */ 4653813da627SRichard Henderson 4654813da627SRichard Henderson static void tcg_register_jit_int(void *buf, size_t size, 46552c90784aSRichard Henderson const void *debug_frame, 46562c90784aSRichard Henderson size_t debug_frame_size) 4657813da627SRichard Henderson { 4658813da627SRichard Henderson } 4659813da627SRichard Henderson 4660813da627SRichard Henderson void tcg_register_jit(void *buf, size_t buf_size) 4661813da627SRichard Henderson { 4662813da627SRichard Henderson } 4663813da627SRichard Henderson #endif /* ELF_HOST_MACHINE */ 4664db432672SRichard Henderson 4665db432672SRichard Henderson #if !TCG_TARGET_MAYBE_vec 4666db432672SRichard Henderson void tcg_expand_vec_op(TCGOpcode o, TCGType t, unsigned e, TCGArg a0, ...) 4667db432672SRichard Henderson { 4668db432672SRichard Henderson g_assert_not_reached(); 4669db432672SRichard Henderson } 4670db432672SRichard Henderson #endif 4671