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" 38c896fe29Sbellard 39c5d3c498SStefan Weil /* Note: the long term plan is to reduce the dependencies on the QEMU 40c896fe29Sbellard CPU definitions. Currently they are used for qemu_ld/st 41c896fe29Sbellard instructions */ 42c896fe29Sbellard #define NO_CPU_IO_DEFS 43c896fe29Sbellard #include "cpu.h" 44c896fe29Sbellard 4563c91552SPaolo Bonzini #include "exec/exec-all.h" 4663c91552SPaolo Bonzini 475cc8767dSLike Xu #if !defined(CONFIG_USER_ONLY) 485cc8767dSLike Xu #include "hw/boards.h" 495cc8767dSLike Xu #endif 505cc8767dSLike Xu 51*dcb32f1dSPhilippe Mathieu-Daudé #include "tcg/tcg-op.h" 52813da627SRichard Henderson 53edee2579SRichard Henderson #if UINTPTR_MAX == UINT32_MAX 54813da627SRichard Henderson # define ELF_CLASS ELFCLASS32 55edee2579SRichard Henderson #else 56edee2579SRichard Henderson # define ELF_CLASS ELFCLASS64 57813da627SRichard Henderson #endif 58813da627SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN 59813da627SRichard Henderson # define ELF_DATA ELFDATA2MSB 60813da627SRichard Henderson #else 61813da627SRichard Henderson # define ELF_DATA ELFDATA2LSB 62813da627SRichard Henderson #endif 63813da627SRichard Henderson 64c896fe29Sbellard #include "elf.h" 65508127e2SPaolo Bonzini #include "exec/log.h" 663468b59eSEmilio G. Cota #include "sysemu/sysemu.h" 67c896fe29Sbellard 68ce151109SPeter Maydell /* Forward declarations for functions declared in tcg-target.inc.c and 69ce151109SPeter Maydell used here. */ 70e4d58b41SRichard Henderson static void tcg_target_init(TCGContext *s); 71f69d277eSRichard Henderson static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode); 72e4d58b41SRichard Henderson static void tcg_target_qemu_prologue(TCGContext *s); 736ac17786SRichard Henderson static bool patch_reloc(tcg_insn_unit *code_ptr, int type, 742ba7fae2SRichard Henderson intptr_t value, intptr_t addend); 75c896fe29Sbellard 76497a22ebSRichard Henderson /* The CIE and FDE header definitions will be common to all hosts. */ 77497a22ebSRichard Henderson typedef struct { 78497a22ebSRichard Henderson uint32_t len __attribute__((aligned((sizeof(void *))))); 79497a22ebSRichard Henderson uint32_t id; 80497a22ebSRichard Henderson uint8_t version; 81497a22ebSRichard Henderson char augmentation[1]; 82497a22ebSRichard Henderson uint8_t code_align; 83497a22ebSRichard Henderson uint8_t data_align; 84497a22ebSRichard Henderson uint8_t return_column; 85497a22ebSRichard Henderson } DebugFrameCIE; 86497a22ebSRichard Henderson 87497a22ebSRichard Henderson typedef struct QEMU_PACKED { 88497a22ebSRichard Henderson uint32_t len __attribute__((aligned((sizeof(void *))))); 89497a22ebSRichard Henderson uint32_t cie_offset; 90edee2579SRichard Henderson uintptr_t func_start; 91edee2579SRichard Henderson uintptr_t func_len; 92497a22ebSRichard Henderson } DebugFrameFDEHeader; 93497a22ebSRichard Henderson 942c90784aSRichard Henderson typedef struct QEMU_PACKED { 952c90784aSRichard Henderson DebugFrameCIE cie; 962c90784aSRichard Henderson DebugFrameFDEHeader fde; 972c90784aSRichard Henderson } DebugFrameHeader; 982c90784aSRichard Henderson 99813da627SRichard Henderson static void tcg_register_jit_int(void *buf, size_t size, 1002c90784aSRichard Henderson const void *debug_frame, 1012c90784aSRichard Henderson size_t debug_frame_size) 102813da627SRichard Henderson __attribute__((unused)); 103813da627SRichard Henderson 104ce151109SPeter Maydell /* Forward declarations for functions declared and used in tcg-target.inc.c. */ 105069ea736SRichard Henderson static const char *target_parse_constraint(TCGArgConstraint *ct, 106069ea736SRichard Henderson const char *ct_str, TCGType type); 1072a534affSRichard Henderson static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1, 108a05b5b9bSRichard Henderson intptr_t arg2); 10978113e83SRichard Henderson static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg); 110c0ad3001SStefan Weil static void tcg_out_movi(TCGContext *s, TCGType type, 1112a534affSRichard Henderson TCGReg ret, tcg_target_long arg); 112c0ad3001SStefan Weil static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, 113c0ad3001SStefan Weil const int *const_args); 114d2fd745fSRichard Henderson #if TCG_TARGET_MAYBE_vec 115e7632cfaSRichard Henderson static bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece, 116e7632cfaSRichard Henderson TCGReg dst, TCGReg src); 117d6ecb4a9SRichard Henderson static bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece, 118d6ecb4a9SRichard Henderson TCGReg dst, TCGReg base, intptr_t offset); 119e7632cfaSRichard Henderson static void tcg_out_dupi_vec(TCGContext *s, TCGType type, 120e7632cfaSRichard Henderson TCGReg dst, tcg_target_long arg); 121d2fd745fSRichard Henderson static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc, unsigned vecl, 122d2fd745fSRichard Henderson unsigned vece, const TCGArg *args, 123d2fd745fSRichard Henderson const int *const_args); 124d2fd745fSRichard Henderson #else 125e7632cfaSRichard Henderson static inline bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece, 126e7632cfaSRichard Henderson TCGReg dst, TCGReg src) 127e7632cfaSRichard Henderson { 128e7632cfaSRichard Henderson g_assert_not_reached(); 129e7632cfaSRichard Henderson } 130d6ecb4a9SRichard Henderson static inline bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece, 131d6ecb4a9SRichard Henderson TCGReg dst, TCGReg base, intptr_t offset) 132d6ecb4a9SRichard Henderson { 133d6ecb4a9SRichard Henderson g_assert_not_reached(); 134d6ecb4a9SRichard Henderson } 135e7632cfaSRichard Henderson static inline void tcg_out_dupi_vec(TCGContext *s, TCGType type, 136e7632cfaSRichard Henderson TCGReg dst, tcg_target_long arg) 137e7632cfaSRichard Henderson { 138e7632cfaSRichard Henderson g_assert_not_reached(); 139e7632cfaSRichard Henderson } 140d2fd745fSRichard Henderson static inline void tcg_out_vec_op(TCGContext *s, TCGOpcode opc, unsigned vecl, 141d2fd745fSRichard Henderson unsigned vece, const TCGArg *args, 142d2fd745fSRichard Henderson const int *const_args) 143d2fd745fSRichard Henderson { 144d2fd745fSRichard Henderson g_assert_not_reached(); 145d2fd745fSRichard Henderson } 146d2fd745fSRichard Henderson #endif 1472a534affSRichard Henderson static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1, 148a05b5b9bSRichard Henderson intptr_t arg2); 14959d7c14eSRichard Henderson static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val, 15059d7c14eSRichard Henderson TCGReg base, intptr_t ofs); 151cf066674SRichard Henderson static void tcg_out_call(TCGContext *s, tcg_insn_unit *target); 152f6c6afc1SRichard Henderson static int tcg_target_const_match(tcg_target_long val, TCGType type, 153c0ad3001SStefan Weil const TCGArgConstraint *arg_ct); 154659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS 155aeee05f5SRichard Henderson static int tcg_out_ldst_finalize(TCGContext *s); 156659ef5cbSRichard Henderson #endif 157c896fe29Sbellard 158a505785cSEmilio G. Cota #define TCG_HIGHWATER 1024 159a505785cSEmilio G. Cota 160df2cce29SEmilio G. Cota static TCGContext **tcg_ctxs; 161df2cce29SEmilio G. Cota static unsigned int n_tcg_ctxs; 1621c2adb95SRichard Henderson TCGv_env cpu_env = 0; 163df2cce29SEmilio G. Cota 164be2cdc5eSEmilio G. Cota struct tcg_region_tree { 165be2cdc5eSEmilio G. Cota QemuMutex lock; 166be2cdc5eSEmilio G. Cota GTree *tree; 167be2cdc5eSEmilio G. Cota /* padding to avoid false sharing is computed at run-time */ 168be2cdc5eSEmilio G. Cota }; 169be2cdc5eSEmilio G. Cota 170e8feb96fSEmilio G. Cota /* 171e8feb96fSEmilio G. Cota * We divide code_gen_buffer into equally-sized "regions" that TCG threads 172e8feb96fSEmilio G. Cota * dynamically allocate from as demand dictates. Given appropriate region 173e8feb96fSEmilio G. Cota * sizing, this minimizes flushes even when some TCG threads generate a lot 174e8feb96fSEmilio G. Cota * more code than others. 175e8feb96fSEmilio G. Cota */ 176e8feb96fSEmilio G. Cota struct tcg_region_state { 177e8feb96fSEmilio G. Cota QemuMutex lock; 178e8feb96fSEmilio G. Cota 179e8feb96fSEmilio G. Cota /* fields set at init time */ 180e8feb96fSEmilio G. Cota void *start; 181e8feb96fSEmilio G. Cota void *start_aligned; 182e8feb96fSEmilio G. Cota void *end; 183e8feb96fSEmilio G. Cota size_t n; 184e8feb96fSEmilio G. Cota size_t size; /* size of one region */ 185e8feb96fSEmilio G. Cota size_t stride; /* .size + guard size */ 186e8feb96fSEmilio G. Cota 187e8feb96fSEmilio G. Cota /* fields protected by the lock */ 188e8feb96fSEmilio G. Cota size_t current; /* current region index */ 189e8feb96fSEmilio G. Cota size_t agg_size_full; /* aggregate size of full regions */ 190e8feb96fSEmilio G. Cota }; 191e8feb96fSEmilio G. Cota 192e8feb96fSEmilio G. Cota static struct tcg_region_state region; 193be2cdc5eSEmilio G. Cota /* 194be2cdc5eSEmilio G. Cota * This is an array of struct tcg_region_tree's, with padding. 195be2cdc5eSEmilio G. Cota * We use void * to simplify the computation of region_trees[i]; each 196be2cdc5eSEmilio G. Cota * struct is found every tree_size bytes. 197be2cdc5eSEmilio G. Cota */ 198be2cdc5eSEmilio G. Cota static void *region_trees; 199be2cdc5eSEmilio G. Cota static size_t tree_size; 200d2fd745fSRichard Henderson static TCGRegSet tcg_target_available_regs[TCG_TYPE_COUNT]; 201b1d8e52eSblueswir1 static TCGRegSet tcg_target_call_clobber_regs; 202c896fe29Sbellard 2031813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE == 1 2044196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out8(TCGContext *s, uint8_t v) 205c896fe29Sbellard { 206c896fe29Sbellard *s->code_ptr++ = v; 207c896fe29Sbellard } 208c896fe29Sbellard 2094196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch8(tcg_insn_unit *p, 2104196dca6SPeter Maydell uint8_t v) 2115c53bb81SPeter Maydell { 2121813e175SRichard Henderson *p = v; 2135c53bb81SPeter Maydell } 2141813e175SRichard Henderson #endif 2155c53bb81SPeter Maydell 2161813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 2 2174196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out16(TCGContext *s, uint16_t v) 218c896fe29Sbellard { 2191813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 2) { 2201813e175SRichard Henderson *s->code_ptr++ = v; 2211813e175SRichard Henderson } else { 2221813e175SRichard Henderson tcg_insn_unit *p = s->code_ptr; 2234387345aSPeter Maydell memcpy(p, &v, sizeof(v)); 2241813e175SRichard Henderson s->code_ptr = p + (2 / TCG_TARGET_INSN_UNIT_SIZE); 2251813e175SRichard Henderson } 226c896fe29Sbellard } 227c896fe29Sbellard 2284196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch16(tcg_insn_unit *p, 2294196dca6SPeter Maydell uint16_t v) 2305c53bb81SPeter Maydell { 2311813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 2) { 2321813e175SRichard Henderson *p = v; 2331813e175SRichard Henderson } else { 2345c53bb81SPeter Maydell memcpy(p, &v, sizeof(v)); 2355c53bb81SPeter Maydell } 2361813e175SRichard Henderson } 2371813e175SRichard Henderson #endif 2385c53bb81SPeter Maydell 2391813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 4 2404196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out32(TCGContext *s, uint32_t v) 241c896fe29Sbellard { 2421813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 4) { 2431813e175SRichard Henderson *s->code_ptr++ = v; 2441813e175SRichard Henderson } else { 2451813e175SRichard Henderson tcg_insn_unit *p = s->code_ptr; 2464387345aSPeter Maydell memcpy(p, &v, sizeof(v)); 2471813e175SRichard Henderson s->code_ptr = p + (4 / TCG_TARGET_INSN_UNIT_SIZE); 2481813e175SRichard Henderson } 249c896fe29Sbellard } 250c896fe29Sbellard 2514196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch32(tcg_insn_unit *p, 2524196dca6SPeter Maydell uint32_t v) 2535c53bb81SPeter Maydell { 2541813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 4) { 2551813e175SRichard Henderson *p = v; 2561813e175SRichard Henderson } else { 2575c53bb81SPeter Maydell memcpy(p, &v, sizeof(v)); 2585c53bb81SPeter Maydell } 2591813e175SRichard Henderson } 2601813e175SRichard Henderson #endif 2615c53bb81SPeter Maydell 2621813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 8 2634196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out64(TCGContext *s, uint64_t v) 264ac26eb69SRichard Henderson { 2651813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 8) { 2661813e175SRichard Henderson *s->code_ptr++ = v; 2671813e175SRichard Henderson } else { 2681813e175SRichard Henderson tcg_insn_unit *p = s->code_ptr; 2694387345aSPeter Maydell memcpy(p, &v, sizeof(v)); 2701813e175SRichard Henderson s->code_ptr = p + (8 / TCG_TARGET_INSN_UNIT_SIZE); 2711813e175SRichard Henderson } 272ac26eb69SRichard Henderson } 273ac26eb69SRichard Henderson 2744196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch64(tcg_insn_unit *p, 2754196dca6SPeter Maydell uint64_t v) 2765c53bb81SPeter Maydell { 2771813e175SRichard Henderson if (TCG_TARGET_INSN_UNIT_SIZE == 8) { 2781813e175SRichard Henderson *p = v; 2791813e175SRichard Henderson } else { 2805c53bb81SPeter Maydell memcpy(p, &v, sizeof(v)); 2815c53bb81SPeter Maydell } 2821813e175SRichard Henderson } 2831813e175SRichard Henderson #endif 2845c53bb81SPeter Maydell 285c896fe29Sbellard /* label relocation processing */ 286c896fe29Sbellard 2871813e175SRichard Henderson static void tcg_out_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type, 288bec16311SRichard Henderson TCGLabel *l, intptr_t addend) 289c896fe29Sbellard { 2907ecd02a0SRichard Henderson TCGRelocation *r = tcg_malloc(sizeof(TCGRelocation)); 291c896fe29Sbellard 292c896fe29Sbellard r->type = type; 293c896fe29Sbellard r->ptr = code_ptr; 294c896fe29Sbellard r->addend = addend; 2957ecd02a0SRichard Henderson QSIMPLEQ_INSERT_TAIL(&l->relocs, r, next); 296c896fe29Sbellard } 297c896fe29Sbellard 298bec16311SRichard Henderson static void tcg_out_label(TCGContext *s, TCGLabel *l, tcg_insn_unit *ptr) 299c896fe29Sbellard { 300eabb7b91SAurelien Jarno tcg_debug_assert(!l->has_value); 301c896fe29Sbellard l->has_value = 1; 3021813e175SRichard Henderson l->u.value_ptr = ptr; 303c896fe29Sbellard } 304c896fe29Sbellard 30542a268c2SRichard Henderson TCGLabel *gen_new_label(void) 306c896fe29Sbellard { 307b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 30851e3972cSRichard Henderson TCGLabel *l = tcg_malloc(sizeof(TCGLabel)); 309c896fe29Sbellard 3107ecd02a0SRichard Henderson memset(l, 0, sizeof(TCGLabel)); 3117ecd02a0SRichard Henderson l->id = s->nb_labels++; 3127ecd02a0SRichard Henderson QSIMPLEQ_INIT(&l->relocs); 3137ecd02a0SRichard Henderson 314bef16ab4SRichard Henderson QSIMPLEQ_INSERT_TAIL(&s->labels, l, next); 31542a268c2SRichard Henderson 31642a268c2SRichard Henderson return l; 317c896fe29Sbellard } 318c896fe29Sbellard 3197ecd02a0SRichard Henderson static bool tcg_resolve_relocs(TCGContext *s) 3207ecd02a0SRichard Henderson { 3217ecd02a0SRichard Henderson TCGLabel *l; 3227ecd02a0SRichard Henderson 3237ecd02a0SRichard Henderson QSIMPLEQ_FOREACH(l, &s->labels, next) { 3247ecd02a0SRichard Henderson TCGRelocation *r; 3257ecd02a0SRichard Henderson uintptr_t value = l->u.value; 3267ecd02a0SRichard Henderson 3277ecd02a0SRichard Henderson QSIMPLEQ_FOREACH(r, &l->relocs, next) { 3287ecd02a0SRichard Henderson if (!patch_reloc(r->ptr, r->type, value, r->addend)) { 3297ecd02a0SRichard Henderson return false; 3307ecd02a0SRichard Henderson } 3317ecd02a0SRichard Henderson } 3327ecd02a0SRichard Henderson } 3337ecd02a0SRichard Henderson return true; 3347ecd02a0SRichard Henderson } 3357ecd02a0SRichard Henderson 3369f754620SRichard Henderson static void set_jmp_reset_offset(TCGContext *s, int which) 3379f754620SRichard Henderson { 3389f754620SRichard Henderson size_t off = tcg_current_code_size(s); 3399f754620SRichard Henderson s->tb_jmp_reset_offset[which] = off; 3409f754620SRichard Henderson /* Make sure that we didn't overflow the stored offset. */ 3419f754620SRichard Henderson assert(s->tb_jmp_reset_offset[which] == off); 3429f754620SRichard Henderson } 3439f754620SRichard Henderson 344ce151109SPeter Maydell #include "tcg-target.inc.c" 345c896fe29Sbellard 346be2cdc5eSEmilio G. Cota /* compare a pointer @ptr and a tb_tc @s */ 347be2cdc5eSEmilio G. Cota static int ptr_cmp_tb_tc(const void *ptr, const struct tb_tc *s) 348be2cdc5eSEmilio G. Cota { 349be2cdc5eSEmilio G. Cota if (ptr >= s->ptr + s->size) { 350be2cdc5eSEmilio G. Cota return 1; 351be2cdc5eSEmilio G. Cota } else if (ptr < s->ptr) { 352be2cdc5eSEmilio G. Cota return -1; 353be2cdc5eSEmilio G. Cota } 354be2cdc5eSEmilio G. Cota return 0; 355be2cdc5eSEmilio G. Cota } 356be2cdc5eSEmilio G. Cota 357be2cdc5eSEmilio G. Cota static gint tb_tc_cmp(gconstpointer ap, gconstpointer bp) 358be2cdc5eSEmilio G. Cota { 359be2cdc5eSEmilio G. Cota const struct tb_tc *a = ap; 360be2cdc5eSEmilio G. Cota const struct tb_tc *b = bp; 361be2cdc5eSEmilio G. Cota 362be2cdc5eSEmilio G. Cota /* 363be2cdc5eSEmilio G. Cota * When both sizes are set, we know this isn't a lookup. 364be2cdc5eSEmilio G. Cota * This is the most likely case: every TB must be inserted; lookups 365be2cdc5eSEmilio G. Cota * are a lot less frequent. 366be2cdc5eSEmilio G. Cota */ 367be2cdc5eSEmilio G. Cota if (likely(a->size && b->size)) { 368be2cdc5eSEmilio G. Cota if (a->ptr > b->ptr) { 369be2cdc5eSEmilio G. Cota return 1; 370be2cdc5eSEmilio G. Cota } else if (a->ptr < b->ptr) { 371be2cdc5eSEmilio G. Cota return -1; 372be2cdc5eSEmilio G. Cota } 373be2cdc5eSEmilio G. Cota /* a->ptr == b->ptr should happen only on deletions */ 374be2cdc5eSEmilio G. Cota g_assert(a->size == b->size); 375be2cdc5eSEmilio G. Cota return 0; 376be2cdc5eSEmilio G. Cota } 377be2cdc5eSEmilio G. Cota /* 378be2cdc5eSEmilio G. Cota * All lookups have either .size field set to 0. 379be2cdc5eSEmilio G. Cota * From the glib sources we see that @ap is always the lookup key. However 380be2cdc5eSEmilio G. Cota * the docs provide no guarantee, so we just mark this case as likely. 381be2cdc5eSEmilio G. Cota */ 382be2cdc5eSEmilio G. Cota if (likely(a->size == 0)) { 383be2cdc5eSEmilio G. Cota return ptr_cmp_tb_tc(a->ptr, b); 384be2cdc5eSEmilio G. Cota } 385be2cdc5eSEmilio G. Cota return ptr_cmp_tb_tc(b->ptr, a); 386be2cdc5eSEmilio G. Cota } 387be2cdc5eSEmilio G. Cota 388be2cdc5eSEmilio G. Cota static void tcg_region_trees_init(void) 389be2cdc5eSEmilio G. Cota { 390be2cdc5eSEmilio G. Cota size_t i; 391be2cdc5eSEmilio G. Cota 392be2cdc5eSEmilio G. Cota tree_size = ROUND_UP(sizeof(struct tcg_region_tree), qemu_dcache_linesize); 393be2cdc5eSEmilio G. Cota region_trees = qemu_memalign(qemu_dcache_linesize, region.n * tree_size); 394be2cdc5eSEmilio G. Cota for (i = 0; i < region.n; i++) { 395be2cdc5eSEmilio G. Cota struct tcg_region_tree *rt = region_trees + i * tree_size; 396be2cdc5eSEmilio G. Cota 397be2cdc5eSEmilio G. Cota qemu_mutex_init(&rt->lock); 398be2cdc5eSEmilio G. Cota rt->tree = g_tree_new(tb_tc_cmp); 399be2cdc5eSEmilio G. Cota } 400be2cdc5eSEmilio G. Cota } 401be2cdc5eSEmilio G. Cota 402be2cdc5eSEmilio G. Cota static struct tcg_region_tree *tc_ptr_to_region_tree(void *p) 403be2cdc5eSEmilio G. Cota { 404be2cdc5eSEmilio G. Cota size_t region_idx; 405be2cdc5eSEmilio G. Cota 406be2cdc5eSEmilio G. Cota if (p < region.start_aligned) { 407be2cdc5eSEmilio G. Cota region_idx = 0; 408be2cdc5eSEmilio G. Cota } else { 409be2cdc5eSEmilio G. Cota ptrdiff_t offset = p - region.start_aligned; 410be2cdc5eSEmilio G. Cota 411be2cdc5eSEmilio G. Cota if (offset > region.stride * (region.n - 1)) { 412be2cdc5eSEmilio G. Cota region_idx = region.n - 1; 413be2cdc5eSEmilio G. Cota } else { 414be2cdc5eSEmilio G. Cota region_idx = offset / region.stride; 415be2cdc5eSEmilio G. Cota } 416be2cdc5eSEmilio G. Cota } 417be2cdc5eSEmilio G. Cota return region_trees + region_idx * tree_size; 418be2cdc5eSEmilio G. Cota } 419be2cdc5eSEmilio G. Cota 420be2cdc5eSEmilio G. Cota void tcg_tb_insert(TranslationBlock *tb) 421be2cdc5eSEmilio G. Cota { 422be2cdc5eSEmilio G. Cota struct tcg_region_tree *rt = tc_ptr_to_region_tree(tb->tc.ptr); 423be2cdc5eSEmilio G. Cota 424be2cdc5eSEmilio G. Cota qemu_mutex_lock(&rt->lock); 425be2cdc5eSEmilio G. Cota g_tree_insert(rt->tree, &tb->tc, tb); 426be2cdc5eSEmilio G. Cota qemu_mutex_unlock(&rt->lock); 427be2cdc5eSEmilio G. Cota } 428be2cdc5eSEmilio G. Cota 429be2cdc5eSEmilio G. Cota void tcg_tb_remove(TranslationBlock *tb) 430be2cdc5eSEmilio G. Cota { 431be2cdc5eSEmilio G. Cota struct tcg_region_tree *rt = tc_ptr_to_region_tree(tb->tc.ptr); 432be2cdc5eSEmilio G. Cota 433be2cdc5eSEmilio G. Cota qemu_mutex_lock(&rt->lock); 434be2cdc5eSEmilio G. Cota g_tree_remove(rt->tree, &tb->tc); 435be2cdc5eSEmilio G. Cota qemu_mutex_unlock(&rt->lock); 436be2cdc5eSEmilio G. Cota } 437be2cdc5eSEmilio G. Cota 438be2cdc5eSEmilio G. Cota /* 439be2cdc5eSEmilio G. Cota * Find the TB 'tb' such that 440be2cdc5eSEmilio G. Cota * tb->tc.ptr <= tc_ptr < tb->tc.ptr + tb->tc.size 441be2cdc5eSEmilio G. Cota * Return NULL if not found. 442be2cdc5eSEmilio G. Cota */ 443be2cdc5eSEmilio G. Cota TranslationBlock *tcg_tb_lookup(uintptr_t tc_ptr) 444be2cdc5eSEmilio G. Cota { 445be2cdc5eSEmilio G. Cota struct tcg_region_tree *rt = tc_ptr_to_region_tree((void *)tc_ptr); 446be2cdc5eSEmilio G. Cota TranslationBlock *tb; 447be2cdc5eSEmilio G. Cota struct tb_tc s = { .ptr = (void *)tc_ptr }; 448be2cdc5eSEmilio G. Cota 449be2cdc5eSEmilio G. Cota qemu_mutex_lock(&rt->lock); 450be2cdc5eSEmilio G. Cota tb = g_tree_lookup(rt->tree, &s); 451be2cdc5eSEmilio G. Cota qemu_mutex_unlock(&rt->lock); 452be2cdc5eSEmilio G. Cota return tb; 453be2cdc5eSEmilio G. Cota } 454be2cdc5eSEmilio G. Cota 455be2cdc5eSEmilio G. Cota static void tcg_region_tree_lock_all(void) 456be2cdc5eSEmilio G. Cota { 457be2cdc5eSEmilio G. Cota size_t i; 458be2cdc5eSEmilio G. Cota 459be2cdc5eSEmilio G. Cota for (i = 0; i < region.n; i++) { 460be2cdc5eSEmilio G. Cota struct tcg_region_tree *rt = region_trees + i * tree_size; 461be2cdc5eSEmilio G. Cota 462be2cdc5eSEmilio G. Cota qemu_mutex_lock(&rt->lock); 463be2cdc5eSEmilio G. Cota } 464be2cdc5eSEmilio G. Cota } 465be2cdc5eSEmilio G. Cota 466be2cdc5eSEmilio G. Cota static void tcg_region_tree_unlock_all(void) 467be2cdc5eSEmilio G. Cota { 468be2cdc5eSEmilio G. Cota size_t i; 469be2cdc5eSEmilio G. Cota 470be2cdc5eSEmilio G. Cota for (i = 0; i < region.n; i++) { 471be2cdc5eSEmilio G. Cota struct tcg_region_tree *rt = region_trees + i * tree_size; 472be2cdc5eSEmilio G. Cota 473be2cdc5eSEmilio G. Cota qemu_mutex_unlock(&rt->lock); 474be2cdc5eSEmilio G. Cota } 475be2cdc5eSEmilio G. Cota } 476be2cdc5eSEmilio G. Cota 477be2cdc5eSEmilio G. Cota void tcg_tb_foreach(GTraverseFunc func, gpointer user_data) 478be2cdc5eSEmilio G. Cota { 479be2cdc5eSEmilio G. Cota size_t i; 480be2cdc5eSEmilio G. Cota 481be2cdc5eSEmilio G. Cota tcg_region_tree_lock_all(); 482be2cdc5eSEmilio G. Cota for (i = 0; i < region.n; i++) { 483be2cdc5eSEmilio G. Cota struct tcg_region_tree *rt = region_trees + i * tree_size; 484be2cdc5eSEmilio G. Cota 485be2cdc5eSEmilio G. Cota g_tree_foreach(rt->tree, func, user_data); 486be2cdc5eSEmilio G. Cota } 487be2cdc5eSEmilio G. Cota tcg_region_tree_unlock_all(); 488be2cdc5eSEmilio G. Cota } 489be2cdc5eSEmilio G. Cota 490be2cdc5eSEmilio G. Cota size_t tcg_nb_tbs(void) 491be2cdc5eSEmilio G. Cota { 492be2cdc5eSEmilio G. Cota size_t nb_tbs = 0; 493be2cdc5eSEmilio G. Cota size_t i; 494be2cdc5eSEmilio G. Cota 495be2cdc5eSEmilio G. Cota tcg_region_tree_lock_all(); 496be2cdc5eSEmilio G. Cota for (i = 0; i < region.n; i++) { 497be2cdc5eSEmilio G. Cota struct tcg_region_tree *rt = region_trees + i * tree_size; 498be2cdc5eSEmilio G. Cota 499be2cdc5eSEmilio G. Cota nb_tbs += g_tree_nnodes(rt->tree); 500be2cdc5eSEmilio G. Cota } 501be2cdc5eSEmilio G. Cota tcg_region_tree_unlock_all(); 502be2cdc5eSEmilio G. Cota return nb_tbs; 503be2cdc5eSEmilio G. Cota } 504be2cdc5eSEmilio G. Cota 505be2cdc5eSEmilio G. Cota static void tcg_region_tree_reset_all(void) 506be2cdc5eSEmilio G. Cota { 507be2cdc5eSEmilio G. Cota size_t i; 508be2cdc5eSEmilio G. Cota 509be2cdc5eSEmilio G. Cota tcg_region_tree_lock_all(); 510be2cdc5eSEmilio G. Cota for (i = 0; i < region.n; i++) { 511be2cdc5eSEmilio G. Cota struct tcg_region_tree *rt = region_trees + i * tree_size; 512be2cdc5eSEmilio G. Cota 513be2cdc5eSEmilio G. Cota /* Increment the refcount first so that destroy acts as a reset */ 514be2cdc5eSEmilio G. Cota g_tree_ref(rt->tree); 515be2cdc5eSEmilio G. Cota g_tree_destroy(rt->tree); 516be2cdc5eSEmilio G. Cota } 517be2cdc5eSEmilio G. Cota tcg_region_tree_unlock_all(); 518be2cdc5eSEmilio G. Cota } 519be2cdc5eSEmilio G. Cota 520e8feb96fSEmilio G. Cota static void tcg_region_bounds(size_t curr_region, void **pstart, void **pend) 521e8feb96fSEmilio G. Cota { 522e8feb96fSEmilio G. Cota void *start, *end; 523e8feb96fSEmilio G. Cota 524e8feb96fSEmilio G. Cota start = region.start_aligned + curr_region * region.stride; 525e8feb96fSEmilio G. Cota end = start + region.size; 526e8feb96fSEmilio G. Cota 527e8feb96fSEmilio G. Cota if (curr_region == 0) { 528e8feb96fSEmilio G. Cota start = region.start; 529e8feb96fSEmilio G. Cota } 530e8feb96fSEmilio G. Cota if (curr_region == region.n - 1) { 531e8feb96fSEmilio G. Cota end = region.end; 532e8feb96fSEmilio G. Cota } 533e8feb96fSEmilio G. Cota 534e8feb96fSEmilio G. Cota *pstart = start; 535e8feb96fSEmilio G. Cota *pend = end; 536e8feb96fSEmilio G. Cota } 537e8feb96fSEmilio G. Cota 538e8feb96fSEmilio G. Cota static void tcg_region_assign(TCGContext *s, size_t curr_region) 539e8feb96fSEmilio G. Cota { 540e8feb96fSEmilio G. Cota void *start, *end; 541e8feb96fSEmilio G. Cota 542e8feb96fSEmilio G. Cota tcg_region_bounds(curr_region, &start, &end); 543e8feb96fSEmilio G. Cota 544e8feb96fSEmilio G. Cota s->code_gen_buffer = start; 545e8feb96fSEmilio G. Cota s->code_gen_ptr = start; 546e8feb96fSEmilio G. Cota s->code_gen_buffer_size = end - start; 547e8feb96fSEmilio G. Cota s->code_gen_highwater = end - TCG_HIGHWATER; 548e8feb96fSEmilio G. Cota } 549e8feb96fSEmilio G. Cota 550e8feb96fSEmilio G. Cota static bool tcg_region_alloc__locked(TCGContext *s) 551e8feb96fSEmilio G. Cota { 552e8feb96fSEmilio G. Cota if (region.current == region.n) { 553e8feb96fSEmilio G. Cota return true; 554e8feb96fSEmilio G. Cota } 555e8feb96fSEmilio G. Cota tcg_region_assign(s, region.current); 556e8feb96fSEmilio G. Cota region.current++; 557e8feb96fSEmilio G. Cota return false; 558e8feb96fSEmilio G. Cota } 559e8feb96fSEmilio G. Cota 560e8feb96fSEmilio G. Cota /* 561e8feb96fSEmilio G. Cota * Request a new region once the one in use has filled up. 562e8feb96fSEmilio G. Cota * Returns true on error. 563e8feb96fSEmilio G. Cota */ 564e8feb96fSEmilio G. Cota static bool tcg_region_alloc(TCGContext *s) 565e8feb96fSEmilio G. Cota { 566e8feb96fSEmilio G. Cota bool err; 567e8feb96fSEmilio G. Cota /* read the region size now; alloc__locked will overwrite it on success */ 568e8feb96fSEmilio G. Cota size_t size_full = s->code_gen_buffer_size; 569e8feb96fSEmilio G. Cota 570e8feb96fSEmilio G. Cota qemu_mutex_lock(®ion.lock); 571e8feb96fSEmilio G. Cota err = tcg_region_alloc__locked(s); 572e8feb96fSEmilio G. Cota if (!err) { 573e8feb96fSEmilio G. Cota region.agg_size_full += size_full - TCG_HIGHWATER; 574e8feb96fSEmilio G. Cota } 575e8feb96fSEmilio G. Cota qemu_mutex_unlock(®ion.lock); 576e8feb96fSEmilio G. Cota return err; 577e8feb96fSEmilio G. Cota } 578e8feb96fSEmilio G. Cota 579e8feb96fSEmilio G. Cota /* 580e8feb96fSEmilio G. Cota * Perform a context's first region allocation. 581e8feb96fSEmilio G. Cota * This function does _not_ increment region.agg_size_full. 582e8feb96fSEmilio G. Cota */ 583e8feb96fSEmilio G. Cota static inline bool tcg_region_initial_alloc__locked(TCGContext *s) 584e8feb96fSEmilio G. Cota { 585e8feb96fSEmilio G. Cota return tcg_region_alloc__locked(s); 586e8feb96fSEmilio G. Cota } 587e8feb96fSEmilio G. Cota 588e8feb96fSEmilio G. Cota /* Call from a safe-work context */ 589e8feb96fSEmilio G. Cota void tcg_region_reset_all(void) 590e8feb96fSEmilio G. Cota { 5913468b59eSEmilio G. Cota unsigned int n_ctxs = atomic_read(&n_tcg_ctxs); 592e8feb96fSEmilio G. Cota unsigned int i; 593e8feb96fSEmilio G. Cota 594e8feb96fSEmilio G. Cota qemu_mutex_lock(®ion.lock); 595e8feb96fSEmilio G. Cota region.current = 0; 596e8feb96fSEmilio G. Cota region.agg_size_full = 0; 597e8feb96fSEmilio G. Cota 5983468b59eSEmilio G. Cota for (i = 0; i < n_ctxs; i++) { 5993468b59eSEmilio G. Cota TCGContext *s = atomic_read(&tcg_ctxs[i]); 6003468b59eSEmilio G. Cota bool err = tcg_region_initial_alloc__locked(s); 601e8feb96fSEmilio G. Cota 602e8feb96fSEmilio G. Cota g_assert(!err); 603e8feb96fSEmilio G. Cota } 604e8feb96fSEmilio G. Cota qemu_mutex_unlock(®ion.lock); 605be2cdc5eSEmilio G. Cota 606be2cdc5eSEmilio G. Cota tcg_region_tree_reset_all(); 607e8feb96fSEmilio G. Cota } 608e8feb96fSEmilio G. Cota 6093468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY 6103468b59eSEmilio G. Cota static size_t tcg_n_regions(void) 6113468b59eSEmilio G. Cota { 6123468b59eSEmilio G. Cota return 1; 6133468b59eSEmilio G. Cota } 6143468b59eSEmilio G. Cota #else 6153468b59eSEmilio G. Cota /* 6163468b59eSEmilio G. Cota * It is likely that some vCPUs will translate more code than others, so we 6173468b59eSEmilio G. Cota * first try to set more regions than max_cpus, with those regions being of 6183468b59eSEmilio G. Cota * reasonable size. If that's not possible we make do by evenly dividing 6193468b59eSEmilio G. Cota * the code_gen_buffer among the vCPUs. 6203468b59eSEmilio G. Cota */ 6213468b59eSEmilio G. Cota static size_t tcg_n_regions(void) 6223468b59eSEmilio G. Cota { 6233468b59eSEmilio G. Cota size_t i; 6243468b59eSEmilio G. Cota 6253468b59eSEmilio G. Cota /* Use a single region if all we have is one vCPU thread */ 6265cc8767dSLike Xu #if !defined(CONFIG_USER_ONLY) 6275cc8767dSLike Xu MachineState *ms = MACHINE(qdev_get_machine()); 6285cc8767dSLike Xu unsigned int max_cpus = ms->smp.max_cpus; 6295cc8767dSLike Xu #endif 6303468b59eSEmilio G. Cota if (max_cpus == 1 || !qemu_tcg_mttcg_enabled()) { 6313468b59eSEmilio G. Cota return 1; 6323468b59eSEmilio G. Cota } 6333468b59eSEmilio G. Cota 6343468b59eSEmilio G. Cota /* Try to have more regions than max_cpus, with each region being >= 2 MB */ 6353468b59eSEmilio G. Cota for (i = 8; i > 0; i--) { 6363468b59eSEmilio G. Cota size_t regions_per_thread = i; 6373468b59eSEmilio G. Cota size_t region_size; 6383468b59eSEmilio G. Cota 6393468b59eSEmilio G. Cota region_size = tcg_init_ctx.code_gen_buffer_size; 6403468b59eSEmilio G. Cota region_size /= max_cpus * regions_per_thread; 6413468b59eSEmilio G. Cota 6423468b59eSEmilio G. Cota if (region_size >= 2 * 1024u * 1024) { 6433468b59eSEmilio G. Cota return max_cpus * regions_per_thread; 6443468b59eSEmilio G. Cota } 6453468b59eSEmilio G. Cota } 6463468b59eSEmilio G. Cota /* If we can't, then just allocate one region per vCPU thread */ 6473468b59eSEmilio G. Cota return max_cpus; 6483468b59eSEmilio G. Cota } 6493468b59eSEmilio G. Cota #endif 6503468b59eSEmilio G. Cota 651e8feb96fSEmilio G. Cota /* 652e8feb96fSEmilio G. Cota * Initializes region partitioning. 653e8feb96fSEmilio G. Cota * 654e8feb96fSEmilio G. Cota * Called at init time from the parent thread (i.e. the one calling 655e8feb96fSEmilio G. Cota * tcg_context_init), after the target's TCG globals have been set. 6563468b59eSEmilio G. Cota * 6573468b59eSEmilio G. Cota * Region partitioning works by splitting code_gen_buffer into separate regions, 6583468b59eSEmilio G. Cota * and then assigning regions to TCG threads so that the threads can translate 6593468b59eSEmilio G. Cota * code in parallel without synchronization. 6603468b59eSEmilio G. Cota * 6613468b59eSEmilio G. Cota * In softmmu the number of TCG threads is bounded by max_cpus, so we use at 6623468b59eSEmilio G. Cota * least max_cpus regions in MTTCG. In !MTTCG we use a single region. 6633468b59eSEmilio G. Cota * Note that the TCG options from the command-line (i.e. -accel accel=tcg,[...]) 6643468b59eSEmilio G. Cota * must have been parsed before calling this function, since it calls 6653468b59eSEmilio G. Cota * qemu_tcg_mttcg_enabled(). 6663468b59eSEmilio G. Cota * 6673468b59eSEmilio G. Cota * In user-mode we use a single region. Having multiple regions in user-mode 6683468b59eSEmilio G. Cota * is not supported, because the number of vCPU threads (recall that each thread 6693468b59eSEmilio G. Cota * spawned by the guest corresponds to a vCPU thread) is only bounded by the 6703468b59eSEmilio G. Cota * OS, and usually this number is huge (tens of thousands is not uncommon). 6713468b59eSEmilio G. Cota * Thus, given this large bound on the number of vCPU threads and the fact 6723468b59eSEmilio G. Cota * that code_gen_buffer is allocated at compile-time, we cannot guarantee 6733468b59eSEmilio G. Cota * that the availability of at least one region per vCPU thread. 6743468b59eSEmilio G. Cota * 6753468b59eSEmilio G. Cota * However, this user-mode limitation is unlikely to be a significant problem 6763468b59eSEmilio G. Cota * in practice. Multi-threaded guests share most if not all of their translated 6773468b59eSEmilio G. Cota * code, which makes parallel code generation less appealing than in softmmu. 678e8feb96fSEmilio G. Cota */ 679e8feb96fSEmilio G. Cota void tcg_region_init(void) 680e8feb96fSEmilio G. Cota { 681e8feb96fSEmilio G. Cota void *buf = tcg_init_ctx.code_gen_buffer; 682e8feb96fSEmilio G. Cota void *aligned; 683e8feb96fSEmilio G. Cota size_t size = tcg_init_ctx.code_gen_buffer_size; 684e8feb96fSEmilio G. Cota size_t page_size = qemu_real_host_page_size; 685e8feb96fSEmilio G. Cota size_t region_size; 686e8feb96fSEmilio G. Cota size_t n_regions; 687e8feb96fSEmilio G. Cota size_t i; 688e8feb96fSEmilio G. Cota 6893468b59eSEmilio G. Cota n_regions = tcg_n_regions(); 690e8feb96fSEmilio G. Cota 691e8feb96fSEmilio G. Cota /* The first region will be 'aligned - buf' bytes larger than the others */ 692e8feb96fSEmilio G. Cota aligned = QEMU_ALIGN_PTR_UP(buf, page_size); 693e8feb96fSEmilio G. Cota g_assert(aligned < tcg_init_ctx.code_gen_buffer + size); 694e8feb96fSEmilio G. Cota /* 695e8feb96fSEmilio G. Cota * Make region_size a multiple of page_size, using aligned as the start. 696e8feb96fSEmilio G. Cota * As a result of this we might end up with a few extra pages at the end of 697e8feb96fSEmilio G. Cota * the buffer; we will assign those to the last region. 698e8feb96fSEmilio G. Cota */ 699e8feb96fSEmilio G. Cota region_size = (size - (aligned - buf)) / n_regions; 700e8feb96fSEmilio G. Cota region_size = QEMU_ALIGN_DOWN(region_size, page_size); 701e8feb96fSEmilio G. Cota 702e8feb96fSEmilio G. Cota /* A region must have at least 2 pages; one code, one guard */ 703e8feb96fSEmilio G. Cota g_assert(region_size >= 2 * page_size); 704e8feb96fSEmilio G. Cota 705e8feb96fSEmilio G. Cota /* init the region struct */ 706e8feb96fSEmilio G. Cota qemu_mutex_init(®ion.lock); 707e8feb96fSEmilio G. Cota region.n = n_regions; 708e8feb96fSEmilio G. Cota region.size = region_size - page_size; 709e8feb96fSEmilio G. Cota region.stride = region_size; 710e8feb96fSEmilio G. Cota region.start = buf; 711e8feb96fSEmilio G. Cota region.start_aligned = aligned; 712e8feb96fSEmilio G. Cota /* page-align the end, since its last page will be a guard page */ 713e8feb96fSEmilio G. Cota region.end = QEMU_ALIGN_PTR_DOWN(buf + size, page_size); 714e8feb96fSEmilio G. Cota /* account for that last guard page */ 715e8feb96fSEmilio G. Cota region.end -= page_size; 716e8feb96fSEmilio G. Cota 717e8feb96fSEmilio G. Cota /* set guard pages */ 718e8feb96fSEmilio G. Cota for (i = 0; i < region.n; i++) { 719e8feb96fSEmilio G. Cota void *start, *end; 720e8feb96fSEmilio G. Cota int rc; 721e8feb96fSEmilio G. Cota 722e8feb96fSEmilio G. Cota tcg_region_bounds(i, &start, &end); 723e8feb96fSEmilio G. Cota rc = qemu_mprotect_none(end, page_size); 724e8feb96fSEmilio G. Cota g_assert(!rc); 725e8feb96fSEmilio G. Cota } 726e8feb96fSEmilio G. Cota 727be2cdc5eSEmilio G. Cota tcg_region_trees_init(); 728be2cdc5eSEmilio G. Cota 7293468b59eSEmilio G. Cota /* In user-mode we support only one ctx, so do the initial allocation now */ 7303468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY 731e8feb96fSEmilio G. Cota { 732e8feb96fSEmilio G. Cota bool err = tcg_region_initial_alloc__locked(tcg_ctx); 733e8feb96fSEmilio G. Cota 734e8feb96fSEmilio G. Cota g_assert(!err); 735e8feb96fSEmilio G. Cota } 7363468b59eSEmilio G. Cota #endif 737e8feb96fSEmilio G. Cota } 738e8feb96fSEmilio G. Cota 73938b47b19SEmilio G. Cota static void alloc_tcg_plugin_context(TCGContext *s) 74038b47b19SEmilio G. Cota { 74138b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN 74238b47b19SEmilio G. Cota s->plugin_tb = g_new0(struct qemu_plugin_tb, 1); 74338b47b19SEmilio G. Cota s->plugin_tb->insns = 74438b47b19SEmilio G. Cota g_ptr_array_new_with_free_func(qemu_plugin_insn_cleanup_fn); 74538b47b19SEmilio G. Cota #endif 74638b47b19SEmilio G. Cota } 74738b47b19SEmilio G. Cota 748e8feb96fSEmilio G. Cota /* 7493468b59eSEmilio G. Cota * All TCG threads except the parent (i.e. the one that called tcg_context_init 7503468b59eSEmilio G. Cota * and registered the target's TCG globals) must register with this function 7513468b59eSEmilio G. Cota * before initiating translation. 7523468b59eSEmilio G. Cota * 7533468b59eSEmilio G. Cota * In user-mode we just point tcg_ctx to tcg_init_ctx. See the documentation 7543468b59eSEmilio G. Cota * of tcg_region_init() for the reasoning behind this. 7553468b59eSEmilio G. Cota * 7563468b59eSEmilio G. Cota * In softmmu each caller registers its context in tcg_ctxs[]. Note that in 7573468b59eSEmilio G. Cota * softmmu tcg_ctxs[] does not track tcg_ctx_init, since the initial context 7583468b59eSEmilio G. Cota * is not used anymore for translation once this function is called. 7593468b59eSEmilio G. Cota * 7603468b59eSEmilio G. Cota * Not tracking tcg_init_ctx in tcg_ctxs[] in softmmu keeps code that iterates 7613468b59eSEmilio G. Cota * over the array (e.g. tcg_code_size() the same for both softmmu and user-mode. 7623468b59eSEmilio G. Cota */ 7633468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY 7643468b59eSEmilio G. Cota void tcg_register_thread(void) 7653468b59eSEmilio G. Cota { 7663468b59eSEmilio G. Cota tcg_ctx = &tcg_init_ctx; 7673468b59eSEmilio G. Cota } 7683468b59eSEmilio G. Cota #else 7693468b59eSEmilio G. Cota void tcg_register_thread(void) 7703468b59eSEmilio G. Cota { 7715cc8767dSLike Xu MachineState *ms = MACHINE(qdev_get_machine()); 7723468b59eSEmilio G. Cota TCGContext *s = g_malloc(sizeof(*s)); 7733468b59eSEmilio G. Cota unsigned int i, n; 7743468b59eSEmilio G. Cota bool err; 7753468b59eSEmilio G. Cota 7763468b59eSEmilio G. Cota *s = tcg_init_ctx; 7773468b59eSEmilio G. Cota 7783468b59eSEmilio G. Cota /* Relink mem_base. */ 7793468b59eSEmilio G. Cota for (i = 0, n = tcg_init_ctx.nb_globals; i < n; ++i) { 7803468b59eSEmilio G. Cota if (tcg_init_ctx.temps[i].mem_base) { 7813468b59eSEmilio G. Cota ptrdiff_t b = tcg_init_ctx.temps[i].mem_base - tcg_init_ctx.temps; 7823468b59eSEmilio G. Cota tcg_debug_assert(b >= 0 && b < n); 7833468b59eSEmilio G. Cota s->temps[i].mem_base = &s->temps[b]; 7843468b59eSEmilio G. Cota } 7853468b59eSEmilio G. Cota } 7863468b59eSEmilio G. Cota 7873468b59eSEmilio G. Cota /* Claim an entry in tcg_ctxs */ 7883468b59eSEmilio G. Cota n = atomic_fetch_inc(&n_tcg_ctxs); 7895cc8767dSLike Xu g_assert(n < ms->smp.max_cpus); 7903468b59eSEmilio G. Cota atomic_set(&tcg_ctxs[n], s); 7913468b59eSEmilio G. Cota 79238b47b19SEmilio G. Cota if (n > 0) { 79338b47b19SEmilio G. Cota alloc_tcg_plugin_context(s); 79438b47b19SEmilio G. Cota } 79538b47b19SEmilio G. Cota 7963468b59eSEmilio G. Cota tcg_ctx = s; 7973468b59eSEmilio G. Cota qemu_mutex_lock(®ion.lock); 7983468b59eSEmilio G. Cota err = tcg_region_initial_alloc__locked(tcg_ctx); 7993468b59eSEmilio G. Cota g_assert(!err); 8003468b59eSEmilio G. Cota qemu_mutex_unlock(®ion.lock); 8013468b59eSEmilio G. Cota } 8023468b59eSEmilio G. Cota #endif /* !CONFIG_USER_ONLY */ 8033468b59eSEmilio G. Cota 8043468b59eSEmilio G. Cota /* 805e8feb96fSEmilio G. Cota * Returns the size (in bytes) of all translated code (i.e. from all regions) 806e8feb96fSEmilio G. Cota * currently in the cache. 807e8feb96fSEmilio G. Cota * See also: tcg_code_capacity() 808e8feb96fSEmilio G. Cota * Do not confuse with tcg_current_code_size(); that one applies to a single 809e8feb96fSEmilio G. Cota * TCG context. 810e8feb96fSEmilio G. Cota */ 811e8feb96fSEmilio G. Cota size_t tcg_code_size(void) 812e8feb96fSEmilio G. Cota { 8133468b59eSEmilio G. Cota unsigned int n_ctxs = atomic_read(&n_tcg_ctxs); 814e8feb96fSEmilio G. Cota unsigned int i; 815e8feb96fSEmilio G. Cota size_t total; 816e8feb96fSEmilio G. Cota 817e8feb96fSEmilio G. Cota qemu_mutex_lock(®ion.lock); 818e8feb96fSEmilio G. Cota total = region.agg_size_full; 8193468b59eSEmilio G. Cota for (i = 0; i < n_ctxs; i++) { 8203468b59eSEmilio G. Cota const TCGContext *s = atomic_read(&tcg_ctxs[i]); 821e8feb96fSEmilio G. Cota size_t size; 822e8feb96fSEmilio G. Cota 823e8feb96fSEmilio G. Cota size = atomic_read(&s->code_gen_ptr) - s->code_gen_buffer; 824e8feb96fSEmilio G. Cota g_assert(size <= s->code_gen_buffer_size); 825e8feb96fSEmilio G. Cota total += size; 826e8feb96fSEmilio G. Cota } 827e8feb96fSEmilio G. Cota qemu_mutex_unlock(®ion.lock); 828e8feb96fSEmilio G. Cota return total; 829e8feb96fSEmilio G. Cota } 830e8feb96fSEmilio G. Cota 831e8feb96fSEmilio G. Cota /* 832e8feb96fSEmilio G. Cota * Returns the code capacity (in bytes) of the entire cache, i.e. including all 833e8feb96fSEmilio G. Cota * regions. 834e8feb96fSEmilio G. Cota * See also: tcg_code_size() 835e8feb96fSEmilio G. Cota */ 836e8feb96fSEmilio G. Cota size_t tcg_code_capacity(void) 837e8feb96fSEmilio G. Cota { 838e8feb96fSEmilio G. Cota size_t guard_size, capacity; 839e8feb96fSEmilio G. Cota 840e8feb96fSEmilio G. Cota /* no need for synchronization; these variables are set at init time */ 841e8feb96fSEmilio G. Cota guard_size = region.stride - region.size; 842e8feb96fSEmilio G. Cota capacity = region.end + guard_size - region.start; 843e8feb96fSEmilio G. Cota capacity -= region.n * (guard_size + TCG_HIGHWATER); 844e8feb96fSEmilio G. Cota return capacity; 845e8feb96fSEmilio G. Cota } 846e8feb96fSEmilio G. Cota 847128ed227SEmilio G. Cota size_t tcg_tb_phys_invalidate_count(void) 848128ed227SEmilio G. Cota { 849128ed227SEmilio G. Cota unsigned int n_ctxs = atomic_read(&n_tcg_ctxs); 850128ed227SEmilio G. Cota unsigned int i; 851128ed227SEmilio G. Cota size_t total = 0; 852128ed227SEmilio G. Cota 853128ed227SEmilio G. Cota for (i = 0; i < n_ctxs; i++) { 854128ed227SEmilio G. Cota const TCGContext *s = atomic_read(&tcg_ctxs[i]); 855128ed227SEmilio G. Cota 856128ed227SEmilio G. Cota total += atomic_read(&s->tb_phys_invalidate_count); 857128ed227SEmilio G. Cota } 858128ed227SEmilio G. Cota return total; 859128ed227SEmilio G. Cota } 860128ed227SEmilio G. Cota 861c896fe29Sbellard /* pool based memory allocation */ 862c896fe29Sbellard void *tcg_malloc_internal(TCGContext *s, int size) 863c896fe29Sbellard { 864c896fe29Sbellard TCGPool *p; 865c896fe29Sbellard int pool_size; 866c896fe29Sbellard 867c896fe29Sbellard if (size > TCG_POOL_CHUNK_SIZE) { 868c896fe29Sbellard /* big malloc: insert a new pool (XXX: could optimize) */ 8697267c094SAnthony Liguori p = g_malloc(sizeof(TCGPool) + size); 870c896fe29Sbellard p->size = size; 8714055299eSKirill Batuzov p->next = s->pool_first_large; 8724055299eSKirill Batuzov s->pool_first_large = p; 8734055299eSKirill Batuzov return p->data; 874c896fe29Sbellard } else { 875c896fe29Sbellard p = s->pool_current; 876c896fe29Sbellard if (!p) { 877c896fe29Sbellard p = s->pool_first; 878c896fe29Sbellard if (!p) 879c896fe29Sbellard goto new_pool; 880c896fe29Sbellard } else { 881c896fe29Sbellard if (!p->next) { 882c896fe29Sbellard new_pool: 883c896fe29Sbellard pool_size = TCG_POOL_CHUNK_SIZE; 8847267c094SAnthony Liguori p = g_malloc(sizeof(TCGPool) + pool_size); 885c896fe29Sbellard p->size = pool_size; 886c896fe29Sbellard p->next = NULL; 887c896fe29Sbellard if (s->pool_current) 888c896fe29Sbellard s->pool_current->next = p; 889c896fe29Sbellard else 890c896fe29Sbellard s->pool_first = p; 891c896fe29Sbellard } else { 892c896fe29Sbellard p = p->next; 893c896fe29Sbellard } 894c896fe29Sbellard } 895c896fe29Sbellard } 896c896fe29Sbellard s->pool_current = p; 897c896fe29Sbellard s->pool_cur = p->data + size; 898c896fe29Sbellard s->pool_end = p->data + p->size; 899c896fe29Sbellard return p->data; 900c896fe29Sbellard } 901c896fe29Sbellard 902c896fe29Sbellard void tcg_pool_reset(TCGContext *s) 903c896fe29Sbellard { 9044055299eSKirill Batuzov TCGPool *p, *t; 9054055299eSKirill Batuzov for (p = s->pool_first_large; p; p = t) { 9064055299eSKirill Batuzov t = p->next; 9074055299eSKirill Batuzov g_free(p); 9084055299eSKirill Batuzov } 9094055299eSKirill Batuzov s->pool_first_large = NULL; 910c896fe29Sbellard s->pool_cur = s->pool_end = NULL; 911c896fe29Sbellard s->pool_current = NULL; 912c896fe29Sbellard } 913c896fe29Sbellard 914100b5e01SRichard Henderson typedef struct TCGHelperInfo { 915100b5e01SRichard Henderson void *func; 916100b5e01SRichard Henderson const char *name; 917afb49896SRichard Henderson unsigned flags; 918afb49896SRichard Henderson unsigned sizemask; 919100b5e01SRichard Henderson } TCGHelperInfo; 920100b5e01SRichard Henderson 9212ef6175aSRichard Henderson #include "exec/helper-proto.h" 9222ef6175aSRichard Henderson 923100b5e01SRichard Henderson static const TCGHelperInfo all_helpers[] = { 9242ef6175aSRichard Henderson #include "exec/helper-tcg.h" 925100b5e01SRichard Henderson }; 926619205fdSEmilio G. Cota static GHashTable *helper_table; 927100b5e01SRichard Henderson 92891478cefSRichard Henderson static int indirect_reg_alloc_order[ARRAY_SIZE(tcg_target_reg_alloc_order)]; 929f69d277eSRichard Henderson static void process_op_defs(TCGContext *s); 9301c2adb95SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type, 9311c2adb95SRichard Henderson TCGReg reg, const char *name); 93291478cefSRichard Henderson 933c896fe29Sbellard void tcg_context_init(TCGContext *s) 934c896fe29Sbellard { 935100b5e01SRichard Henderson int op, total_args, n, i; 936c896fe29Sbellard TCGOpDef *def; 937c896fe29Sbellard TCGArgConstraint *args_ct; 938c896fe29Sbellard int *sorted_args; 9391c2adb95SRichard Henderson TCGTemp *ts; 940c896fe29Sbellard 941c896fe29Sbellard memset(s, 0, sizeof(*s)); 942c896fe29Sbellard s->nb_globals = 0; 943c896fe29Sbellard 944c896fe29Sbellard /* Count total number of arguments and allocate the corresponding 945c896fe29Sbellard space */ 946c896fe29Sbellard total_args = 0; 947c896fe29Sbellard for(op = 0; op < NB_OPS; op++) { 948c896fe29Sbellard def = &tcg_op_defs[op]; 949c896fe29Sbellard n = def->nb_iargs + def->nb_oargs; 950c896fe29Sbellard total_args += n; 951c896fe29Sbellard } 952c896fe29Sbellard 9537267c094SAnthony Liguori args_ct = g_malloc(sizeof(TCGArgConstraint) * total_args); 9547267c094SAnthony Liguori sorted_args = g_malloc(sizeof(int) * total_args); 955c896fe29Sbellard 956c896fe29Sbellard for(op = 0; op < NB_OPS; op++) { 957c896fe29Sbellard def = &tcg_op_defs[op]; 958c896fe29Sbellard def->args_ct = args_ct; 959c896fe29Sbellard def->sorted_args = sorted_args; 960c896fe29Sbellard n = def->nb_iargs + def->nb_oargs; 961c896fe29Sbellard sorted_args += n; 962c896fe29Sbellard args_ct += n; 963c896fe29Sbellard } 964c896fe29Sbellard 9655cd8f621SRichard Henderson /* Register helpers. */ 96684fd9dd3SRichard Henderson /* Use g_direct_hash/equal for direct pointer comparisons on func. */ 967619205fdSEmilio G. Cota helper_table = g_hash_table_new(NULL, NULL); 96884fd9dd3SRichard Henderson 969100b5e01SRichard Henderson for (i = 0; i < ARRAY_SIZE(all_helpers); ++i) { 97084fd9dd3SRichard Henderson g_hash_table_insert(helper_table, (gpointer)all_helpers[i].func, 97172866e82SRichard Henderson (gpointer)&all_helpers[i]); 972100b5e01SRichard Henderson } 9735cd8f621SRichard Henderson 974c896fe29Sbellard tcg_target_init(s); 975f69d277eSRichard Henderson process_op_defs(s); 97691478cefSRichard Henderson 97791478cefSRichard Henderson /* Reverse the order of the saved registers, assuming they're all at 97891478cefSRichard Henderson the start of tcg_target_reg_alloc_order. */ 97991478cefSRichard Henderson for (n = 0; n < ARRAY_SIZE(tcg_target_reg_alloc_order); ++n) { 98091478cefSRichard Henderson int r = tcg_target_reg_alloc_order[n]; 98191478cefSRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, r)) { 98291478cefSRichard Henderson break; 98391478cefSRichard Henderson } 98491478cefSRichard Henderson } 98591478cefSRichard Henderson for (i = 0; i < n; ++i) { 98691478cefSRichard Henderson indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[n - 1 - i]; 98791478cefSRichard Henderson } 98891478cefSRichard Henderson for (; i < ARRAY_SIZE(tcg_target_reg_alloc_order); ++i) { 98991478cefSRichard Henderson indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[i]; 99091478cefSRichard Henderson } 991b1311c4aSEmilio G. Cota 99238b47b19SEmilio G. Cota alloc_tcg_plugin_context(s); 99338b47b19SEmilio G. Cota 994b1311c4aSEmilio G. Cota tcg_ctx = s; 9953468b59eSEmilio G. Cota /* 9963468b59eSEmilio G. Cota * In user-mode we simply share the init context among threads, since we 9973468b59eSEmilio G. Cota * use a single region. See the documentation tcg_region_init() for the 9983468b59eSEmilio G. Cota * reasoning behind this. 9993468b59eSEmilio G. Cota * In softmmu we will have at most max_cpus TCG threads. 10003468b59eSEmilio G. Cota */ 10013468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY 1002df2cce29SEmilio G. Cota tcg_ctxs = &tcg_ctx; 1003df2cce29SEmilio G. Cota n_tcg_ctxs = 1; 10043468b59eSEmilio G. Cota #else 10055cc8767dSLike Xu MachineState *ms = MACHINE(qdev_get_machine()); 10065cc8767dSLike Xu unsigned int max_cpus = ms->smp.max_cpus; 10073468b59eSEmilio G. Cota tcg_ctxs = g_new(TCGContext *, max_cpus); 10083468b59eSEmilio G. Cota #endif 10091c2adb95SRichard Henderson 10101c2adb95SRichard Henderson tcg_debug_assert(!tcg_regset_test_reg(s->reserved_regs, TCG_AREG0)); 10111c2adb95SRichard Henderson ts = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, TCG_AREG0, "env"); 10121c2adb95SRichard Henderson cpu_env = temp_tcgv_ptr(ts); 10139002ec79SRichard Henderson } 1014b03cce8eSbellard 10156e3b2bfdSEmilio G. Cota /* 10166e3b2bfdSEmilio G. Cota * Allocate TBs right before their corresponding translated code, making 10176e3b2bfdSEmilio G. Cota * sure that TBs and code are on different cache lines. 10186e3b2bfdSEmilio G. Cota */ 10196e3b2bfdSEmilio G. Cota TranslationBlock *tcg_tb_alloc(TCGContext *s) 10206e3b2bfdSEmilio G. Cota { 10216e3b2bfdSEmilio G. Cota uintptr_t align = qemu_icache_linesize; 10226e3b2bfdSEmilio G. Cota TranslationBlock *tb; 10236e3b2bfdSEmilio G. Cota void *next; 10246e3b2bfdSEmilio G. Cota 1025e8feb96fSEmilio G. Cota retry: 10266e3b2bfdSEmilio G. Cota tb = (void *)ROUND_UP((uintptr_t)s->code_gen_ptr, align); 10276e3b2bfdSEmilio G. Cota next = (void *)ROUND_UP((uintptr_t)(tb + 1), align); 10286e3b2bfdSEmilio G. Cota 10296e3b2bfdSEmilio G. Cota if (unlikely(next > s->code_gen_highwater)) { 1030e8feb96fSEmilio G. Cota if (tcg_region_alloc(s)) { 10316e3b2bfdSEmilio G. Cota return NULL; 10326e3b2bfdSEmilio G. Cota } 1033e8feb96fSEmilio G. Cota goto retry; 1034e8feb96fSEmilio G. Cota } 1035e8feb96fSEmilio G. Cota atomic_set(&s->code_gen_ptr, next); 103657a26946SRichard Henderson s->data_gen_ptr = NULL; 10376e3b2bfdSEmilio G. Cota return tb; 10386e3b2bfdSEmilio G. Cota } 10396e3b2bfdSEmilio G. Cota 10409002ec79SRichard Henderson void tcg_prologue_init(TCGContext *s) 10419002ec79SRichard Henderson { 10428163b749SRichard Henderson size_t prologue_size, total_size; 10438163b749SRichard Henderson void *buf0, *buf1; 10448163b749SRichard Henderson 10458163b749SRichard Henderson /* Put the prologue at the beginning of code_gen_buffer. */ 10468163b749SRichard Henderson buf0 = s->code_gen_buffer; 10475b38ee31SRichard Henderson total_size = s->code_gen_buffer_size; 10488163b749SRichard Henderson s->code_ptr = buf0; 10498163b749SRichard Henderson s->code_buf = buf0; 10505b38ee31SRichard Henderson s->data_gen_ptr = NULL; 10518163b749SRichard Henderson s->code_gen_prologue = buf0; 10528163b749SRichard Henderson 10535b38ee31SRichard Henderson /* Compute a high-water mark, at which we voluntarily flush the buffer 10545b38ee31SRichard Henderson and start over. The size here is arbitrary, significantly larger 10555b38ee31SRichard Henderson than we expect the code generation for any one opcode to require. */ 10565b38ee31SRichard Henderson s->code_gen_highwater = s->code_gen_buffer + (total_size - TCG_HIGHWATER); 10575b38ee31SRichard Henderson 10585b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS 10595b38ee31SRichard Henderson s->pool_labels = NULL; 10605b38ee31SRichard Henderson #endif 10615b38ee31SRichard Henderson 10628163b749SRichard Henderson /* Generate the prologue. */ 1063b03cce8eSbellard tcg_target_qemu_prologue(s); 10645b38ee31SRichard Henderson 10655b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS 10665b38ee31SRichard Henderson /* Allow the prologue to put e.g. guest_base into a pool entry. */ 10675b38ee31SRichard Henderson { 10681768987bSRichard Henderson int result = tcg_out_pool_finalize(s); 10691768987bSRichard Henderson tcg_debug_assert(result == 0); 10705b38ee31SRichard Henderson } 10715b38ee31SRichard Henderson #endif 10725b38ee31SRichard Henderson 10738163b749SRichard Henderson buf1 = s->code_ptr; 10748163b749SRichard Henderson flush_icache_range((uintptr_t)buf0, (uintptr_t)buf1); 10758163b749SRichard Henderson 10768163b749SRichard Henderson /* Deduct the prologue from the buffer. */ 10778163b749SRichard Henderson prologue_size = tcg_current_code_size(s); 10788163b749SRichard Henderson s->code_gen_ptr = buf1; 10798163b749SRichard Henderson s->code_gen_buffer = buf1; 10808163b749SRichard Henderson s->code_buf = buf1; 10815b38ee31SRichard Henderson total_size -= prologue_size; 10828163b749SRichard Henderson s->code_gen_buffer_size = total_size; 10838163b749SRichard Henderson 10848163b749SRichard Henderson tcg_register_jit(s->code_gen_buffer, total_size); 1085d6b64b2bSRichard Henderson 1086d6b64b2bSRichard Henderson #ifdef DEBUG_DISAS 1087d6b64b2bSRichard Henderson if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) { 1088fc59d2d8SRobert Foley FILE *logfile = qemu_log_lock(); 10898163b749SRichard Henderson qemu_log("PROLOGUE: [size=%zu]\n", prologue_size); 10905b38ee31SRichard Henderson if (s->data_gen_ptr) { 10915b38ee31SRichard Henderson size_t code_size = s->data_gen_ptr - buf0; 10925b38ee31SRichard Henderson size_t data_size = prologue_size - code_size; 10935b38ee31SRichard Henderson size_t i; 10945b38ee31SRichard Henderson 10955b38ee31SRichard Henderson log_disas(buf0, code_size); 10965b38ee31SRichard Henderson 10975b38ee31SRichard Henderson for (i = 0; i < data_size; i += sizeof(tcg_target_ulong)) { 10985b38ee31SRichard Henderson if (sizeof(tcg_target_ulong) == 8) { 10995b38ee31SRichard Henderson qemu_log("0x%08" PRIxPTR ": .quad 0x%016" PRIx64 "\n", 11005b38ee31SRichard Henderson (uintptr_t)s->data_gen_ptr + i, 11015b38ee31SRichard Henderson *(uint64_t *)(s->data_gen_ptr + i)); 11025b38ee31SRichard Henderson } else { 11035b38ee31SRichard Henderson qemu_log("0x%08" PRIxPTR ": .long 0x%08x\n", 11045b38ee31SRichard Henderson (uintptr_t)s->data_gen_ptr + i, 11055b38ee31SRichard Henderson *(uint32_t *)(s->data_gen_ptr + i)); 11065b38ee31SRichard Henderson } 11075b38ee31SRichard Henderson } 11085b38ee31SRichard Henderson } else { 11098163b749SRichard Henderson log_disas(buf0, prologue_size); 11105b38ee31SRichard Henderson } 1111d6b64b2bSRichard Henderson qemu_log("\n"); 1112d6b64b2bSRichard Henderson qemu_log_flush(); 1113fc59d2d8SRobert Foley qemu_log_unlock(logfile); 1114d6b64b2bSRichard Henderson } 1115d6b64b2bSRichard Henderson #endif 1116cedbcb01SEmilio G. Cota 1117cedbcb01SEmilio G. Cota /* Assert that goto_ptr is implemented completely. */ 1118cedbcb01SEmilio G. Cota if (TCG_TARGET_HAS_goto_ptr) { 1119cedbcb01SEmilio G. Cota tcg_debug_assert(s->code_gen_epilogue != NULL); 1120cedbcb01SEmilio G. Cota } 1121c896fe29Sbellard } 1122c896fe29Sbellard 1123c896fe29Sbellard void tcg_func_start(TCGContext *s) 1124c896fe29Sbellard { 1125c896fe29Sbellard tcg_pool_reset(s); 1126c896fe29Sbellard s->nb_temps = s->nb_globals; 11270ec9eabcSRichard Henderson 11280ec9eabcSRichard Henderson /* No temps have been previously allocated for size or locality. */ 11290ec9eabcSRichard Henderson memset(s->free_temps, 0, sizeof(s->free_temps)); 11300ec9eabcSRichard Henderson 1131abebf925SRichard Henderson s->nb_ops = 0; 1132c896fe29Sbellard s->nb_labels = 0; 1133c896fe29Sbellard s->current_frame_offset = s->frame_start; 1134c896fe29Sbellard 11350a209d4bSRichard Henderson #ifdef CONFIG_DEBUG_TCG 11360a209d4bSRichard Henderson s->goto_tb_issue_mask = 0; 11370a209d4bSRichard Henderson #endif 11380a209d4bSRichard Henderson 113915fa08f8SRichard Henderson QTAILQ_INIT(&s->ops); 114015fa08f8SRichard Henderson QTAILQ_INIT(&s->free_ops); 1141bef16ab4SRichard Henderson QSIMPLEQ_INIT(&s->labels); 1142c896fe29Sbellard } 1143c896fe29Sbellard 11447ca4b752SRichard Henderson static inline TCGTemp *tcg_temp_alloc(TCGContext *s) 11457ca4b752SRichard Henderson { 11467ca4b752SRichard Henderson int n = s->nb_temps++; 11477ca4b752SRichard Henderson tcg_debug_assert(n < TCG_MAX_TEMPS); 11487ca4b752SRichard Henderson return memset(&s->temps[n], 0, sizeof(TCGTemp)); 11497ca4b752SRichard Henderson } 11507ca4b752SRichard Henderson 11517ca4b752SRichard Henderson static inline TCGTemp *tcg_global_alloc(TCGContext *s) 11527ca4b752SRichard Henderson { 1153fa477d25SRichard Henderson TCGTemp *ts; 1154fa477d25SRichard Henderson 11557ca4b752SRichard Henderson tcg_debug_assert(s->nb_globals == s->nb_temps); 11567ca4b752SRichard Henderson s->nb_globals++; 1157fa477d25SRichard Henderson ts = tcg_temp_alloc(s); 1158fa477d25SRichard Henderson ts->temp_global = 1; 1159fa477d25SRichard Henderson 1160fa477d25SRichard Henderson return ts; 1161c896fe29Sbellard } 1162c896fe29Sbellard 1163085272b3SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type, 1164b6638662SRichard Henderson TCGReg reg, const char *name) 1165c896fe29Sbellard { 1166c896fe29Sbellard TCGTemp *ts; 1167c896fe29Sbellard 1168b3a62939SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && type != TCG_TYPE_I32) { 1169c896fe29Sbellard tcg_abort(); 1170b3a62939SRichard Henderson } 11717ca4b752SRichard Henderson 11727ca4b752SRichard Henderson ts = tcg_global_alloc(s); 1173c896fe29Sbellard ts->base_type = type; 1174c896fe29Sbellard ts->type = type; 1175c896fe29Sbellard ts->fixed_reg = 1; 1176c896fe29Sbellard ts->reg = reg; 1177c896fe29Sbellard ts->name = name; 1178c896fe29Sbellard tcg_regset_set_reg(s->reserved_regs, reg); 11797ca4b752SRichard Henderson 1180085272b3SRichard Henderson return ts; 1181a7812ae4Spbrook } 1182a7812ae4Spbrook 1183b6638662SRichard Henderson void tcg_set_frame(TCGContext *s, TCGReg reg, intptr_t start, intptr_t size) 1184a7812ae4Spbrook { 1185b3a62939SRichard Henderson s->frame_start = start; 1186b3a62939SRichard Henderson s->frame_end = start + size; 1187085272b3SRichard Henderson s->frame_temp 1188085272b3SRichard Henderson = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, reg, "_frame"); 1189b3a62939SRichard Henderson } 1190a7812ae4Spbrook 1191085272b3SRichard Henderson TCGTemp *tcg_global_mem_new_internal(TCGType type, TCGv_ptr base, 1192e1ccc054SRichard Henderson intptr_t offset, const char *name) 1193c896fe29Sbellard { 1194b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 1195dc41aa7dSRichard Henderson TCGTemp *base_ts = tcgv_ptr_temp(base); 11967ca4b752SRichard Henderson TCGTemp *ts = tcg_global_alloc(s); 1197b3915dbbSRichard Henderson int indirect_reg = 0, bigendian = 0; 11987ca4b752SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN 11997ca4b752SRichard Henderson bigendian = 1; 12007ca4b752SRichard Henderson #endif 1201c896fe29Sbellard 1202b3915dbbSRichard Henderson if (!base_ts->fixed_reg) { 12035a18407fSRichard Henderson /* We do not support double-indirect registers. */ 12045a18407fSRichard Henderson tcg_debug_assert(!base_ts->indirect_reg); 1205b3915dbbSRichard Henderson base_ts->indirect_base = 1; 12065a18407fSRichard Henderson s->nb_indirects += (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64 12075a18407fSRichard Henderson ? 2 : 1); 12085a18407fSRichard Henderson indirect_reg = 1; 1209b3915dbbSRichard Henderson } 1210b3915dbbSRichard Henderson 12117ca4b752SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) { 12127ca4b752SRichard Henderson TCGTemp *ts2 = tcg_global_alloc(s); 1213c896fe29Sbellard char buf[64]; 12147ca4b752SRichard Henderson 12157ca4b752SRichard Henderson ts->base_type = TCG_TYPE_I64; 1216c896fe29Sbellard ts->type = TCG_TYPE_I32; 1217b3915dbbSRichard Henderson ts->indirect_reg = indirect_reg; 1218c896fe29Sbellard ts->mem_allocated = 1; 1219b3a62939SRichard Henderson ts->mem_base = base_ts; 12207ca4b752SRichard Henderson ts->mem_offset = offset + bigendian * 4; 1221c896fe29Sbellard pstrcpy(buf, sizeof(buf), name); 1222c896fe29Sbellard pstrcat(buf, sizeof(buf), "_0"); 1223c896fe29Sbellard ts->name = strdup(buf); 1224c896fe29Sbellard 12257ca4b752SRichard Henderson tcg_debug_assert(ts2 == ts + 1); 12267ca4b752SRichard Henderson ts2->base_type = TCG_TYPE_I64; 12277ca4b752SRichard Henderson ts2->type = TCG_TYPE_I32; 1228b3915dbbSRichard Henderson ts2->indirect_reg = indirect_reg; 12297ca4b752SRichard Henderson ts2->mem_allocated = 1; 12307ca4b752SRichard Henderson ts2->mem_base = base_ts; 12317ca4b752SRichard Henderson ts2->mem_offset = offset + (1 - bigendian) * 4; 1232c896fe29Sbellard pstrcpy(buf, sizeof(buf), name); 1233c896fe29Sbellard pstrcat(buf, sizeof(buf), "_1"); 1234120c1084SRichard Henderson ts2->name = strdup(buf); 12357ca4b752SRichard Henderson } else { 1236c896fe29Sbellard ts->base_type = type; 1237c896fe29Sbellard ts->type = type; 1238b3915dbbSRichard Henderson ts->indirect_reg = indirect_reg; 1239c896fe29Sbellard ts->mem_allocated = 1; 1240b3a62939SRichard Henderson ts->mem_base = base_ts; 1241c896fe29Sbellard ts->mem_offset = offset; 1242c896fe29Sbellard ts->name = name; 1243c896fe29Sbellard } 1244085272b3SRichard Henderson return ts; 1245c896fe29Sbellard } 1246c896fe29Sbellard 12475bfa8034SRichard Henderson TCGTemp *tcg_temp_new_internal(TCGType type, bool temp_local) 1248c896fe29Sbellard { 1249b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 1250c896fe29Sbellard TCGTemp *ts; 1251641d5fbeSbellard int idx, k; 1252c896fe29Sbellard 12530ec9eabcSRichard Henderson k = type + (temp_local ? TCG_TYPE_COUNT : 0); 12540ec9eabcSRichard Henderson idx = find_first_bit(s->free_temps[k].l, TCG_MAX_TEMPS); 12550ec9eabcSRichard Henderson if (idx < TCG_MAX_TEMPS) { 12560ec9eabcSRichard Henderson /* There is already an available temp with the right type. */ 12570ec9eabcSRichard Henderson clear_bit(idx, s->free_temps[k].l); 12580ec9eabcSRichard Henderson 1259e8996ee0Sbellard ts = &s->temps[idx]; 1260e8996ee0Sbellard ts->temp_allocated = 1; 12617ca4b752SRichard Henderson tcg_debug_assert(ts->base_type == type); 12627ca4b752SRichard Henderson tcg_debug_assert(ts->temp_local == temp_local); 1263e8996ee0Sbellard } else { 12647ca4b752SRichard Henderson ts = tcg_temp_alloc(s); 12657ca4b752SRichard Henderson if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) { 12667ca4b752SRichard Henderson TCGTemp *ts2 = tcg_temp_alloc(s); 12677ca4b752SRichard Henderson 1268c896fe29Sbellard ts->base_type = type; 1269c896fe29Sbellard ts->type = TCG_TYPE_I32; 1270e8996ee0Sbellard ts->temp_allocated = 1; 1271641d5fbeSbellard ts->temp_local = temp_local; 12727ca4b752SRichard Henderson 12737ca4b752SRichard Henderson tcg_debug_assert(ts2 == ts + 1); 12747ca4b752SRichard Henderson ts2->base_type = TCG_TYPE_I64; 12757ca4b752SRichard Henderson ts2->type = TCG_TYPE_I32; 12767ca4b752SRichard Henderson ts2->temp_allocated = 1; 12777ca4b752SRichard Henderson ts2->temp_local = temp_local; 12787ca4b752SRichard Henderson } else { 1279c896fe29Sbellard ts->base_type = type; 1280c896fe29Sbellard ts->type = type; 1281e8996ee0Sbellard ts->temp_allocated = 1; 1282641d5fbeSbellard ts->temp_local = temp_local; 1283c896fe29Sbellard } 1284e8996ee0Sbellard } 128527bfd83cSPeter Maydell 128627bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG) 128727bfd83cSPeter Maydell s->temps_in_use++; 128827bfd83cSPeter Maydell #endif 1289085272b3SRichard Henderson return ts; 1290c896fe29Sbellard } 1291c896fe29Sbellard 1292d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec(TCGType type) 1293d2fd745fSRichard Henderson { 1294d2fd745fSRichard Henderson TCGTemp *t; 1295d2fd745fSRichard Henderson 1296d2fd745fSRichard Henderson #ifdef CONFIG_DEBUG_TCG 1297d2fd745fSRichard Henderson switch (type) { 1298d2fd745fSRichard Henderson case TCG_TYPE_V64: 1299d2fd745fSRichard Henderson assert(TCG_TARGET_HAS_v64); 1300d2fd745fSRichard Henderson break; 1301d2fd745fSRichard Henderson case TCG_TYPE_V128: 1302d2fd745fSRichard Henderson assert(TCG_TARGET_HAS_v128); 1303d2fd745fSRichard Henderson break; 1304d2fd745fSRichard Henderson case TCG_TYPE_V256: 1305d2fd745fSRichard Henderson assert(TCG_TARGET_HAS_v256); 1306d2fd745fSRichard Henderson break; 1307d2fd745fSRichard Henderson default: 1308d2fd745fSRichard Henderson g_assert_not_reached(); 1309d2fd745fSRichard Henderson } 1310d2fd745fSRichard Henderson #endif 1311d2fd745fSRichard Henderson 1312d2fd745fSRichard Henderson t = tcg_temp_new_internal(type, 0); 1313d2fd745fSRichard Henderson return temp_tcgv_vec(t); 1314d2fd745fSRichard Henderson } 1315d2fd745fSRichard Henderson 1316d2fd745fSRichard Henderson /* Create a new temp of the same type as an existing temp. */ 1317d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec_matching(TCGv_vec match) 1318d2fd745fSRichard Henderson { 1319d2fd745fSRichard Henderson TCGTemp *t = tcgv_vec_temp(match); 1320d2fd745fSRichard Henderson 1321d2fd745fSRichard Henderson tcg_debug_assert(t->temp_allocated != 0); 1322d2fd745fSRichard Henderson 1323d2fd745fSRichard Henderson t = tcg_temp_new_internal(t->base_type, 0); 1324d2fd745fSRichard Henderson return temp_tcgv_vec(t); 1325d2fd745fSRichard Henderson } 1326d2fd745fSRichard Henderson 13275bfa8034SRichard Henderson void tcg_temp_free_internal(TCGTemp *ts) 1328c896fe29Sbellard { 1329b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 1330085272b3SRichard Henderson int k, idx; 1331c896fe29Sbellard 133227bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG) 133327bfd83cSPeter Maydell s->temps_in_use--; 133427bfd83cSPeter Maydell if (s->temps_in_use < 0) { 133527bfd83cSPeter Maydell fprintf(stderr, "More temporaries freed than allocated!\n"); 133627bfd83cSPeter Maydell } 133727bfd83cSPeter Maydell #endif 133827bfd83cSPeter Maydell 1339085272b3SRichard Henderson tcg_debug_assert(ts->temp_global == 0); 1340eabb7b91SAurelien Jarno tcg_debug_assert(ts->temp_allocated != 0); 1341e8996ee0Sbellard ts->temp_allocated = 0; 13420ec9eabcSRichard Henderson 1343085272b3SRichard Henderson idx = temp_idx(ts); 134418d13fa2SAlexander Graf k = ts->base_type + (ts->temp_local ? TCG_TYPE_COUNT : 0); 13450ec9eabcSRichard Henderson set_bit(idx, s->free_temps[k].l); 1346e8996ee0Sbellard } 1347e8996ee0Sbellard 1348a7812ae4Spbrook TCGv_i32 tcg_const_i32(int32_t val) 1349a7812ae4Spbrook { 1350a7812ae4Spbrook TCGv_i32 t0; 1351a7812ae4Spbrook t0 = tcg_temp_new_i32(); 1352e8996ee0Sbellard tcg_gen_movi_i32(t0, val); 1353e8996ee0Sbellard return t0; 1354c896fe29Sbellard } 1355c896fe29Sbellard 1356a7812ae4Spbrook TCGv_i64 tcg_const_i64(int64_t val) 1357c896fe29Sbellard { 1358a7812ae4Spbrook TCGv_i64 t0; 1359a7812ae4Spbrook t0 = tcg_temp_new_i64(); 1360e8996ee0Sbellard tcg_gen_movi_i64(t0, val); 1361e8996ee0Sbellard return t0; 1362c896fe29Sbellard } 1363c896fe29Sbellard 1364a7812ae4Spbrook TCGv_i32 tcg_const_local_i32(int32_t val) 1365bdffd4a9Saurel32 { 1366a7812ae4Spbrook TCGv_i32 t0; 1367a7812ae4Spbrook t0 = tcg_temp_local_new_i32(); 1368bdffd4a9Saurel32 tcg_gen_movi_i32(t0, val); 1369bdffd4a9Saurel32 return t0; 1370bdffd4a9Saurel32 } 1371bdffd4a9Saurel32 1372a7812ae4Spbrook TCGv_i64 tcg_const_local_i64(int64_t val) 1373bdffd4a9Saurel32 { 1374a7812ae4Spbrook TCGv_i64 t0; 1375a7812ae4Spbrook t0 = tcg_temp_local_new_i64(); 1376bdffd4a9Saurel32 tcg_gen_movi_i64(t0, val); 1377bdffd4a9Saurel32 return t0; 1378bdffd4a9Saurel32 } 1379bdffd4a9Saurel32 138027bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG) 138127bfd83cSPeter Maydell void tcg_clear_temp_count(void) 138227bfd83cSPeter Maydell { 1383b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 138427bfd83cSPeter Maydell s->temps_in_use = 0; 138527bfd83cSPeter Maydell } 138627bfd83cSPeter Maydell 138727bfd83cSPeter Maydell int tcg_check_temp_count(void) 138827bfd83cSPeter Maydell { 1389b1311c4aSEmilio G. Cota TCGContext *s = tcg_ctx; 139027bfd83cSPeter Maydell if (s->temps_in_use) { 139127bfd83cSPeter Maydell /* Clear the count so that we don't give another 139227bfd83cSPeter Maydell * warning immediately next time around. 139327bfd83cSPeter Maydell */ 139427bfd83cSPeter Maydell s->temps_in_use = 0; 139527bfd83cSPeter Maydell return 1; 139627bfd83cSPeter Maydell } 139727bfd83cSPeter Maydell return 0; 139827bfd83cSPeter Maydell } 139927bfd83cSPeter Maydell #endif 140027bfd83cSPeter Maydell 1401be0f34b5SRichard Henderson /* Return true if OP may appear in the opcode stream. 1402be0f34b5SRichard Henderson Test the runtime variable that controls each opcode. */ 1403be0f34b5SRichard Henderson bool tcg_op_supported(TCGOpcode op) 1404be0f34b5SRichard Henderson { 1405d2fd745fSRichard Henderson const bool have_vec 1406d2fd745fSRichard Henderson = TCG_TARGET_HAS_v64 | TCG_TARGET_HAS_v128 | TCG_TARGET_HAS_v256; 1407d2fd745fSRichard Henderson 1408be0f34b5SRichard Henderson switch (op) { 1409be0f34b5SRichard Henderson case INDEX_op_discard: 1410be0f34b5SRichard Henderson case INDEX_op_set_label: 1411be0f34b5SRichard Henderson case INDEX_op_call: 1412be0f34b5SRichard Henderson case INDEX_op_br: 1413be0f34b5SRichard Henderson case INDEX_op_mb: 1414be0f34b5SRichard Henderson case INDEX_op_insn_start: 1415be0f34b5SRichard Henderson case INDEX_op_exit_tb: 1416be0f34b5SRichard Henderson case INDEX_op_goto_tb: 1417be0f34b5SRichard Henderson case INDEX_op_qemu_ld_i32: 1418be0f34b5SRichard Henderson case INDEX_op_qemu_st_i32: 1419be0f34b5SRichard Henderson case INDEX_op_qemu_ld_i64: 1420be0f34b5SRichard Henderson case INDEX_op_qemu_st_i64: 1421be0f34b5SRichard Henderson return true; 1422be0f34b5SRichard Henderson 1423be0f34b5SRichard Henderson case INDEX_op_goto_ptr: 1424be0f34b5SRichard Henderson return TCG_TARGET_HAS_goto_ptr; 1425be0f34b5SRichard Henderson 1426be0f34b5SRichard Henderson case INDEX_op_mov_i32: 1427be0f34b5SRichard Henderson case INDEX_op_movi_i32: 1428be0f34b5SRichard Henderson case INDEX_op_setcond_i32: 1429be0f34b5SRichard Henderson case INDEX_op_brcond_i32: 1430be0f34b5SRichard Henderson case INDEX_op_ld8u_i32: 1431be0f34b5SRichard Henderson case INDEX_op_ld8s_i32: 1432be0f34b5SRichard Henderson case INDEX_op_ld16u_i32: 1433be0f34b5SRichard Henderson case INDEX_op_ld16s_i32: 1434be0f34b5SRichard Henderson case INDEX_op_ld_i32: 1435be0f34b5SRichard Henderson case INDEX_op_st8_i32: 1436be0f34b5SRichard Henderson case INDEX_op_st16_i32: 1437be0f34b5SRichard Henderson case INDEX_op_st_i32: 1438be0f34b5SRichard Henderson case INDEX_op_add_i32: 1439be0f34b5SRichard Henderson case INDEX_op_sub_i32: 1440be0f34b5SRichard Henderson case INDEX_op_mul_i32: 1441be0f34b5SRichard Henderson case INDEX_op_and_i32: 1442be0f34b5SRichard Henderson case INDEX_op_or_i32: 1443be0f34b5SRichard Henderson case INDEX_op_xor_i32: 1444be0f34b5SRichard Henderson case INDEX_op_shl_i32: 1445be0f34b5SRichard Henderson case INDEX_op_shr_i32: 1446be0f34b5SRichard Henderson case INDEX_op_sar_i32: 1447be0f34b5SRichard Henderson return true; 1448be0f34b5SRichard Henderson 1449be0f34b5SRichard Henderson case INDEX_op_movcond_i32: 1450be0f34b5SRichard Henderson return TCG_TARGET_HAS_movcond_i32; 1451be0f34b5SRichard Henderson case INDEX_op_div_i32: 1452be0f34b5SRichard Henderson case INDEX_op_divu_i32: 1453be0f34b5SRichard Henderson return TCG_TARGET_HAS_div_i32; 1454be0f34b5SRichard Henderson case INDEX_op_rem_i32: 1455be0f34b5SRichard Henderson case INDEX_op_remu_i32: 1456be0f34b5SRichard Henderson return TCG_TARGET_HAS_rem_i32; 1457be0f34b5SRichard Henderson case INDEX_op_div2_i32: 1458be0f34b5SRichard Henderson case INDEX_op_divu2_i32: 1459be0f34b5SRichard Henderson return TCG_TARGET_HAS_div2_i32; 1460be0f34b5SRichard Henderson case INDEX_op_rotl_i32: 1461be0f34b5SRichard Henderson case INDEX_op_rotr_i32: 1462be0f34b5SRichard Henderson return TCG_TARGET_HAS_rot_i32; 1463be0f34b5SRichard Henderson case INDEX_op_deposit_i32: 1464be0f34b5SRichard Henderson return TCG_TARGET_HAS_deposit_i32; 1465be0f34b5SRichard Henderson case INDEX_op_extract_i32: 1466be0f34b5SRichard Henderson return TCG_TARGET_HAS_extract_i32; 1467be0f34b5SRichard Henderson case INDEX_op_sextract_i32: 1468be0f34b5SRichard Henderson return TCG_TARGET_HAS_sextract_i32; 1469fce1296fSRichard Henderson case INDEX_op_extract2_i32: 1470fce1296fSRichard Henderson return TCG_TARGET_HAS_extract2_i32; 1471be0f34b5SRichard Henderson case INDEX_op_add2_i32: 1472be0f34b5SRichard Henderson return TCG_TARGET_HAS_add2_i32; 1473be0f34b5SRichard Henderson case INDEX_op_sub2_i32: 1474be0f34b5SRichard Henderson return TCG_TARGET_HAS_sub2_i32; 1475be0f34b5SRichard Henderson case INDEX_op_mulu2_i32: 1476be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulu2_i32; 1477be0f34b5SRichard Henderson case INDEX_op_muls2_i32: 1478be0f34b5SRichard Henderson return TCG_TARGET_HAS_muls2_i32; 1479be0f34b5SRichard Henderson case INDEX_op_muluh_i32: 1480be0f34b5SRichard Henderson return TCG_TARGET_HAS_muluh_i32; 1481be0f34b5SRichard Henderson case INDEX_op_mulsh_i32: 1482be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulsh_i32; 1483be0f34b5SRichard Henderson case INDEX_op_ext8s_i32: 1484be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8s_i32; 1485be0f34b5SRichard Henderson case INDEX_op_ext16s_i32: 1486be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16s_i32; 1487be0f34b5SRichard Henderson case INDEX_op_ext8u_i32: 1488be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8u_i32; 1489be0f34b5SRichard Henderson case INDEX_op_ext16u_i32: 1490be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16u_i32; 1491be0f34b5SRichard Henderson case INDEX_op_bswap16_i32: 1492be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap16_i32; 1493be0f34b5SRichard Henderson case INDEX_op_bswap32_i32: 1494be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap32_i32; 1495be0f34b5SRichard Henderson case INDEX_op_not_i32: 1496be0f34b5SRichard Henderson return TCG_TARGET_HAS_not_i32; 1497be0f34b5SRichard Henderson case INDEX_op_neg_i32: 1498be0f34b5SRichard Henderson return TCG_TARGET_HAS_neg_i32; 1499be0f34b5SRichard Henderson case INDEX_op_andc_i32: 1500be0f34b5SRichard Henderson return TCG_TARGET_HAS_andc_i32; 1501be0f34b5SRichard Henderson case INDEX_op_orc_i32: 1502be0f34b5SRichard Henderson return TCG_TARGET_HAS_orc_i32; 1503be0f34b5SRichard Henderson case INDEX_op_eqv_i32: 1504be0f34b5SRichard Henderson return TCG_TARGET_HAS_eqv_i32; 1505be0f34b5SRichard Henderson case INDEX_op_nand_i32: 1506be0f34b5SRichard Henderson return TCG_TARGET_HAS_nand_i32; 1507be0f34b5SRichard Henderson case INDEX_op_nor_i32: 1508be0f34b5SRichard Henderson return TCG_TARGET_HAS_nor_i32; 1509be0f34b5SRichard Henderson case INDEX_op_clz_i32: 1510be0f34b5SRichard Henderson return TCG_TARGET_HAS_clz_i32; 1511be0f34b5SRichard Henderson case INDEX_op_ctz_i32: 1512be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctz_i32; 1513be0f34b5SRichard Henderson case INDEX_op_ctpop_i32: 1514be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctpop_i32; 1515be0f34b5SRichard Henderson 1516be0f34b5SRichard Henderson case INDEX_op_brcond2_i32: 1517be0f34b5SRichard Henderson case INDEX_op_setcond2_i32: 1518be0f34b5SRichard Henderson return TCG_TARGET_REG_BITS == 32; 1519be0f34b5SRichard Henderson 1520be0f34b5SRichard Henderson case INDEX_op_mov_i64: 1521be0f34b5SRichard Henderson case INDEX_op_movi_i64: 1522be0f34b5SRichard Henderson case INDEX_op_setcond_i64: 1523be0f34b5SRichard Henderson case INDEX_op_brcond_i64: 1524be0f34b5SRichard Henderson case INDEX_op_ld8u_i64: 1525be0f34b5SRichard Henderson case INDEX_op_ld8s_i64: 1526be0f34b5SRichard Henderson case INDEX_op_ld16u_i64: 1527be0f34b5SRichard Henderson case INDEX_op_ld16s_i64: 1528be0f34b5SRichard Henderson case INDEX_op_ld32u_i64: 1529be0f34b5SRichard Henderson case INDEX_op_ld32s_i64: 1530be0f34b5SRichard Henderson case INDEX_op_ld_i64: 1531be0f34b5SRichard Henderson case INDEX_op_st8_i64: 1532be0f34b5SRichard Henderson case INDEX_op_st16_i64: 1533be0f34b5SRichard Henderson case INDEX_op_st32_i64: 1534be0f34b5SRichard Henderson case INDEX_op_st_i64: 1535be0f34b5SRichard Henderson case INDEX_op_add_i64: 1536be0f34b5SRichard Henderson case INDEX_op_sub_i64: 1537be0f34b5SRichard Henderson case INDEX_op_mul_i64: 1538be0f34b5SRichard Henderson case INDEX_op_and_i64: 1539be0f34b5SRichard Henderson case INDEX_op_or_i64: 1540be0f34b5SRichard Henderson case INDEX_op_xor_i64: 1541be0f34b5SRichard Henderson case INDEX_op_shl_i64: 1542be0f34b5SRichard Henderson case INDEX_op_shr_i64: 1543be0f34b5SRichard Henderson case INDEX_op_sar_i64: 1544be0f34b5SRichard Henderson case INDEX_op_ext_i32_i64: 1545be0f34b5SRichard Henderson case INDEX_op_extu_i32_i64: 1546be0f34b5SRichard Henderson return TCG_TARGET_REG_BITS == 64; 1547be0f34b5SRichard Henderson 1548be0f34b5SRichard Henderson case INDEX_op_movcond_i64: 1549be0f34b5SRichard Henderson return TCG_TARGET_HAS_movcond_i64; 1550be0f34b5SRichard Henderson case INDEX_op_div_i64: 1551be0f34b5SRichard Henderson case INDEX_op_divu_i64: 1552be0f34b5SRichard Henderson return TCG_TARGET_HAS_div_i64; 1553be0f34b5SRichard Henderson case INDEX_op_rem_i64: 1554be0f34b5SRichard Henderson case INDEX_op_remu_i64: 1555be0f34b5SRichard Henderson return TCG_TARGET_HAS_rem_i64; 1556be0f34b5SRichard Henderson case INDEX_op_div2_i64: 1557be0f34b5SRichard Henderson case INDEX_op_divu2_i64: 1558be0f34b5SRichard Henderson return TCG_TARGET_HAS_div2_i64; 1559be0f34b5SRichard Henderson case INDEX_op_rotl_i64: 1560be0f34b5SRichard Henderson case INDEX_op_rotr_i64: 1561be0f34b5SRichard Henderson return TCG_TARGET_HAS_rot_i64; 1562be0f34b5SRichard Henderson case INDEX_op_deposit_i64: 1563be0f34b5SRichard Henderson return TCG_TARGET_HAS_deposit_i64; 1564be0f34b5SRichard Henderson case INDEX_op_extract_i64: 1565be0f34b5SRichard Henderson return TCG_TARGET_HAS_extract_i64; 1566be0f34b5SRichard Henderson case INDEX_op_sextract_i64: 1567be0f34b5SRichard Henderson return TCG_TARGET_HAS_sextract_i64; 1568fce1296fSRichard Henderson case INDEX_op_extract2_i64: 1569fce1296fSRichard Henderson return TCG_TARGET_HAS_extract2_i64; 1570be0f34b5SRichard Henderson case INDEX_op_extrl_i64_i32: 1571be0f34b5SRichard Henderson return TCG_TARGET_HAS_extrl_i64_i32; 1572be0f34b5SRichard Henderson case INDEX_op_extrh_i64_i32: 1573be0f34b5SRichard Henderson return TCG_TARGET_HAS_extrh_i64_i32; 1574be0f34b5SRichard Henderson case INDEX_op_ext8s_i64: 1575be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8s_i64; 1576be0f34b5SRichard Henderson case INDEX_op_ext16s_i64: 1577be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16s_i64; 1578be0f34b5SRichard Henderson case INDEX_op_ext32s_i64: 1579be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext32s_i64; 1580be0f34b5SRichard Henderson case INDEX_op_ext8u_i64: 1581be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext8u_i64; 1582be0f34b5SRichard Henderson case INDEX_op_ext16u_i64: 1583be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext16u_i64; 1584be0f34b5SRichard Henderson case INDEX_op_ext32u_i64: 1585be0f34b5SRichard Henderson return TCG_TARGET_HAS_ext32u_i64; 1586be0f34b5SRichard Henderson case INDEX_op_bswap16_i64: 1587be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap16_i64; 1588be0f34b5SRichard Henderson case INDEX_op_bswap32_i64: 1589be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap32_i64; 1590be0f34b5SRichard Henderson case INDEX_op_bswap64_i64: 1591be0f34b5SRichard Henderson return TCG_TARGET_HAS_bswap64_i64; 1592be0f34b5SRichard Henderson case INDEX_op_not_i64: 1593be0f34b5SRichard Henderson return TCG_TARGET_HAS_not_i64; 1594be0f34b5SRichard Henderson case INDEX_op_neg_i64: 1595be0f34b5SRichard Henderson return TCG_TARGET_HAS_neg_i64; 1596be0f34b5SRichard Henderson case INDEX_op_andc_i64: 1597be0f34b5SRichard Henderson return TCG_TARGET_HAS_andc_i64; 1598be0f34b5SRichard Henderson case INDEX_op_orc_i64: 1599be0f34b5SRichard Henderson return TCG_TARGET_HAS_orc_i64; 1600be0f34b5SRichard Henderson case INDEX_op_eqv_i64: 1601be0f34b5SRichard Henderson return TCG_TARGET_HAS_eqv_i64; 1602be0f34b5SRichard Henderson case INDEX_op_nand_i64: 1603be0f34b5SRichard Henderson return TCG_TARGET_HAS_nand_i64; 1604be0f34b5SRichard Henderson case INDEX_op_nor_i64: 1605be0f34b5SRichard Henderson return TCG_TARGET_HAS_nor_i64; 1606be0f34b5SRichard Henderson case INDEX_op_clz_i64: 1607be0f34b5SRichard Henderson return TCG_TARGET_HAS_clz_i64; 1608be0f34b5SRichard Henderson case INDEX_op_ctz_i64: 1609be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctz_i64; 1610be0f34b5SRichard Henderson case INDEX_op_ctpop_i64: 1611be0f34b5SRichard Henderson return TCG_TARGET_HAS_ctpop_i64; 1612be0f34b5SRichard Henderson case INDEX_op_add2_i64: 1613be0f34b5SRichard Henderson return TCG_TARGET_HAS_add2_i64; 1614be0f34b5SRichard Henderson case INDEX_op_sub2_i64: 1615be0f34b5SRichard Henderson return TCG_TARGET_HAS_sub2_i64; 1616be0f34b5SRichard Henderson case INDEX_op_mulu2_i64: 1617be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulu2_i64; 1618be0f34b5SRichard Henderson case INDEX_op_muls2_i64: 1619be0f34b5SRichard Henderson return TCG_TARGET_HAS_muls2_i64; 1620be0f34b5SRichard Henderson case INDEX_op_muluh_i64: 1621be0f34b5SRichard Henderson return TCG_TARGET_HAS_muluh_i64; 1622be0f34b5SRichard Henderson case INDEX_op_mulsh_i64: 1623be0f34b5SRichard Henderson return TCG_TARGET_HAS_mulsh_i64; 1624be0f34b5SRichard Henderson 1625d2fd745fSRichard Henderson case INDEX_op_mov_vec: 1626d2fd745fSRichard Henderson case INDEX_op_dup_vec: 1627d2fd745fSRichard Henderson case INDEX_op_dupi_vec: 162837ee55a0SRichard Henderson case INDEX_op_dupm_vec: 1629d2fd745fSRichard Henderson case INDEX_op_ld_vec: 1630d2fd745fSRichard Henderson case INDEX_op_st_vec: 1631d2fd745fSRichard Henderson case INDEX_op_add_vec: 1632d2fd745fSRichard Henderson case INDEX_op_sub_vec: 1633d2fd745fSRichard Henderson case INDEX_op_and_vec: 1634d2fd745fSRichard Henderson case INDEX_op_or_vec: 1635d2fd745fSRichard Henderson case INDEX_op_xor_vec: 1636212be173SRichard Henderson case INDEX_op_cmp_vec: 1637d2fd745fSRichard Henderson return have_vec; 1638d2fd745fSRichard Henderson case INDEX_op_dup2_vec: 1639d2fd745fSRichard Henderson return have_vec && TCG_TARGET_REG_BITS == 32; 1640d2fd745fSRichard Henderson case INDEX_op_not_vec: 1641d2fd745fSRichard Henderson return have_vec && TCG_TARGET_HAS_not_vec; 1642d2fd745fSRichard Henderson case INDEX_op_neg_vec: 1643d2fd745fSRichard Henderson return have_vec && TCG_TARGET_HAS_neg_vec; 1644bcefc902SRichard Henderson case INDEX_op_abs_vec: 1645bcefc902SRichard Henderson return have_vec && TCG_TARGET_HAS_abs_vec; 1646d2fd745fSRichard Henderson case INDEX_op_andc_vec: 1647d2fd745fSRichard Henderson return have_vec && TCG_TARGET_HAS_andc_vec; 1648d2fd745fSRichard Henderson case INDEX_op_orc_vec: 1649d2fd745fSRichard Henderson return have_vec && TCG_TARGET_HAS_orc_vec; 16503774030aSRichard Henderson case INDEX_op_mul_vec: 16513774030aSRichard Henderson return have_vec && TCG_TARGET_HAS_mul_vec; 1652d0ec9796SRichard Henderson case INDEX_op_shli_vec: 1653d0ec9796SRichard Henderson case INDEX_op_shri_vec: 1654d0ec9796SRichard Henderson case INDEX_op_sari_vec: 1655d0ec9796SRichard Henderson return have_vec && TCG_TARGET_HAS_shi_vec; 1656d0ec9796SRichard Henderson case INDEX_op_shls_vec: 1657d0ec9796SRichard Henderson case INDEX_op_shrs_vec: 1658d0ec9796SRichard Henderson case INDEX_op_sars_vec: 1659d0ec9796SRichard Henderson return have_vec && TCG_TARGET_HAS_shs_vec; 1660d0ec9796SRichard Henderson case INDEX_op_shlv_vec: 1661d0ec9796SRichard Henderson case INDEX_op_shrv_vec: 1662d0ec9796SRichard Henderson case INDEX_op_sarv_vec: 1663d0ec9796SRichard Henderson return have_vec && TCG_TARGET_HAS_shv_vec; 16648afaf050SRichard Henderson case INDEX_op_ssadd_vec: 16658afaf050SRichard Henderson case INDEX_op_usadd_vec: 16668afaf050SRichard Henderson case INDEX_op_sssub_vec: 16678afaf050SRichard Henderson case INDEX_op_ussub_vec: 16688afaf050SRichard Henderson return have_vec && TCG_TARGET_HAS_sat_vec; 1669dd0a0fcdSRichard Henderson case INDEX_op_smin_vec: 1670dd0a0fcdSRichard Henderson case INDEX_op_umin_vec: 1671dd0a0fcdSRichard Henderson case INDEX_op_smax_vec: 1672dd0a0fcdSRichard Henderson case INDEX_op_umax_vec: 1673dd0a0fcdSRichard Henderson return have_vec && TCG_TARGET_HAS_minmax_vec; 167438dc1294SRichard Henderson case INDEX_op_bitsel_vec: 167538dc1294SRichard Henderson return have_vec && TCG_TARGET_HAS_bitsel_vec; 1676f75da298SRichard Henderson case INDEX_op_cmpsel_vec: 1677f75da298SRichard Henderson return have_vec && TCG_TARGET_HAS_cmpsel_vec; 1678d2fd745fSRichard Henderson 1679db432672SRichard Henderson default: 1680db432672SRichard Henderson tcg_debug_assert(op > INDEX_op_last_generic && op < NB_OPS); 1681db432672SRichard Henderson return true; 1682be0f34b5SRichard Henderson } 1683be0f34b5SRichard Henderson } 1684be0f34b5SRichard Henderson 168539cf05d3Sbellard /* Note: we convert the 64 bit args to 32 bit and do some alignment 168639cf05d3Sbellard and endian swap. Maybe it would be better to do the alignment 168739cf05d3Sbellard and endian swap in tcg_reg_alloc_call(). */ 1688ae8b75dcSRichard Henderson void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args) 1689c896fe29Sbellard { 169075e8b9b7SRichard Henderson int i, real_args, nb_rets, pi; 1691bbb8a1b4SRichard Henderson unsigned sizemask, flags; 1692afb49896SRichard Henderson TCGHelperInfo *info; 169375e8b9b7SRichard Henderson TCGOp *op; 1694afb49896SRichard Henderson 1695619205fdSEmilio G. Cota info = g_hash_table_lookup(helper_table, (gpointer)func); 1696bbb8a1b4SRichard Henderson flags = info->flags; 1697bbb8a1b4SRichard Henderson sizemask = info->sizemask; 16982bece2c8SRichard Henderson 169938b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN 170038b47b19SEmilio G. Cota /* detect non-plugin helpers */ 170138b47b19SEmilio G. Cota if (tcg_ctx->plugin_insn && unlikely(strncmp(info->name, "plugin_", 7))) { 170238b47b19SEmilio G. Cota tcg_ctx->plugin_insn->calls_helpers = true; 170338b47b19SEmilio G. Cota } 170438b47b19SEmilio G. Cota #endif 170538b47b19SEmilio G. Cota 170634b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \ 170734b1a49cSRichard Henderson && !defined(CONFIG_TCG_INTERPRETER) 170834b1a49cSRichard Henderson /* We have 64-bit values in one register, but need to pass as two 170934b1a49cSRichard Henderson separate parameters. Split them. */ 171034b1a49cSRichard Henderson int orig_sizemask = sizemask; 171134b1a49cSRichard Henderson int orig_nargs = nargs; 171234b1a49cSRichard Henderson TCGv_i64 retl, reth; 1713ae8b75dcSRichard Henderson TCGTemp *split_args[MAX_OPC_PARAM]; 171434b1a49cSRichard Henderson 1715f764718dSRichard Henderson retl = NULL; 1716f764718dSRichard Henderson reth = NULL; 171734b1a49cSRichard Henderson if (sizemask != 0) { 171834b1a49cSRichard Henderson for (i = real_args = 0; i < nargs; ++i) { 171934b1a49cSRichard Henderson int is_64bit = sizemask & (1 << (i+1)*2); 172034b1a49cSRichard Henderson if (is_64bit) { 1721085272b3SRichard Henderson TCGv_i64 orig = temp_tcgv_i64(args[i]); 172234b1a49cSRichard Henderson TCGv_i32 h = tcg_temp_new_i32(); 172334b1a49cSRichard Henderson TCGv_i32 l = tcg_temp_new_i32(); 172434b1a49cSRichard Henderson tcg_gen_extr_i64_i32(l, h, orig); 1725ae8b75dcSRichard Henderson split_args[real_args++] = tcgv_i32_temp(h); 1726ae8b75dcSRichard Henderson split_args[real_args++] = tcgv_i32_temp(l); 172734b1a49cSRichard Henderson } else { 172834b1a49cSRichard Henderson split_args[real_args++] = args[i]; 172934b1a49cSRichard Henderson } 173034b1a49cSRichard Henderson } 173134b1a49cSRichard Henderson nargs = real_args; 173234b1a49cSRichard Henderson args = split_args; 173334b1a49cSRichard Henderson sizemask = 0; 173434b1a49cSRichard Henderson } 173534b1a49cSRichard Henderson #elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64 17362bece2c8SRichard Henderson for (i = 0; i < nargs; ++i) { 17372bece2c8SRichard Henderson int is_64bit = sizemask & (1 << (i+1)*2); 17382bece2c8SRichard Henderson int is_signed = sizemask & (2 << (i+1)*2); 17392bece2c8SRichard Henderson if (!is_64bit) { 17402bece2c8SRichard Henderson TCGv_i64 temp = tcg_temp_new_i64(); 1741085272b3SRichard Henderson TCGv_i64 orig = temp_tcgv_i64(args[i]); 17422bece2c8SRichard Henderson if (is_signed) { 17432bece2c8SRichard Henderson tcg_gen_ext32s_i64(temp, orig); 17442bece2c8SRichard Henderson } else { 17452bece2c8SRichard Henderson tcg_gen_ext32u_i64(temp, orig); 17462bece2c8SRichard Henderson } 1747ae8b75dcSRichard Henderson args[i] = tcgv_i64_temp(temp); 17482bece2c8SRichard Henderson } 17492bece2c8SRichard Henderson } 17502bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */ 17512bece2c8SRichard Henderson 175215fa08f8SRichard Henderson op = tcg_emit_op(INDEX_op_call); 175375e8b9b7SRichard Henderson 175475e8b9b7SRichard Henderson pi = 0; 1755ae8b75dcSRichard Henderson if (ret != NULL) { 175634b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \ 175734b1a49cSRichard Henderson && !defined(CONFIG_TCG_INTERPRETER) 175834b1a49cSRichard Henderson if (orig_sizemask & 1) { 175934b1a49cSRichard Henderson /* The 32-bit ABI is going to return the 64-bit value in 176034b1a49cSRichard Henderson the %o0/%o1 register pair. Prepare for this by using 176134b1a49cSRichard Henderson two return temporaries, and reassemble below. */ 176234b1a49cSRichard Henderson retl = tcg_temp_new_i64(); 176334b1a49cSRichard Henderson reth = tcg_temp_new_i64(); 1764ae8b75dcSRichard Henderson op->args[pi++] = tcgv_i64_arg(reth); 1765ae8b75dcSRichard Henderson op->args[pi++] = tcgv_i64_arg(retl); 176634b1a49cSRichard Henderson nb_rets = 2; 176734b1a49cSRichard Henderson } else { 1768ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(ret); 176934b1a49cSRichard Henderson nb_rets = 1; 177034b1a49cSRichard Henderson } 177134b1a49cSRichard Henderson #else 177234b1a49cSRichard Henderson if (TCG_TARGET_REG_BITS < 64 && (sizemask & 1)) { 177302eb19d0SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN 1774ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(ret + 1); 1775ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(ret); 1776a7812ae4Spbrook #else 1777ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(ret); 1778ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(ret + 1); 1779a7812ae4Spbrook #endif 1780a7812ae4Spbrook nb_rets = 2; 178134b1a49cSRichard Henderson } else { 1782ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(ret); 1783a7812ae4Spbrook nb_rets = 1; 1784a7812ae4Spbrook } 178534b1a49cSRichard Henderson #endif 1786a7812ae4Spbrook } else { 1787a7812ae4Spbrook nb_rets = 0; 1788a7812ae4Spbrook } 1789cd9090aaSRichard Henderson TCGOP_CALLO(op) = nb_rets; 179075e8b9b7SRichard Henderson 1791a7812ae4Spbrook real_args = 0; 1792a7812ae4Spbrook for (i = 0; i < nargs; i++) { 17932bece2c8SRichard Henderson int is_64bit = sizemask & (1 << (i+1)*2); 1794bbb8a1b4SRichard Henderson if (TCG_TARGET_REG_BITS < 64 && is_64bit) { 179539cf05d3Sbellard #ifdef TCG_TARGET_CALL_ALIGN_ARGS 179639cf05d3Sbellard /* some targets want aligned 64 bit args */ 1797ebd486d5Smalc if (real_args & 1) { 179875e8b9b7SRichard Henderson op->args[pi++] = TCG_CALL_DUMMY_ARG; 1799ebd486d5Smalc real_args++; 180039cf05d3Sbellard } 180139cf05d3Sbellard #endif 18023f90f252SRichard Henderson /* If stack grows up, then we will be placing successive 18033f90f252SRichard Henderson arguments at lower addresses, which means we need to 18043f90f252SRichard Henderson reverse the order compared to how we would normally 18053f90f252SRichard Henderson treat either big or little-endian. For those arguments 18063f90f252SRichard Henderson that will wind up in registers, this still works for 18073f90f252SRichard Henderson HPPA (the only current STACK_GROWSUP target) since the 18083f90f252SRichard Henderson argument registers are *also* allocated in decreasing 18093f90f252SRichard Henderson order. If another such target is added, this logic may 18103f90f252SRichard Henderson have to get more complicated to differentiate between 18113f90f252SRichard Henderson stack arguments and register arguments. */ 181202eb19d0SRichard Henderson #if defined(HOST_WORDS_BIGENDIAN) != defined(TCG_TARGET_STACK_GROWSUP) 1813ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(args[i] + 1); 1814ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(args[i]); 1815c896fe29Sbellard #else 1816ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(args[i]); 1817ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(args[i] + 1); 1818c896fe29Sbellard #endif 1819a7812ae4Spbrook real_args += 2; 18202bece2c8SRichard Henderson continue; 18212bece2c8SRichard Henderson } 18222bece2c8SRichard Henderson 1823ae8b75dcSRichard Henderson op->args[pi++] = temp_arg(args[i]); 1824a7812ae4Spbrook real_args++; 1825c896fe29Sbellard } 182675e8b9b7SRichard Henderson op->args[pi++] = (uintptr_t)func; 182775e8b9b7SRichard Henderson op->args[pi++] = flags; 1828cd9090aaSRichard Henderson TCGOP_CALLI(op) = real_args; 1829a7812ae4Spbrook 183075e8b9b7SRichard Henderson /* Make sure the fields didn't overflow. */ 1831cd9090aaSRichard Henderson tcg_debug_assert(TCGOP_CALLI(op) == real_args); 183275e8b9b7SRichard Henderson tcg_debug_assert(pi <= ARRAY_SIZE(op->args)); 18332bece2c8SRichard Henderson 183434b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \ 183534b1a49cSRichard Henderson && !defined(CONFIG_TCG_INTERPRETER) 183634b1a49cSRichard Henderson /* Free all of the parts we allocated above. */ 183734b1a49cSRichard Henderson for (i = real_args = 0; i < orig_nargs; ++i) { 183834b1a49cSRichard Henderson int is_64bit = orig_sizemask & (1 << (i+1)*2); 183934b1a49cSRichard Henderson if (is_64bit) { 1840085272b3SRichard Henderson tcg_temp_free_internal(args[real_args++]); 1841085272b3SRichard Henderson tcg_temp_free_internal(args[real_args++]); 184234b1a49cSRichard Henderson } else { 184334b1a49cSRichard Henderson real_args++; 184434b1a49cSRichard Henderson } 184534b1a49cSRichard Henderson } 184634b1a49cSRichard Henderson if (orig_sizemask & 1) { 184734b1a49cSRichard Henderson /* The 32-bit ABI returned two 32-bit pieces. Re-assemble them. 184834b1a49cSRichard Henderson Note that describing these as TCGv_i64 eliminates an unnecessary 184934b1a49cSRichard Henderson zero-extension that tcg_gen_concat_i32_i64 would create. */ 1850085272b3SRichard Henderson tcg_gen_concat32_i64(temp_tcgv_i64(ret), retl, reth); 185134b1a49cSRichard Henderson tcg_temp_free_i64(retl); 185234b1a49cSRichard Henderson tcg_temp_free_i64(reth); 185334b1a49cSRichard Henderson } 185434b1a49cSRichard Henderson #elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64 18552bece2c8SRichard Henderson for (i = 0; i < nargs; ++i) { 18562bece2c8SRichard Henderson int is_64bit = sizemask & (1 << (i+1)*2); 18572bece2c8SRichard Henderson if (!is_64bit) { 1858085272b3SRichard Henderson tcg_temp_free_internal(args[i]); 18592bece2c8SRichard Henderson } 18602bece2c8SRichard Henderson } 18612bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */ 1862a7812ae4Spbrook } 1863c896fe29Sbellard 18648fcd3692Sblueswir1 static void tcg_reg_alloc_start(TCGContext *s) 1865c896fe29Sbellard { 1866ac3b8891SRichard Henderson int i, n; 1867c896fe29Sbellard TCGTemp *ts; 1868ac3b8891SRichard Henderson 1869ac3b8891SRichard Henderson for (i = 0, n = s->nb_globals; i < n; i++) { 1870c896fe29Sbellard ts = &s->temps[i]; 1871ac3b8891SRichard Henderson ts->val_type = (ts->fixed_reg ? TEMP_VAL_REG : TEMP_VAL_MEM); 1872c896fe29Sbellard } 1873ac3b8891SRichard Henderson for (n = s->nb_temps; i < n; i++) { 1874e8996ee0Sbellard ts = &s->temps[i]; 1875ac3b8891SRichard Henderson ts->val_type = (ts->temp_local ? TEMP_VAL_MEM : TEMP_VAL_DEAD); 1876e8996ee0Sbellard ts->mem_allocated = 0; 1877e8996ee0Sbellard ts->fixed_reg = 0; 1878e8996ee0Sbellard } 1879f8b2f202SRichard Henderson 1880f8b2f202SRichard Henderson memset(s->reg_to_temp, 0, sizeof(s->reg_to_temp)); 1881c896fe29Sbellard } 1882c896fe29Sbellard 1883f8b2f202SRichard Henderson static char *tcg_get_arg_str_ptr(TCGContext *s, char *buf, int buf_size, 1884f8b2f202SRichard Henderson TCGTemp *ts) 1885c896fe29Sbellard { 18861807f4c4SRichard Henderson int idx = temp_idx(ts); 1887ac56dd48Spbrook 1888fa477d25SRichard Henderson if (ts->temp_global) { 1889ac56dd48Spbrook pstrcpy(buf, buf_size, ts->name); 1890f8b2f202SRichard Henderson } else if (ts->temp_local) { 1891641d5fbeSbellard snprintf(buf, buf_size, "loc%d", idx - s->nb_globals); 1892f8b2f202SRichard Henderson } else { 1893ac56dd48Spbrook snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals); 1894c896fe29Sbellard } 1895c896fe29Sbellard return buf; 1896c896fe29Sbellard } 1897c896fe29Sbellard 189843439139SRichard Henderson static char *tcg_get_arg_str(TCGContext *s, char *buf, 189943439139SRichard Henderson int buf_size, TCGArg arg) 1900f8b2f202SRichard Henderson { 190143439139SRichard Henderson return tcg_get_arg_str_ptr(s, buf, buf_size, arg_temp(arg)); 1902f8b2f202SRichard Henderson } 1903f8b2f202SRichard Henderson 19046e085f72SRichard Henderson /* Find helper name. */ 19056e085f72SRichard Henderson static inline const char *tcg_find_helper(TCGContext *s, uintptr_t val) 1906e8996ee0Sbellard { 19076e085f72SRichard Henderson const char *ret = NULL; 1908619205fdSEmilio G. Cota if (helper_table) { 1909619205fdSEmilio G. Cota TCGHelperInfo *info = g_hash_table_lookup(helper_table, (gpointer)val); 191072866e82SRichard Henderson if (info) { 191172866e82SRichard Henderson ret = info->name; 191272866e82SRichard Henderson } 1913e8996ee0Sbellard } 19146e085f72SRichard Henderson return ret; 19154dc81f28Sbellard } 19164dc81f28Sbellard 1917f48f3edeSblueswir1 static const char * const cond_name[] = 1918f48f3edeSblueswir1 { 19190aed257fSRichard Henderson [TCG_COND_NEVER] = "never", 19200aed257fSRichard Henderson [TCG_COND_ALWAYS] = "always", 1921f48f3edeSblueswir1 [TCG_COND_EQ] = "eq", 1922f48f3edeSblueswir1 [TCG_COND_NE] = "ne", 1923f48f3edeSblueswir1 [TCG_COND_LT] = "lt", 1924f48f3edeSblueswir1 [TCG_COND_GE] = "ge", 1925f48f3edeSblueswir1 [TCG_COND_LE] = "le", 1926f48f3edeSblueswir1 [TCG_COND_GT] = "gt", 1927f48f3edeSblueswir1 [TCG_COND_LTU] = "ltu", 1928f48f3edeSblueswir1 [TCG_COND_GEU] = "geu", 1929f48f3edeSblueswir1 [TCG_COND_LEU] = "leu", 1930f48f3edeSblueswir1 [TCG_COND_GTU] = "gtu" 1931f48f3edeSblueswir1 }; 1932f48f3edeSblueswir1 1933f713d6adSRichard Henderson static const char * const ldst_name[] = 1934f713d6adSRichard Henderson { 1935f713d6adSRichard Henderson [MO_UB] = "ub", 1936f713d6adSRichard Henderson [MO_SB] = "sb", 1937f713d6adSRichard Henderson [MO_LEUW] = "leuw", 1938f713d6adSRichard Henderson [MO_LESW] = "lesw", 1939f713d6adSRichard Henderson [MO_LEUL] = "leul", 1940f713d6adSRichard Henderson [MO_LESL] = "lesl", 1941f713d6adSRichard Henderson [MO_LEQ] = "leq", 1942f713d6adSRichard Henderson [MO_BEUW] = "beuw", 1943f713d6adSRichard Henderson [MO_BESW] = "besw", 1944f713d6adSRichard Henderson [MO_BEUL] = "beul", 1945f713d6adSRichard Henderson [MO_BESL] = "besl", 1946f713d6adSRichard Henderson [MO_BEQ] = "beq", 1947f713d6adSRichard Henderson }; 1948f713d6adSRichard Henderson 19491f00b27fSSergey Sorokin static const char * const alignment_name[(MO_AMASK >> MO_ASHIFT) + 1] = { 195052bf9771Stony.nguyen@bt.com #ifdef TARGET_ALIGNED_ONLY 19511f00b27fSSergey Sorokin [MO_UNALN >> MO_ASHIFT] = "un+", 19521f00b27fSSergey Sorokin [MO_ALIGN >> MO_ASHIFT] = "", 19531f00b27fSSergey Sorokin #else 19541f00b27fSSergey Sorokin [MO_UNALN >> MO_ASHIFT] = "", 19551f00b27fSSergey Sorokin [MO_ALIGN >> MO_ASHIFT] = "al+", 19561f00b27fSSergey Sorokin #endif 19571f00b27fSSergey Sorokin [MO_ALIGN_2 >> MO_ASHIFT] = "al2+", 19581f00b27fSSergey Sorokin [MO_ALIGN_4 >> MO_ASHIFT] = "al4+", 19591f00b27fSSergey Sorokin [MO_ALIGN_8 >> MO_ASHIFT] = "al8+", 19601f00b27fSSergey Sorokin [MO_ALIGN_16 >> MO_ASHIFT] = "al16+", 19611f00b27fSSergey Sorokin [MO_ALIGN_32 >> MO_ASHIFT] = "al32+", 19621f00b27fSSergey Sorokin [MO_ALIGN_64 >> MO_ASHIFT] = "al64+", 19631f00b27fSSergey Sorokin }; 19641f00b27fSSergey Sorokin 1965b016486eSRichard Henderson static inline bool tcg_regset_single(TCGRegSet d) 1966b016486eSRichard Henderson { 1967b016486eSRichard Henderson return (d & (d - 1)) == 0; 1968b016486eSRichard Henderson } 1969b016486eSRichard Henderson 1970b016486eSRichard Henderson static inline TCGReg tcg_regset_first(TCGRegSet d) 1971b016486eSRichard Henderson { 1972b016486eSRichard Henderson if (TCG_TARGET_NB_REGS <= 32) { 1973b016486eSRichard Henderson return ctz32(d); 1974b016486eSRichard Henderson } else { 1975b016486eSRichard Henderson return ctz64(d); 1976b016486eSRichard Henderson } 1977b016486eSRichard Henderson } 1978b016486eSRichard Henderson 19791894f69aSRichard Henderson static void tcg_dump_ops(TCGContext *s, bool have_prefs) 1980c896fe29Sbellard { 1981c896fe29Sbellard char buf[128]; 1982c45cb8bbSRichard Henderson TCGOp *op; 1983c896fe29Sbellard 198415fa08f8SRichard Henderson QTAILQ_FOREACH(op, &s->ops, link) { 1985c45cb8bbSRichard Henderson int i, k, nb_oargs, nb_iargs, nb_cargs; 1986c45cb8bbSRichard Henderson const TCGOpDef *def; 1987c45cb8bbSRichard Henderson TCGOpcode c; 1988bdfb460eSRichard Henderson int col = 0; 1989c45cb8bbSRichard Henderson 1990c45cb8bbSRichard Henderson c = op->opc; 1991c896fe29Sbellard def = &tcg_op_defs[c]; 1992c45cb8bbSRichard Henderson 1993765b842aSRichard Henderson if (c == INDEX_op_insn_start) { 1994b016486eSRichard Henderson nb_oargs = 0; 199515fa08f8SRichard Henderson col += qemu_log("\n ----"); 19969aef40edSRichard Henderson 19979aef40edSRichard Henderson for (i = 0; i < TARGET_INSN_START_WORDS; ++i) { 19989aef40edSRichard Henderson target_ulong a; 19997e4597d7Sbellard #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS 2000efee3746SRichard Henderson a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]); 20017e4597d7Sbellard #else 2002efee3746SRichard Henderson a = op->args[i]; 20037e4597d7Sbellard #endif 2004bdfb460eSRichard Henderson col += qemu_log(" " TARGET_FMT_lx, a); 2005eeacee4dSBlue Swirl } 20067e4597d7Sbellard } else if (c == INDEX_op_call) { 2007c896fe29Sbellard /* variable number of arguments */ 2008cd9090aaSRichard Henderson nb_oargs = TCGOP_CALLO(op); 2009cd9090aaSRichard Henderson nb_iargs = TCGOP_CALLI(op); 2010c896fe29Sbellard nb_cargs = def->nb_cargs; 2011b03cce8eSbellard 2012cf066674SRichard Henderson /* function name, flags, out args */ 2013bdfb460eSRichard Henderson col += qemu_log(" %s %s,$0x%" TCG_PRIlx ",$%d", def->name, 2014efee3746SRichard Henderson tcg_find_helper(s, op->args[nb_oargs + nb_iargs]), 2015efee3746SRichard Henderson op->args[nb_oargs + nb_iargs + 1], nb_oargs); 2016b03cce8eSbellard for (i = 0; i < nb_oargs; i++) { 201743439139SRichard Henderson col += qemu_log(",%s", tcg_get_arg_str(s, buf, sizeof(buf), 2018efee3746SRichard Henderson op->args[i])); 2019b03cce8eSbellard } 2020cf066674SRichard Henderson for (i = 0; i < nb_iargs; i++) { 2021efee3746SRichard Henderson TCGArg arg = op->args[nb_oargs + i]; 2022cf066674SRichard Henderson const char *t = "<dummy>"; 2023cf066674SRichard Henderson if (arg != TCG_CALL_DUMMY_ARG) { 202443439139SRichard Henderson t = tcg_get_arg_str(s, buf, sizeof(buf), arg); 2025b03cce8eSbellard } 2026bdfb460eSRichard Henderson col += qemu_log(",%s", t); 2027e8996ee0Sbellard } 2028b03cce8eSbellard } else { 2029bdfb460eSRichard Henderson col += qemu_log(" %s ", def->name); 2030c45cb8bbSRichard Henderson 2031c896fe29Sbellard nb_oargs = def->nb_oargs; 2032c896fe29Sbellard nb_iargs = def->nb_iargs; 2033c896fe29Sbellard nb_cargs = def->nb_cargs; 2034c896fe29Sbellard 2035d2fd745fSRichard Henderson if (def->flags & TCG_OPF_VECTOR) { 2036d2fd745fSRichard Henderson col += qemu_log("v%d,e%d,", 64 << TCGOP_VECL(op), 2037d2fd745fSRichard Henderson 8 << TCGOP_VECE(op)); 2038d2fd745fSRichard Henderson } 2039d2fd745fSRichard Henderson 2040c896fe29Sbellard k = 0; 2041c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 2042eeacee4dSBlue Swirl if (k != 0) { 2043bdfb460eSRichard Henderson col += qemu_log(","); 2044eeacee4dSBlue Swirl } 204543439139SRichard Henderson col += qemu_log("%s", tcg_get_arg_str(s, buf, sizeof(buf), 2046efee3746SRichard Henderson op->args[k++])); 2047c896fe29Sbellard } 2048c896fe29Sbellard for (i = 0; i < nb_iargs; i++) { 2049eeacee4dSBlue Swirl if (k != 0) { 2050bdfb460eSRichard Henderson col += qemu_log(","); 2051eeacee4dSBlue Swirl } 205243439139SRichard Henderson col += qemu_log("%s", tcg_get_arg_str(s, buf, sizeof(buf), 2053efee3746SRichard Henderson op->args[k++])); 2054c896fe29Sbellard } 2055be210acbSRichard Henderson switch (c) { 2056be210acbSRichard Henderson case INDEX_op_brcond_i32: 2057ffc5ea09SRichard Henderson case INDEX_op_setcond_i32: 2058ffc5ea09SRichard Henderson case INDEX_op_movcond_i32: 2059be210acbSRichard Henderson case INDEX_op_brcond2_i32: 2060be210acbSRichard Henderson case INDEX_op_setcond2_i32: 2061ffc5ea09SRichard Henderson case INDEX_op_brcond_i64: 2062be210acbSRichard Henderson case INDEX_op_setcond_i64: 2063ffc5ea09SRichard Henderson case INDEX_op_movcond_i64: 2064212be173SRichard Henderson case INDEX_op_cmp_vec: 2065f75da298SRichard Henderson case INDEX_op_cmpsel_vec: 2066efee3746SRichard Henderson if (op->args[k] < ARRAY_SIZE(cond_name) 2067efee3746SRichard Henderson && cond_name[op->args[k]]) { 2068efee3746SRichard Henderson col += qemu_log(",%s", cond_name[op->args[k++]]); 2069eeacee4dSBlue Swirl } else { 2070efee3746SRichard Henderson col += qemu_log(",$0x%" TCG_PRIlx, op->args[k++]); 2071eeacee4dSBlue Swirl } 2072f48f3edeSblueswir1 i = 1; 2073be210acbSRichard Henderson break; 2074f713d6adSRichard Henderson case INDEX_op_qemu_ld_i32: 2075f713d6adSRichard Henderson case INDEX_op_qemu_st_i32: 2076f713d6adSRichard Henderson case INDEX_op_qemu_ld_i64: 2077f713d6adSRichard Henderson case INDEX_op_qemu_st_i64: 207859227d5dSRichard Henderson { 2079efee3746SRichard Henderson TCGMemOpIdx oi = op->args[k++]; 208014776ab5STony Nguyen MemOp op = get_memop(oi); 208159227d5dSRichard Henderson unsigned ix = get_mmuidx(oi); 208259227d5dSRichard Henderson 208359c4b7e8SRichard Henderson if (op & ~(MO_AMASK | MO_BSWAP | MO_SSIZE)) { 2084bdfb460eSRichard Henderson col += qemu_log(",$0x%x,%u", op, ix); 208559c4b7e8SRichard Henderson } else { 20861f00b27fSSergey Sorokin const char *s_al, *s_op; 20871f00b27fSSergey Sorokin s_al = alignment_name[(op & MO_AMASK) >> MO_ASHIFT]; 208859c4b7e8SRichard Henderson s_op = ldst_name[op & (MO_BSWAP | MO_SSIZE)]; 2089bdfb460eSRichard Henderson col += qemu_log(",%s%s,%u", s_al, s_op, ix); 2090f713d6adSRichard Henderson } 2091f713d6adSRichard Henderson i = 1; 209259227d5dSRichard Henderson } 2093f713d6adSRichard Henderson break; 2094be210acbSRichard Henderson default: 2095f48f3edeSblueswir1 i = 0; 2096be210acbSRichard Henderson break; 2097be210acbSRichard Henderson } 209851e3972cSRichard Henderson switch (c) { 209951e3972cSRichard Henderson case INDEX_op_set_label: 210051e3972cSRichard Henderson case INDEX_op_br: 210151e3972cSRichard Henderson case INDEX_op_brcond_i32: 210251e3972cSRichard Henderson case INDEX_op_brcond_i64: 210351e3972cSRichard Henderson case INDEX_op_brcond2_i32: 2104efee3746SRichard Henderson col += qemu_log("%s$L%d", k ? "," : "", 2105efee3746SRichard Henderson arg_label(op->args[k])->id); 210651e3972cSRichard Henderson i++, k++; 210751e3972cSRichard Henderson break; 210851e3972cSRichard Henderson default: 210951e3972cSRichard Henderson break; 2110eeacee4dSBlue Swirl } 211151e3972cSRichard Henderson for (; i < nb_cargs; i++, k++) { 2112efee3746SRichard Henderson col += qemu_log("%s$0x%" TCG_PRIlx, k ? "," : "", op->args[k]); 2113bdfb460eSRichard Henderson } 2114bdfb460eSRichard Henderson } 2115bdfb460eSRichard Henderson 21161894f69aSRichard Henderson if (have_prefs || op->life) { 21177606488cSRobert Foley 21187606488cSRobert Foley QemuLogFile *logfile; 21197606488cSRobert Foley 21207606488cSRobert Foley rcu_read_lock(); 21217606488cSRobert Foley logfile = atomic_rcu_read(&qemu_logfile); 21227606488cSRobert Foley if (logfile) { 21231894f69aSRichard Henderson for (; col < 40; ++col) { 21247606488cSRobert Foley putc(' ', logfile->fd); 2125bdfb460eSRichard Henderson } 21261894f69aSRichard Henderson } 21277606488cSRobert Foley rcu_read_unlock(); 21287606488cSRobert Foley } 21291894f69aSRichard Henderson 21301894f69aSRichard Henderson if (op->life) { 21311894f69aSRichard Henderson unsigned life = op->life; 2132bdfb460eSRichard Henderson 2133bdfb460eSRichard Henderson if (life & (SYNC_ARG * 3)) { 2134bdfb460eSRichard Henderson qemu_log(" sync:"); 2135bdfb460eSRichard Henderson for (i = 0; i < 2; ++i) { 2136bdfb460eSRichard Henderson if (life & (SYNC_ARG << i)) { 2137bdfb460eSRichard Henderson qemu_log(" %d", i); 2138bdfb460eSRichard Henderson } 2139bdfb460eSRichard Henderson } 2140bdfb460eSRichard Henderson } 2141bdfb460eSRichard Henderson life /= DEAD_ARG; 2142bdfb460eSRichard Henderson if (life) { 2143bdfb460eSRichard Henderson qemu_log(" dead:"); 2144bdfb460eSRichard Henderson for (i = 0; life; ++i, life >>= 1) { 2145bdfb460eSRichard Henderson if (life & 1) { 2146bdfb460eSRichard Henderson qemu_log(" %d", i); 2147bdfb460eSRichard Henderson } 2148bdfb460eSRichard Henderson } 2149c896fe29Sbellard } 2150b03cce8eSbellard } 21511894f69aSRichard Henderson 21521894f69aSRichard Henderson if (have_prefs) { 21531894f69aSRichard Henderson for (i = 0; i < nb_oargs; ++i) { 21541894f69aSRichard Henderson TCGRegSet set = op->output_pref[i]; 21551894f69aSRichard Henderson 21561894f69aSRichard Henderson if (i == 0) { 21571894f69aSRichard Henderson qemu_log(" pref="); 21581894f69aSRichard Henderson } else { 21591894f69aSRichard Henderson qemu_log(","); 21601894f69aSRichard Henderson } 21611894f69aSRichard Henderson if (set == 0) { 21621894f69aSRichard Henderson qemu_log("none"); 21631894f69aSRichard Henderson } else if (set == MAKE_64BIT_MASK(0, TCG_TARGET_NB_REGS)) { 21641894f69aSRichard Henderson qemu_log("all"); 21651894f69aSRichard Henderson #ifdef CONFIG_DEBUG_TCG 21661894f69aSRichard Henderson } else if (tcg_regset_single(set)) { 21671894f69aSRichard Henderson TCGReg reg = tcg_regset_first(set); 21681894f69aSRichard Henderson qemu_log("%s", tcg_target_reg_names[reg]); 21691894f69aSRichard Henderson #endif 21701894f69aSRichard Henderson } else if (TCG_TARGET_NB_REGS <= 32) { 21711894f69aSRichard Henderson qemu_log("%#x", (uint32_t)set); 21721894f69aSRichard Henderson } else { 21731894f69aSRichard Henderson qemu_log("%#" PRIx64, (uint64_t)set); 21741894f69aSRichard Henderson } 21751894f69aSRichard Henderson } 21761894f69aSRichard Henderson } 21771894f69aSRichard Henderson 2178eeacee4dSBlue Swirl qemu_log("\n"); 2179c896fe29Sbellard } 2180c896fe29Sbellard } 2181c896fe29Sbellard 2182c896fe29Sbellard /* we give more priority to constraints with less registers */ 2183c896fe29Sbellard static int get_constraint_priority(const TCGOpDef *def, int k) 2184c896fe29Sbellard { 2185c896fe29Sbellard const TCGArgConstraint *arg_ct; 2186c896fe29Sbellard 2187c896fe29Sbellard int i, n; 2188c896fe29Sbellard arg_ct = &def->args_ct[k]; 2189c896fe29Sbellard if (arg_ct->ct & TCG_CT_ALIAS) { 2190c896fe29Sbellard /* an alias is equivalent to a single register */ 2191c896fe29Sbellard n = 1; 2192c896fe29Sbellard } else { 2193c896fe29Sbellard if (!(arg_ct->ct & TCG_CT_REG)) 2194c896fe29Sbellard return 0; 2195c896fe29Sbellard n = 0; 2196c896fe29Sbellard for(i = 0; i < TCG_TARGET_NB_REGS; i++) { 2197c896fe29Sbellard if (tcg_regset_test_reg(arg_ct->u.regs, i)) 2198c896fe29Sbellard n++; 2199c896fe29Sbellard } 2200c896fe29Sbellard } 2201c896fe29Sbellard return TCG_TARGET_NB_REGS - n + 1; 2202c896fe29Sbellard } 2203c896fe29Sbellard 2204c896fe29Sbellard /* sort from highest priority to lowest */ 2205c896fe29Sbellard static void sort_constraints(TCGOpDef *def, int start, int n) 2206c896fe29Sbellard { 2207c896fe29Sbellard int i, j, p1, p2, tmp; 2208c896fe29Sbellard 2209c896fe29Sbellard for(i = 0; i < n; i++) 2210c896fe29Sbellard def->sorted_args[start + i] = start + i; 2211c896fe29Sbellard if (n <= 1) 2212c896fe29Sbellard return; 2213c896fe29Sbellard for(i = 0; i < n - 1; i++) { 2214c896fe29Sbellard for(j = i + 1; j < n; j++) { 2215c896fe29Sbellard p1 = get_constraint_priority(def, def->sorted_args[start + i]); 2216c896fe29Sbellard p2 = get_constraint_priority(def, def->sorted_args[start + j]); 2217c896fe29Sbellard if (p1 < p2) { 2218c896fe29Sbellard tmp = def->sorted_args[start + i]; 2219c896fe29Sbellard def->sorted_args[start + i] = def->sorted_args[start + j]; 2220c896fe29Sbellard def->sorted_args[start + j] = tmp; 2221c896fe29Sbellard } 2222c896fe29Sbellard } 2223c896fe29Sbellard } 2224c896fe29Sbellard } 2225c896fe29Sbellard 2226f69d277eSRichard Henderson static void process_op_defs(TCGContext *s) 2227c896fe29Sbellard { 2228a9751609SRichard Henderson TCGOpcode op; 2229c896fe29Sbellard 2230f69d277eSRichard Henderson for (op = 0; op < NB_OPS; op++) { 2231f69d277eSRichard Henderson TCGOpDef *def = &tcg_op_defs[op]; 2232f69d277eSRichard Henderson const TCGTargetOpDef *tdefs; 2233069ea736SRichard Henderson TCGType type; 2234069ea736SRichard Henderson int i, nb_args; 2235f69d277eSRichard Henderson 2236f69d277eSRichard Henderson if (def->flags & TCG_OPF_NOT_PRESENT) { 2237f69d277eSRichard Henderson continue; 2238f69d277eSRichard Henderson } 2239f69d277eSRichard Henderson 2240c896fe29Sbellard nb_args = def->nb_iargs + def->nb_oargs; 2241f69d277eSRichard Henderson if (nb_args == 0) { 2242f69d277eSRichard Henderson continue; 2243f69d277eSRichard Henderson } 2244f69d277eSRichard Henderson 2245f69d277eSRichard Henderson tdefs = tcg_target_op_def(op); 2246f69d277eSRichard Henderson /* Missing TCGTargetOpDef entry. */ 2247f69d277eSRichard Henderson tcg_debug_assert(tdefs != NULL); 2248f69d277eSRichard Henderson 2249069ea736SRichard Henderson type = (def->flags & TCG_OPF_64BIT ? TCG_TYPE_I64 : TCG_TYPE_I32); 2250c896fe29Sbellard for (i = 0; i < nb_args; i++) { 2251f69d277eSRichard Henderson const char *ct_str = tdefs->args_ct_str[i]; 2252f69d277eSRichard Henderson /* Incomplete TCGTargetOpDef entry. */ 2253eabb7b91SAurelien Jarno tcg_debug_assert(ct_str != NULL); 2254f69d277eSRichard Henderson 2255ccb1bb66SRichard Henderson def->args_ct[i].u.regs = 0; 2256c896fe29Sbellard def->args_ct[i].ct = 0; 225717280ff4SRichard Henderson while (*ct_str != '\0') { 225817280ff4SRichard Henderson switch(*ct_str) { 225917280ff4SRichard Henderson case '0' ... '9': 226017280ff4SRichard Henderson { 226117280ff4SRichard Henderson int oarg = *ct_str - '0'; 226217280ff4SRichard Henderson tcg_debug_assert(ct_str == tdefs->args_ct_str[i]); 2263eabb7b91SAurelien Jarno tcg_debug_assert(oarg < def->nb_oargs); 2264eabb7b91SAurelien Jarno tcg_debug_assert(def->args_ct[oarg].ct & TCG_CT_REG); 226517280ff4SRichard Henderson /* TCG_CT_ALIAS is for the output arguments. 226617280ff4SRichard Henderson The input is tagged with TCG_CT_IALIAS. */ 2267c896fe29Sbellard def->args_ct[i] = def->args_ct[oarg]; 226817280ff4SRichard Henderson def->args_ct[oarg].ct |= TCG_CT_ALIAS; 22695ff9d6a4Sbellard def->args_ct[oarg].alias_index = i; 2270c896fe29Sbellard def->args_ct[i].ct |= TCG_CT_IALIAS; 22715ff9d6a4Sbellard def->args_ct[i].alias_index = oarg; 227217280ff4SRichard Henderson } 227317280ff4SRichard Henderson ct_str++; 2274c896fe29Sbellard break; 227582790a87SRichard Henderson case '&': 227682790a87SRichard Henderson def->args_ct[i].ct |= TCG_CT_NEWREG; 227782790a87SRichard Henderson ct_str++; 227882790a87SRichard Henderson break; 2279c896fe29Sbellard case 'i': 2280c896fe29Sbellard def->args_ct[i].ct |= TCG_CT_CONST; 2281c896fe29Sbellard ct_str++; 2282c896fe29Sbellard break; 2283c896fe29Sbellard default: 2284069ea736SRichard Henderson ct_str = target_parse_constraint(&def->args_ct[i], 2285069ea736SRichard Henderson ct_str, type); 2286f69d277eSRichard Henderson /* Typo in TCGTargetOpDef constraint. */ 2287069ea736SRichard Henderson tcg_debug_assert(ct_str != NULL); 2288c896fe29Sbellard } 2289c896fe29Sbellard } 2290c896fe29Sbellard } 2291c896fe29Sbellard 2292c68aaa18SStefan Weil /* TCGTargetOpDef entry with too much information? */ 2293eabb7b91SAurelien Jarno tcg_debug_assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL); 2294c68aaa18SStefan Weil 2295c896fe29Sbellard /* sort the constraints (XXX: this is just an heuristic) */ 2296c896fe29Sbellard sort_constraints(def, 0, def->nb_oargs); 2297c896fe29Sbellard sort_constraints(def, def->nb_oargs, def->nb_iargs); 2298c896fe29Sbellard } 2299c896fe29Sbellard } 2300c896fe29Sbellard 23010c627cdcSRichard Henderson void tcg_op_remove(TCGContext *s, TCGOp *op) 23020c627cdcSRichard Henderson { 2303d88a117eSRichard Henderson TCGLabel *label; 2304d88a117eSRichard Henderson 2305d88a117eSRichard Henderson switch (op->opc) { 2306d88a117eSRichard Henderson case INDEX_op_br: 2307d88a117eSRichard Henderson label = arg_label(op->args[0]); 2308d88a117eSRichard Henderson label->refs--; 2309d88a117eSRichard Henderson break; 2310d88a117eSRichard Henderson case INDEX_op_brcond_i32: 2311d88a117eSRichard Henderson case INDEX_op_brcond_i64: 2312d88a117eSRichard Henderson label = arg_label(op->args[3]); 2313d88a117eSRichard Henderson label->refs--; 2314d88a117eSRichard Henderson break; 2315d88a117eSRichard Henderson case INDEX_op_brcond2_i32: 2316d88a117eSRichard Henderson label = arg_label(op->args[5]); 2317d88a117eSRichard Henderson label->refs--; 2318d88a117eSRichard Henderson break; 2319d88a117eSRichard Henderson default: 2320d88a117eSRichard Henderson break; 2321d88a117eSRichard Henderson } 2322d88a117eSRichard Henderson 232315fa08f8SRichard Henderson QTAILQ_REMOVE(&s->ops, op, link); 232415fa08f8SRichard Henderson QTAILQ_INSERT_TAIL(&s->free_ops, op, link); 2325abebf925SRichard Henderson s->nb_ops--; 23260c627cdcSRichard Henderson 23270c627cdcSRichard Henderson #ifdef CONFIG_PROFILER 2328c3fac113SEmilio G. Cota atomic_set(&s->prof.del_op_count, s->prof.del_op_count + 1); 23290c627cdcSRichard Henderson #endif 23300c627cdcSRichard Henderson } 23310c627cdcSRichard Henderson 233215fa08f8SRichard Henderson static TCGOp *tcg_op_alloc(TCGOpcode opc) 233315fa08f8SRichard Henderson { 233415fa08f8SRichard Henderson TCGContext *s = tcg_ctx; 233515fa08f8SRichard Henderson TCGOp *op; 233615fa08f8SRichard Henderson 233715fa08f8SRichard Henderson if (likely(QTAILQ_EMPTY(&s->free_ops))) { 233815fa08f8SRichard Henderson op = tcg_malloc(sizeof(TCGOp)); 233915fa08f8SRichard Henderson } else { 234015fa08f8SRichard Henderson op = QTAILQ_FIRST(&s->free_ops); 234115fa08f8SRichard Henderson QTAILQ_REMOVE(&s->free_ops, op, link); 234215fa08f8SRichard Henderson } 234315fa08f8SRichard Henderson memset(op, 0, offsetof(TCGOp, link)); 234415fa08f8SRichard Henderson op->opc = opc; 2345abebf925SRichard Henderson s->nb_ops++; 234615fa08f8SRichard Henderson 234715fa08f8SRichard Henderson return op; 234815fa08f8SRichard Henderson } 234915fa08f8SRichard Henderson 235015fa08f8SRichard Henderson TCGOp *tcg_emit_op(TCGOpcode opc) 235115fa08f8SRichard Henderson { 235215fa08f8SRichard Henderson TCGOp *op = tcg_op_alloc(opc); 235315fa08f8SRichard Henderson QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link); 235415fa08f8SRichard Henderson return op; 235515fa08f8SRichard Henderson } 235615fa08f8SRichard Henderson 2357ac1043f6SEmilio G. Cota TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op, TCGOpcode opc) 23585a18407fSRichard Henderson { 235915fa08f8SRichard Henderson TCGOp *new_op = tcg_op_alloc(opc); 236015fa08f8SRichard Henderson QTAILQ_INSERT_BEFORE(old_op, new_op, link); 23615a18407fSRichard Henderson return new_op; 23625a18407fSRichard Henderson } 23635a18407fSRichard Henderson 2364ac1043f6SEmilio G. Cota TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op, TCGOpcode opc) 23655a18407fSRichard Henderson { 236615fa08f8SRichard Henderson TCGOp *new_op = tcg_op_alloc(opc); 236715fa08f8SRichard Henderson QTAILQ_INSERT_AFTER(&s->ops, old_op, new_op, link); 23685a18407fSRichard Henderson return new_op; 23695a18407fSRichard Henderson } 23705a18407fSRichard Henderson 2371b4fc67c7SRichard Henderson /* Reachable analysis : remove unreachable code. */ 2372b4fc67c7SRichard Henderson static void reachable_code_pass(TCGContext *s) 2373b4fc67c7SRichard Henderson { 2374b4fc67c7SRichard Henderson TCGOp *op, *op_next; 2375b4fc67c7SRichard Henderson bool dead = false; 2376b4fc67c7SRichard Henderson 2377b4fc67c7SRichard Henderson QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) { 2378b4fc67c7SRichard Henderson bool remove = dead; 2379b4fc67c7SRichard Henderson TCGLabel *label; 2380b4fc67c7SRichard Henderson int call_flags; 2381b4fc67c7SRichard Henderson 2382b4fc67c7SRichard Henderson switch (op->opc) { 2383b4fc67c7SRichard Henderson case INDEX_op_set_label: 2384b4fc67c7SRichard Henderson label = arg_label(op->args[0]); 2385b4fc67c7SRichard Henderson if (label->refs == 0) { 2386b4fc67c7SRichard Henderson /* 2387b4fc67c7SRichard Henderson * While there is an occasional backward branch, virtually 2388b4fc67c7SRichard Henderson * all branches generated by the translators are forward. 2389b4fc67c7SRichard Henderson * Which means that generally we will have already removed 2390b4fc67c7SRichard Henderson * all references to the label that will be, and there is 2391b4fc67c7SRichard Henderson * little to be gained by iterating. 2392b4fc67c7SRichard Henderson */ 2393b4fc67c7SRichard Henderson remove = true; 2394b4fc67c7SRichard Henderson } else { 2395b4fc67c7SRichard Henderson /* Once we see a label, insns become live again. */ 2396b4fc67c7SRichard Henderson dead = false; 2397b4fc67c7SRichard Henderson remove = false; 2398b4fc67c7SRichard Henderson 2399b4fc67c7SRichard Henderson /* 2400b4fc67c7SRichard Henderson * Optimization can fold conditional branches to unconditional. 2401b4fc67c7SRichard Henderson * If we find a label with one reference which is preceded by 2402b4fc67c7SRichard Henderson * an unconditional branch to it, remove both. This needed to 2403b4fc67c7SRichard Henderson * wait until the dead code in between them was removed. 2404b4fc67c7SRichard Henderson */ 2405b4fc67c7SRichard Henderson if (label->refs == 1) { 2406eae3eb3eSPaolo Bonzini TCGOp *op_prev = QTAILQ_PREV(op, link); 2407b4fc67c7SRichard Henderson if (op_prev->opc == INDEX_op_br && 2408b4fc67c7SRichard Henderson label == arg_label(op_prev->args[0])) { 2409b4fc67c7SRichard Henderson tcg_op_remove(s, op_prev); 2410b4fc67c7SRichard Henderson remove = true; 2411b4fc67c7SRichard Henderson } 2412b4fc67c7SRichard Henderson } 2413b4fc67c7SRichard Henderson } 2414b4fc67c7SRichard Henderson break; 2415b4fc67c7SRichard Henderson 2416b4fc67c7SRichard Henderson case INDEX_op_br: 2417b4fc67c7SRichard Henderson case INDEX_op_exit_tb: 2418b4fc67c7SRichard Henderson case INDEX_op_goto_ptr: 2419b4fc67c7SRichard Henderson /* Unconditional branches; everything following is dead. */ 2420b4fc67c7SRichard Henderson dead = true; 2421b4fc67c7SRichard Henderson break; 2422b4fc67c7SRichard Henderson 2423b4fc67c7SRichard Henderson case INDEX_op_call: 2424b4fc67c7SRichard Henderson /* Notice noreturn helper calls, raising exceptions. */ 2425b4fc67c7SRichard Henderson call_flags = op->args[TCGOP_CALLO(op) + TCGOP_CALLI(op) + 1]; 2426b4fc67c7SRichard Henderson if (call_flags & TCG_CALL_NO_RETURN) { 2427b4fc67c7SRichard Henderson dead = true; 2428b4fc67c7SRichard Henderson } 2429b4fc67c7SRichard Henderson break; 2430b4fc67c7SRichard Henderson 2431b4fc67c7SRichard Henderson case INDEX_op_insn_start: 2432b4fc67c7SRichard Henderson /* Never remove -- we need to keep these for unwind. */ 2433b4fc67c7SRichard Henderson remove = false; 2434b4fc67c7SRichard Henderson break; 2435b4fc67c7SRichard Henderson 2436b4fc67c7SRichard Henderson default: 2437b4fc67c7SRichard Henderson break; 2438b4fc67c7SRichard Henderson } 2439b4fc67c7SRichard Henderson 2440b4fc67c7SRichard Henderson if (remove) { 2441b4fc67c7SRichard Henderson tcg_op_remove(s, op); 2442b4fc67c7SRichard Henderson } 2443b4fc67c7SRichard Henderson } 2444b4fc67c7SRichard Henderson } 2445b4fc67c7SRichard Henderson 2446c70fbf0aSRichard Henderson #define TS_DEAD 1 2447c70fbf0aSRichard Henderson #define TS_MEM 2 2448c70fbf0aSRichard Henderson 24495a18407fSRichard Henderson #define IS_DEAD_ARG(n) (arg_life & (DEAD_ARG << (n))) 24505a18407fSRichard Henderson #define NEED_SYNC_ARG(n) (arg_life & (SYNC_ARG << (n))) 24515a18407fSRichard Henderson 245225f49c5fSRichard Henderson /* For liveness_pass_1, the register preferences for a given temp. */ 245325f49c5fSRichard Henderson static inline TCGRegSet *la_temp_pref(TCGTemp *ts) 245425f49c5fSRichard Henderson { 245525f49c5fSRichard Henderson return ts->state_ptr; 245625f49c5fSRichard Henderson } 245725f49c5fSRichard Henderson 245825f49c5fSRichard Henderson /* For liveness_pass_1, reset the preferences for a given temp to the 245925f49c5fSRichard Henderson * maximal regset for its type. 246025f49c5fSRichard Henderson */ 246125f49c5fSRichard Henderson static inline void la_reset_pref(TCGTemp *ts) 246225f49c5fSRichard Henderson { 246325f49c5fSRichard Henderson *la_temp_pref(ts) 246425f49c5fSRichard Henderson = (ts->state == TS_DEAD ? 0 : tcg_target_available_regs[ts->type]); 246525f49c5fSRichard Henderson } 246625f49c5fSRichard Henderson 24679c43b68dSAurelien Jarno /* liveness analysis: end of function: all temps are dead, and globals 24689c43b68dSAurelien Jarno should be in memory. */ 24692616c808SRichard Henderson static void la_func_end(TCGContext *s, int ng, int nt) 2470c896fe29Sbellard { 2471b83eabeaSRichard Henderson int i; 2472b83eabeaSRichard Henderson 2473b83eabeaSRichard Henderson for (i = 0; i < ng; ++i) { 2474b83eabeaSRichard Henderson s->temps[i].state = TS_DEAD | TS_MEM; 247525f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 2476b83eabeaSRichard Henderson } 2477b83eabeaSRichard Henderson for (i = ng; i < nt; ++i) { 2478b83eabeaSRichard Henderson s->temps[i].state = TS_DEAD; 247925f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 2480b83eabeaSRichard Henderson } 2481c896fe29Sbellard } 2482c896fe29Sbellard 24839c43b68dSAurelien Jarno /* liveness analysis: end of basic block: all temps are dead, globals 24849c43b68dSAurelien Jarno and local temps should be in memory. */ 24852616c808SRichard Henderson static void la_bb_end(TCGContext *s, int ng, int nt) 2486641d5fbeSbellard { 2487b83eabeaSRichard Henderson int i; 2488641d5fbeSbellard 2489b83eabeaSRichard Henderson for (i = 0; i < ng; ++i) { 2490b83eabeaSRichard Henderson s->temps[i].state = TS_DEAD | TS_MEM; 249125f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 2492c70fbf0aSRichard Henderson } 2493b83eabeaSRichard Henderson for (i = ng; i < nt; ++i) { 2494b83eabeaSRichard Henderson s->temps[i].state = (s->temps[i].temp_local 2495b83eabeaSRichard Henderson ? TS_DEAD | TS_MEM 2496b83eabeaSRichard Henderson : TS_DEAD); 249725f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 2498641d5fbeSbellard } 2499641d5fbeSbellard } 2500641d5fbeSbellard 2501f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory. */ 2502f65a061cSRichard Henderson static void la_global_sync(TCGContext *s, int ng) 2503f65a061cSRichard Henderson { 2504f65a061cSRichard Henderson int i; 2505f65a061cSRichard Henderson 2506f65a061cSRichard Henderson for (i = 0; i < ng; ++i) { 250725f49c5fSRichard Henderson int state = s->temps[i].state; 250825f49c5fSRichard Henderson s->temps[i].state = state | TS_MEM; 250925f49c5fSRichard Henderson if (state == TS_DEAD) { 251025f49c5fSRichard Henderson /* If the global was previously dead, reset prefs. */ 251125f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 251225f49c5fSRichard Henderson } 2513f65a061cSRichard Henderson } 2514f65a061cSRichard Henderson } 2515f65a061cSRichard Henderson 2516f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory and kill. */ 2517f65a061cSRichard Henderson static void la_global_kill(TCGContext *s, int ng) 2518f65a061cSRichard Henderson { 2519f65a061cSRichard Henderson int i; 2520f65a061cSRichard Henderson 2521f65a061cSRichard Henderson for (i = 0; i < ng; i++) { 2522f65a061cSRichard Henderson s->temps[i].state = TS_DEAD | TS_MEM; 252325f49c5fSRichard Henderson la_reset_pref(&s->temps[i]); 252425f49c5fSRichard Henderson } 252525f49c5fSRichard Henderson } 252625f49c5fSRichard Henderson 252725f49c5fSRichard Henderson /* liveness analysis: note live globals crossing calls. */ 252825f49c5fSRichard Henderson static void la_cross_call(TCGContext *s, int nt) 252925f49c5fSRichard Henderson { 253025f49c5fSRichard Henderson TCGRegSet mask = ~tcg_target_call_clobber_regs; 253125f49c5fSRichard Henderson int i; 253225f49c5fSRichard Henderson 253325f49c5fSRichard Henderson for (i = 0; i < nt; i++) { 253425f49c5fSRichard Henderson TCGTemp *ts = &s->temps[i]; 253525f49c5fSRichard Henderson if (!(ts->state & TS_DEAD)) { 253625f49c5fSRichard Henderson TCGRegSet *pset = la_temp_pref(ts); 253725f49c5fSRichard Henderson TCGRegSet set = *pset; 253825f49c5fSRichard Henderson 253925f49c5fSRichard Henderson set &= mask; 254025f49c5fSRichard Henderson /* If the combination is not possible, restart. */ 254125f49c5fSRichard Henderson if (set == 0) { 254225f49c5fSRichard Henderson set = tcg_target_available_regs[ts->type] & mask; 254325f49c5fSRichard Henderson } 254425f49c5fSRichard Henderson *pset = set; 254525f49c5fSRichard Henderson } 2546f65a061cSRichard Henderson } 2547f65a061cSRichard Henderson } 2548f65a061cSRichard Henderson 2549a1b3c48dSRichard Henderson /* Liveness analysis : update the opc_arg_life array to tell if a 2550c896fe29Sbellard given input arguments is dead. Instructions updating dead 2551c896fe29Sbellard temporaries are removed. */ 2552b83eabeaSRichard Henderson static void liveness_pass_1(TCGContext *s) 2553c896fe29Sbellard { 2554c70fbf0aSRichard Henderson int nb_globals = s->nb_globals; 25552616c808SRichard Henderson int nb_temps = s->nb_temps; 255615fa08f8SRichard Henderson TCGOp *op, *op_prev; 255725f49c5fSRichard Henderson TCGRegSet *prefs; 255825f49c5fSRichard Henderson int i; 255925f49c5fSRichard Henderson 256025f49c5fSRichard Henderson prefs = tcg_malloc(sizeof(TCGRegSet) * nb_temps); 256125f49c5fSRichard Henderson for (i = 0; i < nb_temps; ++i) { 256225f49c5fSRichard Henderson s->temps[i].state_ptr = prefs + i; 256325f49c5fSRichard Henderson } 2564c896fe29Sbellard 2565ae36a246SRichard Henderson /* ??? Should be redundant with the exit_tb that ends the TB. */ 25662616c808SRichard Henderson la_func_end(s, nb_globals, nb_temps); 2567c896fe29Sbellard 2568eae3eb3eSPaolo Bonzini QTAILQ_FOREACH_REVERSE_SAFE(op, &s->ops, link, op_prev) { 256925f49c5fSRichard Henderson int nb_iargs, nb_oargs; 2570c45cb8bbSRichard Henderson TCGOpcode opc_new, opc_new2; 2571c45cb8bbSRichard Henderson bool have_opc_new2; 2572a1b3c48dSRichard Henderson TCGLifeData arg_life = 0; 257325f49c5fSRichard Henderson TCGTemp *ts; 2574c45cb8bbSRichard Henderson TCGOpcode opc = op->opc; 2575c45cb8bbSRichard Henderson const TCGOpDef *def = &tcg_op_defs[opc]; 2576c45cb8bbSRichard Henderson 2577c45cb8bbSRichard Henderson switch (opc) { 2578c896fe29Sbellard case INDEX_op_call: 2579c6e113f5Sbellard { 2580c6e113f5Sbellard int call_flags; 258125f49c5fSRichard Henderson int nb_call_regs; 2582c6e113f5Sbellard 2583cd9090aaSRichard Henderson nb_oargs = TCGOP_CALLO(op); 2584cd9090aaSRichard Henderson nb_iargs = TCGOP_CALLI(op); 2585efee3746SRichard Henderson call_flags = op->args[nb_oargs + nb_iargs + 1]; 2586c6e113f5Sbellard 2587c45cb8bbSRichard Henderson /* pure functions can be removed if their result is unused */ 258878505279SAurelien Jarno if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) { 2589c6e113f5Sbellard for (i = 0; i < nb_oargs; i++) { 259025f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 259125f49c5fSRichard Henderson if (ts->state != TS_DEAD) { 2592c6e113f5Sbellard goto do_not_remove_call; 2593c6e113f5Sbellard } 25949c43b68dSAurelien Jarno } 2595c45cb8bbSRichard Henderson goto do_remove; 2596152c35aaSRichard Henderson } 2597c6e113f5Sbellard do_not_remove_call: 2598c896fe29Sbellard 259925f49c5fSRichard Henderson /* Output args are dead. */ 2600c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 260125f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 260225f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 2603a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 26046b64b624SAurelien Jarno } 260525f49c5fSRichard Henderson if (ts->state & TS_MEM) { 2606a1b3c48dSRichard Henderson arg_life |= SYNC_ARG << i; 26079c43b68dSAurelien Jarno } 260825f49c5fSRichard Henderson ts->state = TS_DEAD; 260925f49c5fSRichard Henderson la_reset_pref(ts); 261025f49c5fSRichard Henderson 261125f49c5fSRichard Henderson /* Not used -- it will be tcg_target_call_oarg_regs[i]. */ 261225f49c5fSRichard Henderson op->output_pref[i] = 0; 2613c896fe29Sbellard } 2614c896fe29Sbellard 261578505279SAurelien Jarno if (!(call_flags & (TCG_CALL_NO_WRITE_GLOBALS | 261678505279SAurelien Jarno TCG_CALL_NO_READ_GLOBALS))) { 2617f65a061cSRichard Henderson la_global_kill(s, nb_globals); 2618c70fbf0aSRichard Henderson } else if (!(call_flags & TCG_CALL_NO_READ_GLOBALS)) { 2619f65a061cSRichard Henderson la_global_sync(s, nb_globals); 2620b9c18f56Saurel32 } 2621c896fe29Sbellard 262225f49c5fSRichard Henderson /* Record arguments that die in this helper. */ 2623866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 262425f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 262525f49c5fSRichard Henderson if (ts && ts->state & TS_DEAD) { 2626a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 2627c896fe29Sbellard } 2628c896fe29Sbellard } 262925f49c5fSRichard Henderson 263025f49c5fSRichard Henderson /* For all live registers, remove call-clobbered prefs. */ 263125f49c5fSRichard Henderson la_cross_call(s, nb_temps); 263225f49c5fSRichard Henderson 263325f49c5fSRichard Henderson nb_call_regs = ARRAY_SIZE(tcg_target_call_iarg_regs); 263425f49c5fSRichard Henderson 263525f49c5fSRichard Henderson /* Input arguments are live for preceding opcodes. */ 263625f49c5fSRichard Henderson for (i = 0; i < nb_iargs; i++) { 263725f49c5fSRichard Henderson ts = arg_temp(op->args[i + nb_oargs]); 263825f49c5fSRichard Henderson if (ts && ts->state & TS_DEAD) { 263925f49c5fSRichard Henderson /* For those arguments that die, and will be allocated 264025f49c5fSRichard Henderson * in registers, clear the register set for that arg, 264125f49c5fSRichard Henderson * to be filled in below. For args that will be on 264225f49c5fSRichard Henderson * the stack, reset to any available reg. 264325f49c5fSRichard Henderson */ 264425f49c5fSRichard Henderson *la_temp_pref(ts) 264525f49c5fSRichard Henderson = (i < nb_call_regs ? 0 : 264625f49c5fSRichard Henderson tcg_target_available_regs[ts->type]); 264725f49c5fSRichard Henderson ts->state &= ~TS_DEAD; 264825f49c5fSRichard Henderson } 264925f49c5fSRichard Henderson } 265025f49c5fSRichard Henderson 265125f49c5fSRichard Henderson /* For each input argument, add its input register to prefs. 265225f49c5fSRichard Henderson If a temp is used once, this produces a single set bit. */ 265325f49c5fSRichard Henderson for (i = 0; i < MIN(nb_call_regs, nb_iargs); i++) { 265425f49c5fSRichard Henderson ts = arg_temp(op->args[i + nb_oargs]); 265525f49c5fSRichard Henderson if (ts) { 265625f49c5fSRichard Henderson tcg_regset_set_reg(*la_temp_pref(ts), 265725f49c5fSRichard Henderson tcg_target_call_iarg_regs[i]); 2658c70fbf0aSRichard Henderson } 2659c19f47bfSAurelien Jarno } 2660c6e113f5Sbellard } 2661c896fe29Sbellard break; 2662765b842aSRichard Henderson case INDEX_op_insn_start: 2663c896fe29Sbellard break; 26645ff9d6a4Sbellard case INDEX_op_discard: 26655ff9d6a4Sbellard /* mark the temporary as dead */ 266625f49c5fSRichard Henderson ts = arg_temp(op->args[0]); 266725f49c5fSRichard Henderson ts->state = TS_DEAD; 266825f49c5fSRichard Henderson la_reset_pref(ts); 26695ff9d6a4Sbellard break; 26701305c451SRichard Henderson 26711305c451SRichard Henderson case INDEX_op_add2_i32: 2672c45cb8bbSRichard Henderson opc_new = INDEX_op_add_i32; 2673f1fae40cSRichard Henderson goto do_addsub2; 26741305c451SRichard Henderson case INDEX_op_sub2_i32: 2675c45cb8bbSRichard Henderson opc_new = INDEX_op_sub_i32; 2676f1fae40cSRichard Henderson goto do_addsub2; 2677f1fae40cSRichard Henderson case INDEX_op_add2_i64: 2678c45cb8bbSRichard Henderson opc_new = INDEX_op_add_i64; 2679f1fae40cSRichard Henderson goto do_addsub2; 2680f1fae40cSRichard Henderson case INDEX_op_sub2_i64: 2681c45cb8bbSRichard Henderson opc_new = INDEX_op_sub_i64; 2682f1fae40cSRichard Henderson do_addsub2: 26831305c451SRichard Henderson nb_iargs = 4; 26841305c451SRichard Henderson nb_oargs = 2; 26851305c451SRichard Henderson /* Test if the high part of the operation is dead, but not 26861305c451SRichard Henderson the low part. The result can be optimized to a simple 26871305c451SRichard Henderson add or sub. This happens often for x86_64 guest when the 26881305c451SRichard Henderson cpu mode is set to 32 bit. */ 2689b83eabeaSRichard Henderson if (arg_temp(op->args[1])->state == TS_DEAD) { 2690b83eabeaSRichard Henderson if (arg_temp(op->args[0])->state == TS_DEAD) { 26911305c451SRichard Henderson goto do_remove; 26921305c451SRichard Henderson } 2693c45cb8bbSRichard Henderson /* Replace the opcode and adjust the args in place, 2694c45cb8bbSRichard Henderson leaving 3 unused args at the end. */ 2695c45cb8bbSRichard Henderson op->opc = opc = opc_new; 2696efee3746SRichard Henderson op->args[1] = op->args[2]; 2697efee3746SRichard Henderson op->args[2] = op->args[4]; 26981305c451SRichard Henderson /* Fall through and mark the single-word operation live. */ 26991305c451SRichard Henderson nb_iargs = 2; 27001305c451SRichard Henderson nb_oargs = 1; 27011305c451SRichard Henderson } 27021305c451SRichard Henderson goto do_not_remove; 27031305c451SRichard Henderson 27041414968aSRichard Henderson case INDEX_op_mulu2_i32: 2705c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i32; 2706c45cb8bbSRichard Henderson opc_new2 = INDEX_op_muluh_i32; 2707c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_muluh_i32; 270803271524SRichard Henderson goto do_mul2; 2709f1fae40cSRichard Henderson case INDEX_op_muls2_i32: 2710c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i32; 2711c45cb8bbSRichard Henderson opc_new2 = INDEX_op_mulsh_i32; 2712c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_mulsh_i32; 2713f1fae40cSRichard Henderson goto do_mul2; 2714f1fae40cSRichard Henderson case INDEX_op_mulu2_i64: 2715c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i64; 2716c45cb8bbSRichard Henderson opc_new2 = INDEX_op_muluh_i64; 2717c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_muluh_i64; 271803271524SRichard Henderson goto do_mul2; 2719f1fae40cSRichard Henderson case INDEX_op_muls2_i64: 2720c45cb8bbSRichard Henderson opc_new = INDEX_op_mul_i64; 2721c45cb8bbSRichard Henderson opc_new2 = INDEX_op_mulsh_i64; 2722c45cb8bbSRichard Henderson have_opc_new2 = TCG_TARGET_HAS_mulsh_i64; 272303271524SRichard Henderson goto do_mul2; 2724f1fae40cSRichard Henderson do_mul2: 27251414968aSRichard Henderson nb_iargs = 2; 27261414968aSRichard Henderson nb_oargs = 2; 2727b83eabeaSRichard Henderson if (arg_temp(op->args[1])->state == TS_DEAD) { 2728b83eabeaSRichard Henderson if (arg_temp(op->args[0])->state == TS_DEAD) { 272903271524SRichard Henderson /* Both parts of the operation are dead. */ 27301414968aSRichard Henderson goto do_remove; 27311414968aSRichard Henderson } 273203271524SRichard Henderson /* The high part of the operation is dead; generate the low. */ 2733c45cb8bbSRichard Henderson op->opc = opc = opc_new; 2734efee3746SRichard Henderson op->args[1] = op->args[2]; 2735efee3746SRichard Henderson op->args[2] = op->args[3]; 2736b83eabeaSRichard Henderson } else if (arg_temp(op->args[0])->state == TS_DEAD && have_opc_new2) { 273703271524SRichard Henderson /* The low part of the operation is dead; generate the high. */ 2738c45cb8bbSRichard Henderson op->opc = opc = opc_new2; 2739efee3746SRichard Henderson op->args[0] = op->args[1]; 2740efee3746SRichard Henderson op->args[1] = op->args[2]; 2741efee3746SRichard Henderson op->args[2] = op->args[3]; 274203271524SRichard Henderson } else { 274303271524SRichard Henderson goto do_not_remove; 274403271524SRichard Henderson } 274503271524SRichard Henderson /* Mark the single-word operation live. */ 27461414968aSRichard Henderson nb_oargs = 1; 27471414968aSRichard Henderson goto do_not_remove; 27481414968aSRichard Henderson 2749c896fe29Sbellard default: 27501305c451SRichard Henderson /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */ 2751c896fe29Sbellard nb_iargs = def->nb_iargs; 2752c896fe29Sbellard nb_oargs = def->nb_oargs; 2753c896fe29Sbellard 2754c896fe29Sbellard /* Test if the operation can be removed because all 27555ff9d6a4Sbellard its outputs are dead. We assume that nb_oargs == 0 27565ff9d6a4Sbellard implies side effects */ 27575ff9d6a4Sbellard if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) { 2758c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 2759b83eabeaSRichard Henderson if (arg_temp(op->args[i])->state != TS_DEAD) { 2760c896fe29Sbellard goto do_not_remove; 2761c896fe29Sbellard } 27629c43b68dSAurelien Jarno } 2763152c35aaSRichard Henderson goto do_remove; 2764152c35aaSRichard Henderson } 2765152c35aaSRichard Henderson goto do_not_remove; 2766152c35aaSRichard Henderson 27671305c451SRichard Henderson do_remove: 27680c627cdcSRichard Henderson tcg_op_remove(s, op); 2769152c35aaSRichard Henderson break; 2770152c35aaSRichard Henderson 2771c896fe29Sbellard do_not_remove: 2772c896fe29Sbellard for (i = 0; i < nb_oargs; i++) { 277325f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 277425f49c5fSRichard Henderson 277525f49c5fSRichard Henderson /* Remember the preference of the uses that followed. */ 277625f49c5fSRichard Henderson op->output_pref[i] = *la_temp_pref(ts); 277725f49c5fSRichard Henderson 277825f49c5fSRichard Henderson /* Output args are dead. */ 277925f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 2780a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 27816b64b624SAurelien Jarno } 278225f49c5fSRichard Henderson if (ts->state & TS_MEM) { 2783a1b3c48dSRichard Henderson arg_life |= SYNC_ARG << i; 27849c43b68dSAurelien Jarno } 278525f49c5fSRichard Henderson ts->state = TS_DEAD; 278625f49c5fSRichard Henderson la_reset_pref(ts); 2787c896fe29Sbellard } 2788c896fe29Sbellard 278925f49c5fSRichard Henderson /* If end of basic block, update. */ 2790ae36a246SRichard Henderson if (def->flags & TCG_OPF_BB_EXIT) { 2791ae36a246SRichard Henderson la_func_end(s, nb_globals, nb_temps); 2792ae36a246SRichard Henderson } else if (def->flags & TCG_OPF_BB_END) { 27932616c808SRichard Henderson la_bb_end(s, nb_globals, nb_temps); 27943d5c5f87SAurelien Jarno } else if (def->flags & TCG_OPF_SIDE_EFFECTS) { 2795f65a061cSRichard Henderson la_global_sync(s, nb_globals); 279625f49c5fSRichard Henderson if (def->flags & TCG_OPF_CALL_CLOBBER) { 279725f49c5fSRichard Henderson la_cross_call(s, nb_temps); 279825f49c5fSRichard Henderson } 2799c896fe29Sbellard } 2800c896fe29Sbellard 280125f49c5fSRichard Henderson /* Record arguments that die in this opcode. */ 2802866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 280325f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 280425f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 2805a1b3c48dSRichard Henderson arg_life |= DEAD_ARG << i; 2806c896fe29Sbellard } 2807c19f47bfSAurelien Jarno } 280825f49c5fSRichard Henderson 280925f49c5fSRichard Henderson /* Input arguments are live for preceding opcodes. */ 2810c19f47bfSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 281125f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 281225f49c5fSRichard Henderson if (ts->state & TS_DEAD) { 281325f49c5fSRichard Henderson /* For operands that were dead, initially allow 281425f49c5fSRichard Henderson all regs for the type. */ 281525f49c5fSRichard Henderson *la_temp_pref(ts) = tcg_target_available_regs[ts->type]; 281625f49c5fSRichard Henderson ts->state &= ~TS_DEAD; 281725f49c5fSRichard Henderson } 281825f49c5fSRichard Henderson } 281925f49c5fSRichard Henderson 282025f49c5fSRichard Henderson /* Incorporate constraints for this operand. */ 282125f49c5fSRichard Henderson switch (opc) { 282225f49c5fSRichard Henderson case INDEX_op_mov_i32: 282325f49c5fSRichard Henderson case INDEX_op_mov_i64: 282425f49c5fSRichard Henderson /* Note that these are TCG_OPF_NOT_PRESENT and do not 282525f49c5fSRichard Henderson have proper constraints. That said, special case 282625f49c5fSRichard Henderson moves to propagate preferences backward. */ 282725f49c5fSRichard Henderson if (IS_DEAD_ARG(1)) { 282825f49c5fSRichard Henderson *la_temp_pref(arg_temp(op->args[0])) 282925f49c5fSRichard Henderson = *la_temp_pref(arg_temp(op->args[1])); 283025f49c5fSRichard Henderson } 283125f49c5fSRichard Henderson break; 283225f49c5fSRichard Henderson 283325f49c5fSRichard Henderson default: 283425f49c5fSRichard Henderson for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 283525f49c5fSRichard Henderson const TCGArgConstraint *ct = &def->args_ct[i]; 283625f49c5fSRichard Henderson TCGRegSet set, *pset; 283725f49c5fSRichard Henderson 283825f49c5fSRichard Henderson ts = arg_temp(op->args[i]); 283925f49c5fSRichard Henderson pset = la_temp_pref(ts); 284025f49c5fSRichard Henderson set = *pset; 284125f49c5fSRichard Henderson 284225f49c5fSRichard Henderson set &= ct->u.regs; 284325f49c5fSRichard Henderson if (ct->ct & TCG_CT_IALIAS) { 284425f49c5fSRichard Henderson set &= op->output_pref[ct->alias_index]; 284525f49c5fSRichard Henderson } 284625f49c5fSRichard Henderson /* If the combination is not possible, restart. */ 284725f49c5fSRichard Henderson if (set == 0) { 284825f49c5fSRichard Henderson set = ct->u.regs; 284925f49c5fSRichard Henderson } 285025f49c5fSRichard Henderson *pset = set; 285125f49c5fSRichard Henderson } 285225f49c5fSRichard Henderson break; 2853c896fe29Sbellard } 2854c896fe29Sbellard break; 2855c896fe29Sbellard } 2856bee158cbSRichard Henderson op->life = arg_life; 2857c896fe29Sbellard } 28581ff0a2c5SEvgeny Voevodin } 2859c896fe29Sbellard 28605a18407fSRichard Henderson /* Liveness analysis: Convert indirect regs to direct temporaries. */ 2861b83eabeaSRichard Henderson static bool liveness_pass_2(TCGContext *s) 28625a18407fSRichard Henderson { 28635a18407fSRichard Henderson int nb_globals = s->nb_globals; 286415fa08f8SRichard Henderson int nb_temps, i; 28655a18407fSRichard Henderson bool changes = false; 286615fa08f8SRichard Henderson TCGOp *op, *op_next; 28675a18407fSRichard Henderson 28685a18407fSRichard Henderson /* Create a temporary for each indirect global. */ 28695a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) { 28705a18407fSRichard Henderson TCGTemp *its = &s->temps[i]; 28715a18407fSRichard Henderson if (its->indirect_reg) { 28725a18407fSRichard Henderson TCGTemp *dts = tcg_temp_alloc(s); 28735a18407fSRichard Henderson dts->type = its->type; 28745a18407fSRichard Henderson dts->base_type = its->base_type; 2875b83eabeaSRichard Henderson its->state_ptr = dts; 2876b83eabeaSRichard Henderson } else { 2877b83eabeaSRichard Henderson its->state_ptr = NULL; 28785a18407fSRichard Henderson } 2879b83eabeaSRichard Henderson /* All globals begin dead. */ 2880b83eabeaSRichard Henderson its->state = TS_DEAD; 28815a18407fSRichard Henderson } 2882b83eabeaSRichard Henderson for (nb_temps = s->nb_temps; i < nb_temps; ++i) { 2883b83eabeaSRichard Henderson TCGTemp *its = &s->temps[i]; 2884b83eabeaSRichard Henderson its->state_ptr = NULL; 2885b83eabeaSRichard Henderson its->state = TS_DEAD; 2886b83eabeaSRichard Henderson } 28875a18407fSRichard Henderson 288815fa08f8SRichard Henderson QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) { 28895a18407fSRichard Henderson TCGOpcode opc = op->opc; 28905a18407fSRichard Henderson const TCGOpDef *def = &tcg_op_defs[opc]; 28915a18407fSRichard Henderson TCGLifeData arg_life = op->life; 28925a18407fSRichard Henderson int nb_iargs, nb_oargs, call_flags; 2893b83eabeaSRichard Henderson TCGTemp *arg_ts, *dir_ts; 28945a18407fSRichard Henderson 28955a18407fSRichard Henderson if (opc == INDEX_op_call) { 2896cd9090aaSRichard Henderson nb_oargs = TCGOP_CALLO(op); 2897cd9090aaSRichard Henderson nb_iargs = TCGOP_CALLI(op); 2898efee3746SRichard Henderson call_flags = op->args[nb_oargs + nb_iargs + 1]; 28995a18407fSRichard Henderson } else { 29005a18407fSRichard Henderson nb_iargs = def->nb_iargs; 29015a18407fSRichard Henderson nb_oargs = def->nb_oargs; 29025a18407fSRichard Henderson 29035a18407fSRichard Henderson /* Set flags similar to how calls require. */ 29045a18407fSRichard Henderson if (def->flags & TCG_OPF_BB_END) { 29055a18407fSRichard Henderson /* Like writing globals: save_globals */ 29065a18407fSRichard Henderson call_flags = 0; 29075a18407fSRichard Henderson } else if (def->flags & TCG_OPF_SIDE_EFFECTS) { 29085a18407fSRichard Henderson /* Like reading globals: sync_globals */ 29095a18407fSRichard Henderson call_flags = TCG_CALL_NO_WRITE_GLOBALS; 29105a18407fSRichard Henderson } else { 29115a18407fSRichard Henderson /* No effect on globals. */ 29125a18407fSRichard Henderson call_flags = (TCG_CALL_NO_READ_GLOBALS | 29135a18407fSRichard Henderson TCG_CALL_NO_WRITE_GLOBALS); 29145a18407fSRichard Henderson } 29155a18407fSRichard Henderson } 29165a18407fSRichard Henderson 29175a18407fSRichard Henderson /* Make sure that input arguments are available. */ 29185a18407fSRichard Henderson for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 2919b83eabeaSRichard Henderson arg_ts = arg_temp(op->args[i]); 2920b83eabeaSRichard Henderson if (arg_ts) { 2921b83eabeaSRichard Henderson dir_ts = arg_ts->state_ptr; 2922b83eabeaSRichard Henderson if (dir_ts && arg_ts->state == TS_DEAD) { 2923b83eabeaSRichard Henderson TCGOpcode lopc = (arg_ts->type == TCG_TYPE_I32 29245a18407fSRichard Henderson ? INDEX_op_ld_i32 29255a18407fSRichard Henderson : INDEX_op_ld_i64); 2926ac1043f6SEmilio G. Cota TCGOp *lop = tcg_op_insert_before(s, op, lopc); 29275a18407fSRichard Henderson 2928b83eabeaSRichard Henderson lop->args[0] = temp_arg(dir_ts); 2929b83eabeaSRichard Henderson lop->args[1] = temp_arg(arg_ts->mem_base); 2930b83eabeaSRichard Henderson lop->args[2] = arg_ts->mem_offset; 29315a18407fSRichard Henderson 29325a18407fSRichard Henderson /* Loaded, but synced with memory. */ 2933b83eabeaSRichard Henderson arg_ts->state = TS_MEM; 29345a18407fSRichard Henderson } 29355a18407fSRichard Henderson } 29365a18407fSRichard Henderson } 29375a18407fSRichard Henderson 29385a18407fSRichard Henderson /* Perform input replacement, and mark inputs that became dead. 29395a18407fSRichard Henderson No action is required except keeping temp_state up to date 29405a18407fSRichard Henderson so that we reload when needed. */ 29415a18407fSRichard Henderson for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 2942b83eabeaSRichard Henderson arg_ts = arg_temp(op->args[i]); 2943b83eabeaSRichard Henderson if (arg_ts) { 2944b83eabeaSRichard Henderson dir_ts = arg_ts->state_ptr; 2945b83eabeaSRichard Henderson if (dir_ts) { 2946b83eabeaSRichard Henderson op->args[i] = temp_arg(dir_ts); 29475a18407fSRichard Henderson changes = true; 29485a18407fSRichard Henderson if (IS_DEAD_ARG(i)) { 2949b83eabeaSRichard Henderson arg_ts->state = TS_DEAD; 29505a18407fSRichard Henderson } 29515a18407fSRichard Henderson } 29525a18407fSRichard Henderson } 29535a18407fSRichard Henderson } 29545a18407fSRichard Henderson 29555a18407fSRichard Henderson /* Liveness analysis should ensure that the following are 29565a18407fSRichard Henderson all correct, for call sites and basic block end points. */ 29575a18407fSRichard Henderson if (call_flags & TCG_CALL_NO_READ_GLOBALS) { 29585a18407fSRichard Henderson /* Nothing to do */ 29595a18407fSRichard Henderson } else if (call_flags & TCG_CALL_NO_WRITE_GLOBALS) { 29605a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) { 29615a18407fSRichard Henderson /* Liveness should see that globals are synced back, 29625a18407fSRichard Henderson that is, either TS_DEAD or TS_MEM. */ 2963b83eabeaSRichard Henderson arg_ts = &s->temps[i]; 2964b83eabeaSRichard Henderson tcg_debug_assert(arg_ts->state_ptr == 0 2965b83eabeaSRichard Henderson || arg_ts->state != 0); 29665a18407fSRichard Henderson } 29675a18407fSRichard Henderson } else { 29685a18407fSRichard Henderson for (i = 0; i < nb_globals; ++i) { 29695a18407fSRichard Henderson /* Liveness should see that globals are saved back, 29705a18407fSRichard Henderson that is, TS_DEAD, waiting to be reloaded. */ 2971b83eabeaSRichard Henderson arg_ts = &s->temps[i]; 2972b83eabeaSRichard Henderson tcg_debug_assert(arg_ts->state_ptr == 0 2973b83eabeaSRichard Henderson || arg_ts->state == TS_DEAD); 29745a18407fSRichard Henderson } 29755a18407fSRichard Henderson } 29765a18407fSRichard Henderson 29775a18407fSRichard Henderson /* Outputs become available. */ 29785a18407fSRichard Henderson for (i = 0; i < nb_oargs; i++) { 2979b83eabeaSRichard Henderson arg_ts = arg_temp(op->args[i]); 2980b83eabeaSRichard Henderson dir_ts = arg_ts->state_ptr; 2981b83eabeaSRichard Henderson if (!dir_ts) { 29825a18407fSRichard Henderson continue; 29835a18407fSRichard Henderson } 2984b83eabeaSRichard Henderson op->args[i] = temp_arg(dir_ts); 29855a18407fSRichard Henderson changes = true; 29865a18407fSRichard Henderson 29875a18407fSRichard Henderson /* The output is now live and modified. */ 2988b83eabeaSRichard Henderson arg_ts->state = 0; 29895a18407fSRichard Henderson 29905a18407fSRichard Henderson /* Sync outputs upon their last write. */ 29915a18407fSRichard Henderson if (NEED_SYNC_ARG(i)) { 2992b83eabeaSRichard Henderson TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32 29935a18407fSRichard Henderson ? INDEX_op_st_i32 29945a18407fSRichard Henderson : INDEX_op_st_i64); 2995ac1043f6SEmilio G. Cota TCGOp *sop = tcg_op_insert_after(s, op, sopc); 29965a18407fSRichard Henderson 2997b83eabeaSRichard Henderson sop->args[0] = temp_arg(dir_ts); 2998b83eabeaSRichard Henderson sop->args[1] = temp_arg(arg_ts->mem_base); 2999b83eabeaSRichard Henderson sop->args[2] = arg_ts->mem_offset; 30005a18407fSRichard Henderson 3001b83eabeaSRichard Henderson arg_ts->state = TS_MEM; 30025a18407fSRichard Henderson } 30035a18407fSRichard Henderson /* Drop outputs that are dead. */ 30045a18407fSRichard Henderson if (IS_DEAD_ARG(i)) { 3005b83eabeaSRichard Henderson arg_ts->state = TS_DEAD; 30065a18407fSRichard Henderson } 30075a18407fSRichard Henderson } 30085a18407fSRichard Henderson } 30095a18407fSRichard Henderson 30105a18407fSRichard Henderson return changes; 30115a18407fSRichard Henderson } 30125a18407fSRichard Henderson 30138d8fdbaeSAurelien Jarno #ifdef CONFIG_DEBUG_TCG 3014c896fe29Sbellard static void dump_regs(TCGContext *s) 3015c896fe29Sbellard { 3016c896fe29Sbellard TCGTemp *ts; 3017c896fe29Sbellard int i; 3018c896fe29Sbellard char buf[64]; 3019c896fe29Sbellard 3020c896fe29Sbellard for(i = 0; i < s->nb_temps; i++) { 3021c896fe29Sbellard ts = &s->temps[i]; 302243439139SRichard Henderson printf(" %10s: ", tcg_get_arg_str_ptr(s, buf, sizeof(buf), ts)); 3023c896fe29Sbellard switch(ts->val_type) { 3024c896fe29Sbellard case TEMP_VAL_REG: 3025c896fe29Sbellard printf("%s", tcg_target_reg_names[ts->reg]); 3026c896fe29Sbellard break; 3027c896fe29Sbellard case TEMP_VAL_MEM: 3028b3a62939SRichard Henderson printf("%d(%s)", (int)ts->mem_offset, 3029b3a62939SRichard Henderson tcg_target_reg_names[ts->mem_base->reg]); 3030c896fe29Sbellard break; 3031c896fe29Sbellard case TEMP_VAL_CONST: 3032c896fe29Sbellard printf("$0x%" TCG_PRIlx, ts->val); 3033c896fe29Sbellard break; 3034c896fe29Sbellard case TEMP_VAL_DEAD: 3035c896fe29Sbellard printf("D"); 3036c896fe29Sbellard break; 3037c896fe29Sbellard default: 3038c896fe29Sbellard printf("???"); 3039c896fe29Sbellard break; 3040c896fe29Sbellard } 3041c896fe29Sbellard printf("\n"); 3042c896fe29Sbellard } 3043c896fe29Sbellard 3044c896fe29Sbellard for(i = 0; i < TCG_TARGET_NB_REGS; i++) { 3045f8b2f202SRichard Henderson if (s->reg_to_temp[i] != NULL) { 3046c896fe29Sbellard printf("%s: %s\n", 3047c896fe29Sbellard tcg_target_reg_names[i], 3048f8b2f202SRichard Henderson tcg_get_arg_str_ptr(s, buf, sizeof(buf), s->reg_to_temp[i])); 3049c896fe29Sbellard } 3050c896fe29Sbellard } 3051c896fe29Sbellard } 3052c896fe29Sbellard 3053c896fe29Sbellard static void check_regs(TCGContext *s) 3054c896fe29Sbellard { 3055869938aeSRichard Henderson int reg; 3056b6638662SRichard Henderson int k; 3057c896fe29Sbellard TCGTemp *ts; 3058c896fe29Sbellard char buf[64]; 3059c896fe29Sbellard 3060c896fe29Sbellard for (reg = 0; reg < TCG_TARGET_NB_REGS; reg++) { 3061f8b2f202SRichard Henderson ts = s->reg_to_temp[reg]; 3062f8b2f202SRichard Henderson if (ts != NULL) { 3063f8b2f202SRichard Henderson if (ts->val_type != TEMP_VAL_REG || ts->reg != reg) { 3064c896fe29Sbellard printf("Inconsistency for register %s:\n", 3065c896fe29Sbellard tcg_target_reg_names[reg]); 3066b03cce8eSbellard goto fail; 3067c896fe29Sbellard } 3068c896fe29Sbellard } 3069c896fe29Sbellard } 3070c896fe29Sbellard for (k = 0; k < s->nb_temps; k++) { 3071c896fe29Sbellard ts = &s->temps[k]; 3072f8b2f202SRichard Henderson if (ts->val_type == TEMP_VAL_REG && !ts->fixed_reg 3073f8b2f202SRichard Henderson && s->reg_to_temp[ts->reg] != ts) { 3074c896fe29Sbellard printf("Inconsistency for temp %s:\n", 3075f8b2f202SRichard Henderson tcg_get_arg_str_ptr(s, buf, sizeof(buf), ts)); 3076b03cce8eSbellard fail: 3077c896fe29Sbellard printf("reg state:\n"); 3078c896fe29Sbellard dump_regs(s); 3079c896fe29Sbellard tcg_abort(); 3080c896fe29Sbellard } 3081c896fe29Sbellard } 3082c896fe29Sbellard } 3083c896fe29Sbellard #endif 3084c896fe29Sbellard 30852272e4a7SRichard Henderson static void temp_allocate_frame(TCGContext *s, TCGTemp *ts) 3086c896fe29Sbellard { 30879b9c37c3SRichard Henderson #if !(defined(__sparc__) && TCG_TARGET_REG_BITS == 64) 30889b9c37c3SRichard Henderson /* Sparc64 stack is accessed with offset of 2047 */ 3089b591dc59SBlue Swirl s->current_frame_offset = (s->current_frame_offset + 3090b591dc59SBlue Swirl (tcg_target_long)sizeof(tcg_target_long) - 1) & 3091b591dc59SBlue Swirl ~(sizeof(tcg_target_long) - 1); 3092f44c9960SBlue Swirl #endif 3093b591dc59SBlue Swirl if (s->current_frame_offset + (tcg_target_long)sizeof(tcg_target_long) > 3094b591dc59SBlue Swirl s->frame_end) { 30955ff9d6a4Sbellard tcg_abort(); 3096b591dc59SBlue Swirl } 3097c896fe29Sbellard ts->mem_offset = s->current_frame_offset; 3098b3a62939SRichard Henderson ts->mem_base = s->frame_temp; 3099c896fe29Sbellard ts->mem_allocated = 1; 3100e2c6d1b4SRichard Henderson s->current_frame_offset += sizeof(tcg_target_long); 3101c896fe29Sbellard } 3102c896fe29Sbellard 3103b722452aSRichard Henderson static void temp_load(TCGContext *, TCGTemp *, TCGRegSet, TCGRegSet, TCGRegSet); 3104b3915dbbSRichard Henderson 310559d7c14eSRichard Henderson /* Mark a temporary as free or dead. If 'free_or_dead' is negative, 310659d7c14eSRichard Henderson mark it free; otherwise mark it dead. */ 310759d7c14eSRichard Henderson static void temp_free_or_dead(TCGContext *s, TCGTemp *ts, int free_or_dead) 3108c896fe29Sbellard { 310959d7c14eSRichard Henderson if (ts->fixed_reg) { 311059d7c14eSRichard Henderson return; 311159d7c14eSRichard Henderson } 311259d7c14eSRichard Henderson if (ts->val_type == TEMP_VAL_REG) { 311359d7c14eSRichard Henderson s->reg_to_temp[ts->reg] = NULL; 311459d7c14eSRichard Henderson } 311559d7c14eSRichard Henderson ts->val_type = (free_or_dead < 0 311659d7c14eSRichard Henderson || ts->temp_local 3117fa477d25SRichard Henderson || ts->temp_global 311859d7c14eSRichard Henderson ? TEMP_VAL_MEM : TEMP_VAL_DEAD); 311959d7c14eSRichard Henderson } 3120c896fe29Sbellard 312159d7c14eSRichard Henderson /* Mark a temporary as dead. */ 312259d7c14eSRichard Henderson static inline void temp_dead(TCGContext *s, TCGTemp *ts) 312359d7c14eSRichard Henderson { 312459d7c14eSRichard Henderson temp_free_or_dead(s, ts, 1); 312559d7c14eSRichard Henderson } 312659d7c14eSRichard Henderson 312759d7c14eSRichard Henderson /* Sync a temporary to memory. 'allocated_regs' is used in case a temporary 312859d7c14eSRichard Henderson registers needs to be allocated to store a constant. If 'free_or_dead' 312959d7c14eSRichard Henderson is non-zero, subsequently release the temporary; if it is positive, the 313059d7c14eSRichard Henderson temp is dead; if it is negative, the temp is free. */ 313198b4e186SRichard Henderson static void temp_sync(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs, 313298b4e186SRichard Henderson TCGRegSet preferred_regs, int free_or_dead) 313359d7c14eSRichard Henderson { 313459d7c14eSRichard Henderson if (ts->fixed_reg) { 313559d7c14eSRichard Henderson return; 313659d7c14eSRichard Henderson } 313759d7c14eSRichard Henderson if (!ts->mem_coherent) { 31387f6ceedfSAurelien Jarno if (!ts->mem_allocated) { 31392272e4a7SRichard Henderson temp_allocate_frame(s, ts); 314059d7c14eSRichard Henderson } 314159d7c14eSRichard Henderson switch (ts->val_type) { 314259d7c14eSRichard Henderson case TEMP_VAL_CONST: 314359d7c14eSRichard Henderson /* If we're going to free the temp immediately, then we won't 314459d7c14eSRichard Henderson require it later in a register, so attempt to store the 314559d7c14eSRichard Henderson constant to memory directly. */ 314659d7c14eSRichard Henderson if (free_or_dead 314759d7c14eSRichard Henderson && tcg_out_sti(s, ts->type, ts->val, 314859d7c14eSRichard Henderson ts->mem_base->reg, ts->mem_offset)) { 314959d7c14eSRichard Henderson break; 315059d7c14eSRichard Henderson } 315159d7c14eSRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], 315298b4e186SRichard Henderson allocated_regs, preferred_regs); 315359d7c14eSRichard Henderson /* fallthrough */ 315459d7c14eSRichard Henderson 315559d7c14eSRichard Henderson case TEMP_VAL_REG: 315659d7c14eSRichard Henderson tcg_out_st(s, ts->type, ts->reg, 315759d7c14eSRichard Henderson ts->mem_base->reg, ts->mem_offset); 315859d7c14eSRichard Henderson break; 315959d7c14eSRichard Henderson 316059d7c14eSRichard Henderson case TEMP_VAL_MEM: 316159d7c14eSRichard Henderson break; 316259d7c14eSRichard Henderson 316359d7c14eSRichard Henderson case TEMP_VAL_DEAD: 316459d7c14eSRichard Henderson default: 316559d7c14eSRichard Henderson tcg_abort(); 3166c896fe29Sbellard } 31677f6ceedfSAurelien Jarno ts->mem_coherent = 1; 31687f6ceedfSAurelien Jarno } 316959d7c14eSRichard Henderson if (free_or_dead) { 317059d7c14eSRichard Henderson temp_free_or_dead(s, ts, free_or_dead); 317159d7c14eSRichard Henderson } 317259d7c14eSRichard Henderson } 31737f6ceedfSAurelien Jarno 31747f6ceedfSAurelien Jarno /* free register 'reg' by spilling the corresponding temporary if necessary */ 3175b3915dbbSRichard Henderson static void tcg_reg_free(TCGContext *s, TCGReg reg, TCGRegSet allocated_regs) 31767f6ceedfSAurelien Jarno { 3177f8b2f202SRichard Henderson TCGTemp *ts = s->reg_to_temp[reg]; 3178f8b2f202SRichard Henderson if (ts != NULL) { 317998b4e186SRichard Henderson temp_sync(s, ts, allocated_regs, 0, -1); 3180c896fe29Sbellard } 3181c896fe29Sbellard } 3182c896fe29Sbellard 3183b016486eSRichard Henderson /** 3184b016486eSRichard Henderson * tcg_reg_alloc: 3185b016486eSRichard Henderson * @required_regs: Set of registers in which we must allocate. 3186b016486eSRichard Henderson * @allocated_regs: Set of registers which must be avoided. 3187b016486eSRichard Henderson * @preferred_regs: Set of registers we should prefer. 3188b016486eSRichard Henderson * @rev: True if we search the registers in "indirect" order. 3189b016486eSRichard Henderson * 3190b016486eSRichard Henderson * The allocated register must be in @required_regs & ~@allocated_regs, 3191b016486eSRichard Henderson * but if we can put it in @preferred_regs we may save a move later. 3192b016486eSRichard Henderson */ 3193b016486eSRichard Henderson static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet required_regs, 3194b016486eSRichard Henderson TCGRegSet allocated_regs, 3195b016486eSRichard Henderson TCGRegSet preferred_regs, bool rev) 3196c896fe29Sbellard { 3197b016486eSRichard Henderson int i, j, f, n = ARRAY_SIZE(tcg_target_reg_alloc_order); 3198b016486eSRichard Henderson TCGRegSet reg_ct[2]; 319991478cefSRichard Henderson const int *order; 3200c896fe29Sbellard 3201b016486eSRichard Henderson reg_ct[1] = required_regs & ~allocated_regs; 3202b016486eSRichard Henderson tcg_debug_assert(reg_ct[1] != 0); 3203b016486eSRichard Henderson reg_ct[0] = reg_ct[1] & preferred_regs; 3204b016486eSRichard Henderson 3205b016486eSRichard Henderson /* Skip the preferred_regs option if it cannot be satisfied, 3206b016486eSRichard Henderson or if the preference made no difference. */ 3207b016486eSRichard Henderson f = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1]; 3208b016486eSRichard Henderson 320991478cefSRichard Henderson order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order; 3210c896fe29Sbellard 3211b016486eSRichard Henderson /* Try free registers, preferences first. */ 3212b016486eSRichard Henderson for (j = f; j < 2; j++) { 3213b016486eSRichard Henderson TCGRegSet set = reg_ct[j]; 3214b016486eSRichard Henderson 3215b016486eSRichard Henderson if (tcg_regset_single(set)) { 3216b016486eSRichard Henderson /* One register in the set. */ 3217b016486eSRichard Henderson TCGReg reg = tcg_regset_first(set); 3218b016486eSRichard Henderson if (s->reg_to_temp[reg] == NULL) { 3219c896fe29Sbellard return reg; 3220c896fe29Sbellard } 3221b016486eSRichard Henderson } else { 322291478cefSRichard Henderson for (i = 0; i < n; i++) { 3223b016486eSRichard Henderson TCGReg reg = order[i]; 3224b016486eSRichard Henderson if (s->reg_to_temp[reg] == NULL && 3225b016486eSRichard Henderson tcg_regset_test_reg(set, reg)) { 3226b016486eSRichard Henderson return reg; 3227b016486eSRichard Henderson } 3228b016486eSRichard Henderson } 3229b016486eSRichard Henderson } 3230b016486eSRichard Henderson } 3231b016486eSRichard Henderson 3232b016486eSRichard Henderson /* We must spill something. */ 3233b016486eSRichard Henderson for (j = f; j < 2; j++) { 3234b016486eSRichard Henderson TCGRegSet set = reg_ct[j]; 3235b016486eSRichard Henderson 3236b016486eSRichard Henderson if (tcg_regset_single(set)) { 3237b016486eSRichard Henderson /* One register in the set. */ 3238b016486eSRichard Henderson TCGReg reg = tcg_regset_first(set); 3239b3915dbbSRichard Henderson tcg_reg_free(s, reg, allocated_regs); 3240c896fe29Sbellard return reg; 3241b016486eSRichard Henderson } else { 3242b016486eSRichard Henderson for (i = 0; i < n; i++) { 3243b016486eSRichard Henderson TCGReg reg = order[i]; 3244b016486eSRichard Henderson if (tcg_regset_test_reg(set, reg)) { 3245b016486eSRichard Henderson tcg_reg_free(s, reg, allocated_regs); 3246b016486eSRichard Henderson return reg; 3247b016486eSRichard Henderson } 3248b016486eSRichard Henderson } 3249c896fe29Sbellard } 3250c896fe29Sbellard } 3251c896fe29Sbellard 3252c896fe29Sbellard tcg_abort(); 3253c896fe29Sbellard } 3254c896fe29Sbellard 325540ae5c62SRichard Henderson /* Make sure the temporary is in a register. If needed, allocate the register 325640ae5c62SRichard Henderson from DESIRED while avoiding ALLOCATED. */ 325740ae5c62SRichard Henderson static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs, 3258b722452aSRichard Henderson TCGRegSet allocated_regs, TCGRegSet preferred_regs) 325940ae5c62SRichard Henderson { 326040ae5c62SRichard Henderson TCGReg reg; 326140ae5c62SRichard Henderson 326240ae5c62SRichard Henderson switch (ts->val_type) { 326340ae5c62SRichard Henderson case TEMP_VAL_REG: 326440ae5c62SRichard Henderson return; 326540ae5c62SRichard Henderson case TEMP_VAL_CONST: 3266b016486eSRichard Henderson reg = tcg_reg_alloc(s, desired_regs, allocated_regs, 3267b722452aSRichard Henderson preferred_regs, ts->indirect_base); 326840ae5c62SRichard Henderson tcg_out_movi(s, ts->type, reg, ts->val); 326940ae5c62SRichard Henderson ts->mem_coherent = 0; 327040ae5c62SRichard Henderson break; 327140ae5c62SRichard Henderson case TEMP_VAL_MEM: 3272b016486eSRichard Henderson reg = tcg_reg_alloc(s, desired_regs, allocated_regs, 3273b722452aSRichard Henderson preferred_regs, ts->indirect_base); 327440ae5c62SRichard Henderson tcg_out_ld(s, ts->type, reg, ts->mem_base->reg, ts->mem_offset); 327540ae5c62SRichard Henderson ts->mem_coherent = 1; 327640ae5c62SRichard Henderson break; 327740ae5c62SRichard Henderson case TEMP_VAL_DEAD: 327840ae5c62SRichard Henderson default: 327940ae5c62SRichard Henderson tcg_abort(); 328040ae5c62SRichard Henderson } 328140ae5c62SRichard Henderson ts->reg = reg; 328240ae5c62SRichard Henderson ts->val_type = TEMP_VAL_REG; 328340ae5c62SRichard Henderson s->reg_to_temp[reg] = ts; 328440ae5c62SRichard Henderson } 328540ae5c62SRichard Henderson 328659d7c14eSRichard Henderson /* Save a temporary to memory. 'allocated_regs' is used in case a 3287e8996ee0Sbellard temporary registers needs to be allocated to store a constant. */ 328859d7c14eSRichard Henderson static void temp_save(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs) 32891ad80729SAurelien Jarno { 32902c0366f0SAurelien Jarno /* The liveness analysis already ensures that globals are back 3291eabb7b91SAurelien Jarno in memory. Keep an tcg_debug_assert for safety. */ 3292f8bf00f1SRichard Henderson tcg_debug_assert(ts->val_type == TEMP_VAL_MEM || ts->fixed_reg); 32931ad80729SAurelien Jarno } 32941ad80729SAurelien Jarno 32959814dd27SDong Xu Wang /* save globals to their canonical location and assume they can be 3296641d5fbeSbellard modified be the following code. 'allocated_regs' is used in case a 3297641d5fbeSbellard temporary registers needs to be allocated to store a constant. */ 3298641d5fbeSbellard static void save_globals(TCGContext *s, TCGRegSet allocated_regs) 3299641d5fbeSbellard { 3300ac3b8891SRichard Henderson int i, n; 3301641d5fbeSbellard 3302ac3b8891SRichard Henderson for (i = 0, n = s->nb_globals; i < n; i++) { 3303b13eb728SRichard Henderson temp_save(s, &s->temps[i], allocated_regs); 3304641d5fbeSbellard } 3305e5097dc8Sbellard } 3306e5097dc8Sbellard 33073d5c5f87SAurelien Jarno /* sync globals to their canonical location and assume they can be 33083d5c5f87SAurelien Jarno read by the following code. 'allocated_regs' is used in case a 33093d5c5f87SAurelien Jarno temporary registers needs to be allocated to store a constant. */ 33103d5c5f87SAurelien Jarno static void sync_globals(TCGContext *s, TCGRegSet allocated_regs) 33113d5c5f87SAurelien Jarno { 3312ac3b8891SRichard Henderson int i, n; 33133d5c5f87SAurelien Jarno 3314ac3b8891SRichard Henderson for (i = 0, n = s->nb_globals; i < n; i++) { 331512b9b11aSRichard Henderson TCGTemp *ts = &s->temps[i]; 331612b9b11aSRichard Henderson tcg_debug_assert(ts->val_type != TEMP_VAL_REG 331712b9b11aSRichard Henderson || ts->fixed_reg 331812b9b11aSRichard Henderson || ts->mem_coherent); 33193d5c5f87SAurelien Jarno } 33203d5c5f87SAurelien Jarno } 33213d5c5f87SAurelien Jarno 3322e5097dc8Sbellard /* at the end of a basic block, we assume all temporaries are dead and 3323e8996ee0Sbellard all globals are stored at their canonical location. */ 3324e8996ee0Sbellard static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs) 3325e5097dc8Sbellard { 3326e5097dc8Sbellard int i; 3327e5097dc8Sbellard 3328c896fe29Sbellard for (i = s->nb_globals; i < s->nb_temps; i++) { 3329b13eb728SRichard Henderson TCGTemp *ts = &s->temps[i]; 3330641d5fbeSbellard if (ts->temp_local) { 3331b13eb728SRichard Henderson temp_save(s, ts, allocated_regs); 3332641d5fbeSbellard } else { 33332c0366f0SAurelien Jarno /* The liveness analysis already ensures that temps are dead. 3334eabb7b91SAurelien Jarno Keep an tcg_debug_assert for safety. */ 3335eabb7b91SAurelien Jarno tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD); 3336c896fe29Sbellard } 3337641d5fbeSbellard } 3338e8996ee0Sbellard 3339e8996ee0Sbellard save_globals(s, allocated_regs); 3340c896fe29Sbellard } 3341c896fe29Sbellard 3342bab1671fSRichard Henderson /* 3343bab1671fSRichard Henderson * Specialized code generation for INDEX_op_movi_*. 3344bab1671fSRichard Henderson */ 33450fe4fca4SPaolo Bonzini static void tcg_reg_alloc_do_movi(TCGContext *s, TCGTemp *ots, 3346ba87719cSRichard Henderson tcg_target_ulong val, TCGLifeData arg_life, 3347ba87719cSRichard Henderson TCGRegSet preferred_regs) 3348e8996ee0Sbellard { 3349d63e3b6eSRichard Henderson /* ENV should not be modified. */ 3350d63e3b6eSRichard Henderson tcg_debug_assert(!ots->fixed_reg); 335159d7c14eSRichard Henderson 335259d7c14eSRichard Henderson /* The movi is not explicitly generated here. */ 3353f8b2f202SRichard Henderson if (ots->val_type == TEMP_VAL_REG) { 3354f8b2f202SRichard Henderson s->reg_to_temp[ots->reg] = NULL; 3355f8b2f202SRichard Henderson } 3356e8996ee0Sbellard ots->val_type = TEMP_VAL_CONST; 3357e8996ee0Sbellard ots->val = val; 335859d7c14eSRichard Henderson ots->mem_coherent = 0; 3359ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(0)) { 3360ba87719cSRichard Henderson temp_sync(s, ots, s->reserved_regs, preferred_regs, IS_DEAD_ARG(0)); 336159d7c14eSRichard Henderson } else if (IS_DEAD_ARG(0)) { 3362f8bf00f1SRichard Henderson temp_dead(s, ots); 33634c4e1ab2SAurelien Jarno } 3364e8996ee0Sbellard } 3365e8996ee0Sbellard 3366dd186292SRichard Henderson static void tcg_reg_alloc_movi(TCGContext *s, const TCGOp *op) 33670fe4fca4SPaolo Bonzini { 336843439139SRichard Henderson TCGTemp *ots = arg_temp(op->args[0]); 3369dd186292SRichard Henderson tcg_target_ulong val = op->args[1]; 33700fe4fca4SPaolo Bonzini 337169e3706dSRichard Henderson tcg_reg_alloc_do_movi(s, ots, val, op->life, op->output_pref[0]); 33720fe4fca4SPaolo Bonzini } 33730fe4fca4SPaolo Bonzini 3374bab1671fSRichard Henderson /* 3375bab1671fSRichard Henderson * Specialized code generation for INDEX_op_mov_*. 3376bab1671fSRichard Henderson */ 3377dd186292SRichard Henderson static void tcg_reg_alloc_mov(TCGContext *s, const TCGOp *op) 3378c896fe29Sbellard { 3379dd186292SRichard Henderson const TCGLifeData arg_life = op->life; 338069e3706dSRichard Henderson TCGRegSet allocated_regs, preferred_regs; 3381c896fe29Sbellard TCGTemp *ts, *ots; 3382450445d5SRichard Henderson TCGType otype, itype; 3383c896fe29Sbellard 3384d21369f5SRichard Henderson allocated_regs = s->reserved_regs; 338569e3706dSRichard Henderson preferred_regs = op->output_pref[0]; 338643439139SRichard Henderson ots = arg_temp(op->args[0]); 338743439139SRichard Henderson ts = arg_temp(op->args[1]); 3388450445d5SRichard Henderson 3389d63e3b6eSRichard Henderson /* ENV should not be modified. */ 3390d63e3b6eSRichard Henderson tcg_debug_assert(!ots->fixed_reg); 3391d63e3b6eSRichard Henderson 3392450445d5SRichard Henderson /* Note that otype != itype for no-op truncation. */ 3393450445d5SRichard Henderson otype = ots->type; 3394450445d5SRichard Henderson itype = ts->type; 3395c896fe29Sbellard 33960fe4fca4SPaolo Bonzini if (ts->val_type == TEMP_VAL_CONST) { 33970fe4fca4SPaolo Bonzini /* propagate constant or generate sti */ 33980fe4fca4SPaolo Bonzini tcg_target_ulong val = ts->val; 33990fe4fca4SPaolo Bonzini if (IS_DEAD_ARG(1)) { 34000fe4fca4SPaolo Bonzini temp_dead(s, ts); 34010fe4fca4SPaolo Bonzini } 340269e3706dSRichard Henderson tcg_reg_alloc_do_movi(s, ots, val, arg_life, preferred_regs); 34030fe4fca4SPaolo Bonzini return; 34040fe4fca4SPaolo Bonzini } 34050fe4fca4SPaolo Bonzini 34060fe4fca4SPaolo Bonzini /* If the source value is in memory we're going to be forced 34070fe4fca4SPaolo Bonzini to have it in a register in order to perform the copy. Copy 34080fe4fca4SPaolo Bonzini the SOURCE value into its own register first, that way we 34090fe4fca4SPaolo Bonzini don't have to reload SOURCE the next time it is used. */ 34100fe4fca4SPaolo Bonzini if (ts->val_type == TEMP_VAL_MEM) { 341169e3706dSRichard Henderson temp_load(s, ts, tcg_target_available_regs[itype], 341269e3706dSRichard Henderson allocated_regs, preferred_regs); 3413c29c1d7eSAurelien Jarno } 3414c29c1d7eSAurelien Jarno 34150fe4fca4SPaolo Bonzini tcg_debug_assert(ts->val_type == TEMP_VAL_REG); 3416d63e3b6eSRichard Henderson if (IS_DEAD_ARG(0)) { 3417c29c1d7eSAurelien Jarno /* mov to a non-saved dead register makes no sense (even with 3418c29c1d7eSAurelien Jarno liveness analysis disabled). */ 3419eabb7b91SAurelien Jarno tcg_debug_assert(NEED_SYNC_ARG(0)); 3420c29c1d7eSAurelien Jarno if (!ots->mem_allocated) { 34212272e4a7SRichard Henderson temp_allocate_frame(s, ots); 3422c29c1d7eSAurelien Jarno } 3423b3a62939SRichard Henderson tcg_out_st(s, otype, ts->reg, ots->mem_base->reg, ots->mem_offset); 3424c29c1d7eSAurelien Jarno if (IS_DEAD_ARG(1)) { 3425f8bf00f1SRichard Henderson temp_dead(s, ts); 3426c29c1d7eSAurelien Jarno } 3427f8bf00f1SRichard Henderson temp_dead(s, ots); 3428e8996ee0Sbellard } else { 3429d63e3b6eSRichard Henderson if (IS_DEAD_ARG(1) && !ts->fixed_reg) { 3430c29c1d7eSAurelien Jarno /* the mov can be suppressed */ 3431c29c1d7eSAurelien Jarno if (ots->val_type == TEMP_VAL_REG) { 3432f8b2f202SRichard Henderson s->reg_to_temp[ots->reg] = NULL; 3433c896fe29Sbellard } 3434c29c1d7eSAurelien Jarno ots->reg = ts->reg; 3435f8bf00f1SRichard Henderson temp_dead(s, ts); 3436c29c1d7eSAurelien Jarno } else { 3437c29c1d7eSAurelien Jarno if (ots->val_type != TEMP_VAL_REG) { 3438c29c1d7eSAurelien Jarno /* When allocating a new register, make sure to not spill the 3439c29c1d7eSAurelien Jarno input one. */ 3440c29c1d7eSAurelien Jarno tcg_regset_set_reg(allocated_regs, ts->reg); 3441450445d5SRichard Henderson ots->reg = tcg_reg_alloc(s, tcg_target_available_regs[otype], 344269e3706dSRichard Henderson allocated_regs, preferred_regs, 3443b016486eSRichard Henderson ots->indirect_base); 3444c29c1d7eSAurelien Jarno } 344578113e83SRichard Henderson if (!tcg_out_mov(s, otype, ots->reg, ts->reg)) { 3446240c08d0SRichard Henderson /* 3447240c08d0SRichard Henderson * Cross register class move not supported. 3448240c08d0SRichard Henderson * Store the source register into the destination slot 3449240c08d0SRichard Henderson * and leave the destination temp as TEMP_VAL_MEM. 3450240c08d0SRichard Henderson */ 3451240c08d0SRichard Henderson assert(!ots->fixed_reg); 3452240c08d0SRichard Henderson if (!ts->mem_allocated) { 3453240c08d0SRichard Henderson temp_allocate_frame(s, ots); 3454240c08d0SRichard Henderson } 3455240c08d0SRichard Henderson tcg_out_st(s, ts->type, ts->reg, 3456240c08d0SRichard Henderson ots->mem_base->reg, ots->mem_offset); 3457240c08d0SRichard Henderson ots->mem_coherent = 1; 3458240c08d0SRichard Henderson temp_free_or_dead(s, ots, -1); 3459240c08d0SRichard Henderson return; 346078113e83SRichard Henderson } 3461c29c1d7eSAurelien Jarno } 3462c896fe29Sbellard ots->val_type = TEMP_VAL_REG; 3463c896fe29Sbellard ots->mem_coherent = 0; 3464f8b2f202SRichard Henderson s->reg_to_temp[ots->reg] = ots; 3465ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(0)) { 346698b4e186SRichard Henderson temp_sync(s, ots, allocated_regs, 0, 0); 3467c29c1d7eSAurelien Jarno } 3468ec7a869dSAurelien Jarno } 3469c896fe29Sbellard } 3470c896fe29Sbellard 3471bab1671fSRichard Henderson /* 3472bab1671fSRichard Henderson * Specialized code generation for INDEX_op_dup_vec. 3473bab1671fSRichard Henderson */ 3474bab1671fSRichard Henderson static void tcg_reg_alloc_dup(TCGContext *s, const TCGOp *op) 3475bab1671fSRichard Henderson { 3476bab1671fSRichard Henderson const TCGLifeData arg_life = op->life; 3477bab1671fSRichard Henderson TCGRegSet dup_out_regs, dup_in_regs; 3478bab1671fSRichard Henderson TCGTemp *its, *ots; 3479bab1671fSRichard Henderson TCGType itype, vtype; 3480d6ecb4a9SRichard Henderson intptr_t endian_fixup; 3481bab1671fSRichard Henderson unsigned vece; 3482bab1671fSRichard Henderson bool ok; 3483bab1671fSRichard Henderson 3484bab1671fSRichard Henderson ots = arg_temp(op->args[0]); 3485bab1671fSRichard Henderson its = arg_temp(op->args[1]); 3486bab1671fSRichard Henderson 3487bab1671fSRichard Henderson /* ENV should not be modified. */ 3488bab1671fSRichard Henderson tcg_debug_assert(!ots->fixed_reg); 3489bab1671fSRichard Henderson 3490bab1671fSRichard Henderson itype = its->type; 3491bab1671fSRichard Henderson vece = TCGOP_VECE(op); 3492bab1671fSRichard Henderson vtype = TCGOP_VECL(op) + TCG_TYPE_V64; 3493bab1671fSRichard Henderson 3494bab1671fSRichard Henderson if (its->val_type == TEMP_VAL_CONST) { 3495bab1671fSRichard Henderson /* Propagate constant via movi -> dupi. */ 3496bab1671fSRichard Henderson tcg_target_ulong val = its->val; 3497bab1671fSRichard Henderson if (IS_DEAD_ARG(1)) { 3498bab1671fSRichard Henderson temp_dead(s, its); 3499bab1671fSRichard Henderson } 3500bab1671fSRichard Henderson tcg_reg_alloc_do_movi(s, ots, val, arg_life, op->output_pref[0]); 3501bab1671fSRichard Henderson return; 3502bab1671fSRichard Henderson } 3503bab1671fSRichard Henderson 3504bab1671fSRichard Henderson dup_out_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[0].u.regs; 3505bab1671fSRichard Henderson dup_in_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[1].u.regs; 3506bab1671fSRichard Henderson 3507bab1671fSRichard Henderson /* Allocate the output register now. */ 3508bab1671fSRichard Henderson if (ots->val_type != TEMP_VAL_REG) { 3509bab1671fSRichard Henderson TCGRegSet allocated_regs = s->reserved_regs; 3510bab1671fSRichard Henderson 3511bab1671fSRichard Henderson if (!IS_DEAD_ARG(1) && its->val_type == TEMP_VAL_REG) { 3512bab1671fSRichard Henderson /* Make sure to not spill the input register. */ 3513bab1671fSRichard Henderson tcg_regset_set_reg(allocated_regs, its->reg); 3514bab1671fSRichard Henderson } 3515bab1671fSRichard Henderson ots->reg = tcg_reg_alloc(s, dup_out_regs, allocated_regs, 3516bab1671fSRichard Henderson op->output_pref[0], ots->indirect_base); 3517bab1671fSRichard Henderson ots->val_type = TEMP_VAL_REG; 3518bab1671fSRichard Henderson ots->mem_coherent = 0; 3519bab1671fSRichard Henderson s->reg_to_temp[ots->reg] = ots; 3520bab1671fSRichard Henderson } 3521bab1671fSRichard Henderson 3522bab1671fSRichard Henderson switch (its->val_type) { 3523bab1671fSRichard Henderson case TEMP_VAL_REG: 3524bab1671fSRichard Henderson /* 3525bab1671fSRichard Henderson * The dup constriaints must be broad, covering all possible VECE. 3526bab1671fSRichard Henderson * However, tcg_op_dup_vec() gets to see the VECE and we allow it 3527bab1671fSRichard Henderson * to fail, indicating that extra moves are required for that case. 3528bab1671fSRichard Henderson */ 3529bab1671fSRichard Henderson if (tcg_regset_test_reg(dup_in_regs, its->reg)) { 3530bab1671fSRichard Henderson if (tcg_out_dup_vec(s, vtype, vece, ots->reg, its->reg)) { 3531bab1671fSRichard Henderson goto done; 3532bab1671fSRichard Henderson } 3533bab1671fSRichard Henderson /* Try again from memory or a vector input register. */ 3534bab1671fSRichard Henderson } 3535bab1671fSRichard Henderson if (!its->mem_coherent) { 3536bab1671fSRichard Henderson /* 3537bab1671fSRichard Henderson * The input register is not synced, and so an extra store 3538bab1671fSRichard Henderson * would be required to use memory. Attempt an integer-vector 3539bab1671fSRichard Henderson * register move first. We do not have a TCGRegSet for this. 3540bab1671fSRichard Henderson */ 3541bab1671fSRichard Henderson if (tcg_out_mov(s, itype, ots->reg, its->reg)) { 3542bab1671fSRichard Henderson break; 3543bab1671fSRichard Henderson } 3544bab1671fSRichard Henderson /* Sync the temp back to its slot and load from there. */ 3545bab1671fSRichard Henderson temp_sync(s, its, s->reserved_regs, 0, 0); 3546bab1671fSRichard Henderson } 3547bab1671fSRichard Henderson /* fall through */ 3548bab1671fSRichard Henderson 3549bab1671fSRichard Henderson case TEMP_VAL_MEM: 3550d6ecb4a9SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN 3551d6ecb4a9SRichard Henderson endian_fixup = itype == TCG_TYPE_I32 ? 4 : 8; 3552d6ecb4a9SRichard Henderson endian_fixup -= 1 << vece; 3553d6ecb4a9SRichard Henderson #else 3554d6ecb4a9SRichard Henderson endian_fixup = 0; 3555d6ecb4a9SRichard Henderson #endif 3556d6ecb4a9SRichard Henderson if (tcg_out_dupm_vec(s, vtype, vece, ots->reg, its->mem_base->reg, 3557d6ecb4a9SRichard Henderson its->mem_offset + endian_fixup)) { 3558d6ecb4a9SRichard Henderson goto done; 3559d6ecb4a9SRichard Henderson } 3560bab1671fSRichard Henderson tcg_out_ld(s, itype, ots->reg, its->mem_base->reg, its->mem_offset); 3561bab1671fSRichard Henderson break; 3562bab1671fSRichard Henderson 3563bab1671fSRichard Henderson default: 3564bab1671fSRichard Henderson g_assert_not_reached(); 3565bab1671fSRichard Henderson } 3566bab1671fSRichard Henderson 3567bab1671fSRichard Henderson /* We now have a vector input register, so dup must succeed. */ 3568bab1671fSRichard Henderson ok = tcg_out_dup_vec(s, vtype, vece, ots->reg, ots->reg); 3569bab1671fSRichard Henderson tcg_debug_assert(ok); 3570bab1671fSRichard Henderson 3571bab1671fSRichard Henderson done: 3572bab1671fSRichard Henderson if (IS_DEAD_ARG(1)) { 3573bab1671fSRichard Henderson temp_dead(s, its); 3574bab1671fSRichard Henderson } 3575bab1671fSRichard Henderson if (NEED_SYNC_ARG(0)) { 3576bab1671fSRichard Henderson temp_sync(s, ots, s->reserved_regs, 0, 0); 3577bab1671fSRichard Henderson } 3578bab1671fSRichard Henderson if (IS_DEAD_ARG(0)) { 3579bab1671fSRichard Henderson temp_dead(s, ots); 3580bab1671fSRichard Henderson } 3581bab1671fSRichard Henderson } 3582bab1671fSRichard Henderson 3583dd186292SRichard Henderson static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) 3584c896fe29Sbellard { 3585dd186292SRichard Henderson const TCGLifeData arg_life = op->life; 3586dd186292SRichard Henderson const TCGOpDef * const def = &tcg_op_defs[op->opc]; 358782790a87SRichard Henderson TCGRegSet i_allocated_regs; 358882790a87SRichard Henderson TCGRegSet o_allocated_regs; 3589b6638662SRichard Henderson int i, k, nb_iargs, nb_oargs; 3590b6638662SRichard Henderson TCGReg reg; 3591c896fe29Sbellard TCGArg arg; 3592c896fe29Sbellard const TCGArgConstraint *arg_ct; 3593c896fe29Sbellard TCGTemp *ts; 3594c896fe29Sbellard TCGArg new_args[TCG_MAX_OP_ARGS]; 3595c896fe29Sbellard int const_args[TCG_MAX_OP_ARGS]; 3596c896fe29Sbellard 3597c896fe29Sbellard nb_oargs = def->nb_oargs; 3598c896fe29Sbellard nb_iargs = def->nb_iargs; 3599c896fe29Sbellard 3600c896fe29Sbellard /* copy constants */ 3601c896fe29Sbellard memcpy(new_args + nb_oargs + nb_iargs, 3602dd186292SRichard Henderson op->args + nb_oargs + nb_iargs, 3603c896fe29Sbellard sizeof(TCGArg) * def->nb_cargs); 3604c896fe29Sbellard 3605d21369f5SRichard Henderson i_allocated_regs = s->reserved_regs; 3606d21369f5SRichard Henderson o_allocated_regs = s->reserved_regs; 360782790a87SRichard Henderson 3608c896fe29Sbellard /* satisfy input constraints */ 3609c896fe29Sbellard for (k = 0; k < nb_iargs; k++) { 3610d62816f2SRichard Henderson TCGRegSet i_preferred_regs, o_preferred_regs; 3611d62816f2SRichard Henderson 3612c896fe29Sbellard i = def->sorted_args[nb_oargs + k]; 3613dd186292SRichard Henderson arg = op->args[i]; 3614c896fe29Sbellard arg_ct = &def->args_ct[i]; 361543439139SRichard Henderson ts = arg_temp(arg); 361640ae5c62SRichard Henderson 361740ae5c62SRichard Henderson if (ts->val_type == TEMP_VAL_CONST 361840ae5c62SRichard Henderson && tcg_target_const_match(ts->val, ts->type, arg_ct)) { 3619c896fe29Sbellard /* constant is OK for instruction */ 3620c896fe29Sbellard const_args[i] = 1; 3621c896fe29Sbellard new_args[i] = ts->val; 3622d62816f2SRichard Henderson continue; 3623c896fe29Sbellard } 362440ae5c62SRichard Henderson 3625d62816f2SRichard Henderson i_preferred_regs = o_preferred_regs = 0; 36265ff9d6a4Sbellard if (arg_ct->ct & TCG_CT_IALIAS) { 3627d62816f2SRichard Henderson o_preferred_regs = op->output_pref[arg_ct->alias_index]; 36285ff9d6a4Sbellard if (ts->fixed_reg) { 36295ff9d6a4Sbellard /* if fixed register, we must allocate a new register 36305ff9d6a4Sbellard if the alias is not the same register */ 3631d62816f2SRichard Henderson if (arg != op->args[arg_ct->alias_index]) { 36325ff9d6a4Sbellard goto allocate_in_reg; 3633d62816f2SRichard Henderson } 36345ff9d6a4Sbellard } else { 3635c896fe29Sbellard /* if the input is aliased to an output and if it is 3636c896fe29Sbellard not dead after the instruction, we must allocate 3637c896fe29Sbellard a new register and move it */ 3638866cb6cbSAurelien Jarno if (!IS_DEAD_ARG(i)) { 3639c896fe29Sbellard goto allocate_in_reg; 3640c896fe29Sbellard } 3641d62816f2SRichard Henderson 36427e1df267SAurelien Jarno /* check if the current register has already been allocated 36437e1df267SAurelien Jarno for another input aliased to an output */ 3644d62816f2SRichard Henderson if (ts->val_type == TEMP_VAL_REG) { 36457e1df267SAurelien Jarno int k2, i2; 3646d62816f2SRichard Henderson reg = ts->reg; 36477e1df267SAurelien Jarno for (k2 = 0 ; k2 < k ; k2++) { 36487e1df267SAurelien Jarno i2 = def->sorted_args[nb_oargs + k2]; 36497e1df267SAurelien Jarno if ((def->args_ct[i2].ct & TCG_CT_IALIAS) && 3650d62816f2SRichard Henderson reg == new_args[i2]) { 36517e1df267SAurelien Jarno goto allocate_in_reg; 36527e1df267SAurelien Jarno } 36537e1df267SAurelien Jarno } 36545ff9d6a4Sbellard } 3655d62816f2SRichard Henderson i_preferred_regs = o_preferred_regs; 3656866cb6cbSAurelien Jarno } 3657d62816f2SRichard Henderson } 3658d62816f2SRichard Henderson 3659d62816f2SRichard Henderson temp_load(s, ts, arg_ct->u.regs, i_allocated_regs, i_preferred_regs); 3660c896fe29Sbellard reg = ts->reg; 3661d62816f2SRichard Henderson 3662c896fe29Sbellard if (tcg_regset_test_reg(arg_ct->u.regs, reg)) { 3663c896fe29Sbellard /* nothing to do : the constraint is satisfied */ 3664c896fe29Sbellard } else { 3665c896fe29Sbellard allocate_in_reg: 3666c896fe29Sbellard /* allocate a new register matching the constraint 3667c896fe29Sbellard and move the temporary register into it */ 3668d62816f2SRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], 3669d62816f2SRichard Henderson i_allocated_regs, 0); 367082790a87SRichard Henderson reg = tcg_reg_alloc(s, arg_ct->u.regs, i_allocated_regs, 3671d62816f2SRichard Henderson o_preferred_regs, ts->indirect_base); 367278113e83SRichard Henderson if (!tcg_out_mov(s, ts->type, reg, ts->reg)) { 3673240c08d0SRichard Henderson /* 3674240c08d0SRichard Henderson * Cross register class move not supported. Sync the 3675240c08d0SRichard Henderson * temp back to its slot and load from there. 3676240c08d0SRichard Henderson */ 3677240c08d0SRichard Henderson temp_sync(s, ts, i_allocated_regs, 0, 0); 3678240c08d0SRichard Henderson tcg_out_ld(s, ts->type, reg, 3679240c08d0SRichard Henderson ts->mem_base->reg, ts->mem_offset); 368078113e83SRichard Henderson } 3681c896fe29Sbellard } 3682c896fe29Sbellard new_args[i] = reg; 3683c896fe29Sbellard const_args[i] = 0; 368482790a87SRichard Henderson tcg_regset_set_reg(i_allocated_regs, reg); 3685c896fe29Sbellard } 3686c896fe29Sbellard 3687c896fe29Sbellard /* mark dead temporaries and free the associated registers */ 3688866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { 3689866cb6cbSAurelien Jarno if (IS_DEAD_ARG(i)) { 369043439139SRichard Henderson temp_dead(s, arg_temp(op->args[i])); 3691c896fe29Sbellard } 3692c896fe29Sbellard } 3693c896fe29Sbellard 3694a52ad07eSAurelien Jarno if (def->flags & TCG_OPF_BB_END) { 369582790a87SRichard Henderson tcg_reg_alloc_bb_end(s, i_allocated_regs); 3696a52ad07eSAurelien Jarno } else { 3697c896fe29Sbellard if (def->flags & TCG_OPF_CALL_CLOBBER) { 3698b03cce8eSbellard /* XXX: permit generic clobber register list ? */ 3699c8074023SRichard Henderson for (i = 0; i < TCG_TARGET_NB_REGS; i++) { 3700c8074023SRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) { 370182790a87SRichard Henderson tcg_reg_free(s, i, i_allocated_regs); 3702c896fe29Sbellard } 3703c896fe29Sbellard } 37043d5c5f87SAurelien Jarno } 37053d5c5f87SAurelien Jarno if (def->flags & TCG_OPF_SIDE_EFFECTS) { 37063d5c5f87SAurelien Jarno /* sync globals if the op has side effects and might trigger 37073d5c5f87SAurelien Jarno an exception. */ 370882790a87SRichard Henderson sync_globals(s, i_allocated_regs); 3709c896fe29Sbellard } 3710c896fe29Sbellard 3711c896fe29Sbellard /* satisfy the output constraints */ 3712c896fe29Sbellard for(k = 0; k < nb_oargs; k++) { 3713c896fe29Sbellard i = def->sorted_args[k]; 3714dd186292SRichard Henderson arg = op->args[i]; 3715c896fe29Sbellard arg_ct = &def->args_ct[i]; 371643439139SRichard Henderson ts = arg_temp(arg); 3717d63e3b6eSRichard Henderson 3718d63e3b6eSRichard Henderson /* ENV should not be modified. */ 3719d63e3b6eSRichard Henderson tcg_debug_assert(!ts->fixed_reg); 3720d63e3b6eSRichard Henderson 372117280ff4SRichard Henderson if ((arg_ct->ct & TCG_CT_ALIAS) 372217280ff4SRichard Henderson && !const_args[arg_ct->alias_index]) { 37235ff9d6a4Sbellard reg = new_args[arg_ct->alias_index]; 372482790a87SRichard Henderson } else if (arg_ct->ct & TCG_CT_NEWREG) { 372582790a87SRichard Henderson reg = tcg_reg_alloc(s, arg_ct->u.regs, 372682790a87SRichard Henderson i_allocated_regs | o_allocated_regs, 372769e3706dSRichard Henderson op->output_pref[k], ts->indirect_base); 3728c896fe29Sbellard } else { 372982790a87SRichard Henderson reg = tcg_reg_alloc(s, arg_ct->u.regs, o_allocated_regs, 373069e3706dSRichard Henderson op->output_pref[k], ts->indirect_base); 3731c896fe29Sbellard } 373282790a87SRichard Henderson tcg_regset_set_reg(o_allocated_regs, reg); 3733639368ddSAurelien Jarno if (ts->val_type == TEMP_VAL_REG) { 3734f8b2f202SRichard Henderson s->reg_to_temp[ts->reg] = NULL; 3735639368ddSAurelien Jarno } 3736c896fe29Sbellard ts->val_type = TEMP_VAL_REG; 3737c896fe29Sbellard ts->reg = reg; 3738d63e3b6eSRichard Henderson /* 3739d63e3b6eSRichard Henderson * Temp value is modified, so the value kept in memory is 3740d63e3b6eSRichard Henderson * potentially not the same. 3741d63e3b6eSRichard Henderson */ 3742c896fe29Sbellard ts->mem_coherent = 0; 3743f8b2f202SRichard Henderson s->reg_to_temp[reg] = ts; 3744c896fe29Sbellard new_args[i] = reg; 3745c896fe29Sbellard } 3746e8996ee0Sbellard } 3747c896fe29Sbellard 3748c896fe29Sbellard /* emit instruction */ 3749d2fd745fSRichard Henderson if (def->flags & TCG_OPF_VECTOR) { 3750d2fd745fSRichard Henderson tcg_out_vec_op(s, op->opc, TCGOP_VECL(op), TCGOP_VECE(op), 3751d2fd745fSRichard Henderson new_args, const_args); 3752d2fd745fSRichard Henderson } else { 3753dd186292SRichard Henderson tcg_out_op(s, op->opc, new_args, const_args); 3754d2fd745fSRichard Henderson } 3755c896fe29Sbellard 3756c896fe29Sbellard /* move the outputs in the correct register if needed */ 3757c896fe29Sbellard for(i = 0; i < nb_oargs; i++) { 375843439139SRichard Henderson ts = arg_temp(op->args[i]); 3759d63e3b6eSRichard Henderson 3760d63e3b6eSRichard Henderson /* ENV should not be modified. */ 3761d63e3b6eSRichard Henderson tcg_debug_assert(!ts->fixed_reg); 3762d63e3b6eSRichard Henderson 3763ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(i)) { 376498b4e186SRichard Henderson temp_sync(s, ts, o_allocated_regs, 0, IS_DEAD_ARG(i)); 376559d7c14eSRichard Henderson } else if (IS_DEAD_ARG(i)) { 3766f8bf00f1SRichard Henderson temp_dead(s, ts); 3767ec7a869dSAurelien Jarno } 3768c896fe29Sbellard } 3769c896fe29Sbellard } 3770c896fe29Sbellard 3771b03cce8eSbellard #ifdef TCG_TARGET_STACK_GROWSUP 3772b03cce8eSbellard #define STACK_DIR(x) (-(x)) 3773b03cce8eSbellard #else 3774b03cce8eSbellard #define STACK_DIR(x) (x) 3775b03cce8eSbellard #endif 3776b03cce8eSbellard 3777dd186292SRichard Henderson static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op) 3778c896fe29Sbellard { 3779cd9090aaSRichard Henderson const int nb_oargs = TCGOP_CALLO(op); 3780cd9090aaSRichard Henderson const int nb_iargs = TCGOP_CALLI(op); 3781dd186292SRichard Henderson const TCGLifeData arg_life = op->life; 3782b6638662SRichard Henderson int flags, nb_regs, i; 3783b6638662SRichard Henderson TCGReg reg; 3784cf066674SRichard Henderson TCGArg arg; 3785c896fe29Sbellard TCGTemp *ts; 3786d3452f1fSRichard Henderson intptr_t stack_offset; 3787d3452f1fSRichard Henderson size_t call_stack_size; 3788cf066674SRichard Henderson tcg_insn_unit *func_addr; 3789cf066674SRichard Henderson int allocate_args; 3790c896fe29Sbellard TCGRegSet allocated_regs; 3791c896fe29Sbellard 3792dd186292SRichard Henderson func_addr = (tcg_insn_unit *)(intptr_t)op->args[nb_oargs + nb_iargs]; 3793dd186292SRichard Henderson flags = op->args[nb_oargs + nb_iargs + 1]; 3794c896fe29Sbellard 37956e17d0c5SStefan Weil nb_regs = ARRAY_SIZE(tcg_target_call_iarg_regs); 3796c45cb8bbSRichard Henderson if (nb_regs > nb_iargs) { 3797c45cb8bbSRichard Henderson nb_regs = nb_iargs; 3798cf066674SRichard Henderson } 3799c896fe29Sbellard 3800c896fe29Sbellard /* assign stack slots first */ 3801c45cb8bbSRichard Henderson call_stack_size = (nb_iargs - nb_regs) * sizeof(tcg_target_long); 3802c896fe29Sbellard call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) & 3803c896fe29Sbellard ~(TCG_TARGET_STACK_ALIGN - 1); 3804b03cce8eSbellard allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE); 3805b03cce8eSbellard if (allocate_args) { 3806345649c0SBlue Swirl /* XXX: if more than TCG_STATIC_CALL_ARGS_SIZE is needed, 3807345649c0SBlue Swirl preallocate call stack */ 3808345649c0SBlue Swirl tcg_abort(); 3809b03cce8eSbellard } 381039cf05d3Sbellard 381139cf05d3Sbellard stack_offset = TCG_TARGET_CALL_STACK_OFFSET; 3812c45cb8bbSRichard Henderson for (i = nb_regs; i < nb_iargs; i++) { 3813dd186292SRichard Henderson arg = op->args[nb_oargs + i]; 381439cf05d3Sbellard #ifdef TCG_TARGET_STACK_GROWSUP 381539cf05d3Sbellard stack_offset -= sizeof(tcg_target_long); 381639cf05d3Sbellard #endif 381739cf05d3Sbellard if (arg != TCG_CALL_DUMMY_ARG) { 381843439139SRichard Henderson ts = arg_temp(arg); 381940ae5c62SRichard Henderson temp_load(s, ts, tcg_target_available_regs[ts->type], 3820b722452aSRichard Henderson s->reserved_regs, 0); 3821e4d5434cSblueswir1 tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, stack_offset); 382239cf05d3Sbellard } 382339cf05d3Sbellard #ifndef TCG_TARGET_STACK_GROWSUP 382439cf05d3Sbellard stack_offset += sizeof(tcg_target_long); 382539cf05d3Sbellard #endif 3826c896fe29Sbellard } 3827c896fe29Sbellard 3828c896fe29Sbellard /* assign input registers */ 3829d21369f5SRichard Henderson allocated_regs = s->reserved_regs; 3830c896fe29Sbellard for (i = 0; i < nb_regs; i++) { 3831dd186292SRichard Henderson arg = op->args[nb_oargs + i]; 383239cf05d3Sbellard if (arg != TCG_CALL_DUMMY_ARG) { 383343439139SRichard Henderson ts = arg_temp(arg); 3834c896fe29Sbellard reg = tcg_target_call_iarg_regs[i]; 383540ae5c62SRichard Henderson 3836c896fe29Sbellard if (ts->val_type == TEMP_VAL_REG) { 3837c896fe29Sbellard if (ts->reg != reg) { 38384250da10SRichard Henderson tcg_reg_free(s, reg, allocated_regs); 383978113e83SRichard Henderson if (!tcg_out_mov(s, ts->type, reg, ts->reg)) { 3840240c08d0SRichard Henderson /* 3841240c08d0SRichard Henderson * Cross register class move not supported. Sync the 3842240c08d0SRichard Henderson * temp back to its slot and load from there. 3843240c08d0SRichard Henderson */ 3844240c08d0SRichard Henderson temp_sync(s, ts, allocated_regs, 0, 0); 3845240c08d0SRichard Henderson tcg_out_ld(s, ts->type, reg, 3846240c08d0SRichard Henderson ts->mem_base->reg, ts->mem_offset); 384778113e83SRichard Henderson } 3848c896fe29Sbellard } 3849c896fe29Sbellard } else { 3850ccb1bb66SRichard Henderson TCGRegSet arg_set = 0; 385140ae5c62SRichard Henderson 38524250da10SRichard Henderson tcg_reg_free(s, reg, allocated_regs); 385340ae5c62SRichard Henderson tcg_regset_set_reg(arg_set, reg); 3854b722452aSRichard Henderson temp_load(s, ts, arg_set, allocated_regs, 0); 3855c896fe29Sbellard } 385640ae5c62SRichard Henderson 3857c896fe29Sbellard tcg_regset_set_reg(allocated_regs, reg); 3858c896fe29Sbellard } 385939cf05d3Sbellard } 3860c896fe29Sbellard 3861c896fe29Sbellard /* mark dead temporaries and free the associated registers */ 3862866cb6cbSAurelien Jarno for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { 3863866cb6cbSAurelien Jarno if (IS_DEAD_ARG(i)) { 386443439139SRichard Henderson temp_dead(s, arg_temp(op->args[i])); 3865c896fe29Sbellard } 3866c896fe29Sbellard } 3867c896fe29Sbellard 3868c896fe29Sbellard /* clobber call registers */ 3869c8074023SRichard Henderson for (i = 0; i < TCG_TARGET_NB_REGS; i++) { 3870c8074023SRichard Henderson if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) { 3871b3915dbbSRichard Henderson tcg_reg_free(s, i, allocated_regs); 3872c896fe29Sbellard } 3873c896fe29Sbellard } 3874c896fe29Sbellard 387578505279SAurelien Jarno /* Save globals if they might be written by the helper, sync them if 387678505279SAurelien Jarno they might be read. */ 387778505279SAurelien Jarno if (flags & TCG_CALL_NO_READ_GLOBALS) { 387878505279SAurelien Jarno /* Nothing to do */ 387978505279SAurelien Jarno } else if (flags & TCG_CALL_NO_WRITE_GLOBALS) { 388078505279SAurelien Jarno sync_globals(s, allocated_regs); 388178505279SAurelien Jarno } else { 3882e8996ee0Sbellard save_globals(s, allocated_regs); 3883b9c18f56Saurel32 } 3884c896fe29Sbellard 3885cf066674SRichard Henderson tcg_out_call(s, func_addr); 3886c896fe29Sbellard 3887c896fe29Sbellard /* assign output registers and emit moves if needed */ 3888c896fe29Sbellard for(i = 0; i < nb_oargs; i++) { 3889dd186292SRichard Henderson arg = op->args[i]; 389043439139SRichard Henderson ts = arg_temp(arg); 3891d63e3b6eSRichard Henderson 3892d63e3b6eSRichard Henderson /* ENV should not be modified. */ 3893d63e3b6eSRichard Henderson tcg_debug_assert(!ts->fixed_reg); 3894d63e3b6eSRichard Henderson 3895c896fe29Sbellard reg = tcg_target_call_oarg_regs[i]; 3896eabb7b91SAurelien Jarno tcg_debug_assert(s->reg_to_temp[reg] == NULL); 3897639368ddSAurelien Jarno if (ts->val_type == TEMP_VAL_REG) { 3898f8b2f202SRichard Henderson s->reg_to_temp[ts->reg] = NULL; 3899639368ddSAurelien Jarno } 3900c896fe29Sbellard ts->val_type = TEMP_VAL_REG; 3901c896fe29Sbellard ts->reg = reg; 3902c896fe29Sbellard ts->mem_coherent = 0; 3903f8b2f202SRichard Henderson s->reg_to_temp[reg] = ts; 3904ec7a869dSAurelien Jarno if (NEED_SYNC_ARG(i)) { 390598b4e186SRichard Henderson temp_sync(s, ts, allocated_regs, 0, IS_DEAD_ARG(i)); 390659d7c14eSRichard Henderson } else if (IS_DEAD_ARG(i)) { 3907f8bf00f1SRichard Henderson temp_dead(s, ts); 3908c896fe29Sbellard } 3909c896fe29Sbellard } 39108c11ad25SAurelien Jarno } 3911c896fe29Sbellard 3912c896fe29Sbellard #ifdef CONFIG_PROFILER 3913c896fe29Sbellard 3914c3fac113SEmilio G. Cota /* avoid copy/paste errors */ 3915c3fac113SEmilio G. Cota #define PROF_ADD(to, from, field) \ 3916c3fac113SEmilio G. Cota do { \ 3917c3fac113SEmilio G. Cota (to)->field += atomic_read(&((from)->field)); \ 3918c3fac113SEmilio G. Cota } while (0) 3919c896fe29Sbellard 3920c3fac113SEmilio G. Cota #define PROF_MAX(to, from, field) \ 3921c3fac113SEmilio G. Cota do { \ 3922c3fac113SEmilio G. Cota typeof((from)->field) val__ = atomic_read(&((from)->field)); \ 3923c3fac113SEmilio G. Cota if (val__ > (to)->field) { \ 3924c3fac113SEmilio G. Cota (to)->field = val__; \ 3925c3fac113SEmilio G. Cota } \ 3926c3fac113SEmilio G. Cota } while (0) 3927c3fac113SEmilio G. Cota 3928c3fac113SEmilio G. Cota /* Pass in a zero'ed @prof */ 3929c3fac113SEmilio G. Cota static inline 3930c3fac113SEmilio G. Cota void tcg_profile_snapshot(TCGProfile *prof, bool counters, bool table) 3931c896fe29Sbellard { 39323468b59eSEmilio G. Cota unsigned int n_ctxs = atomic_read(&n_tcg_ctxs); 3933c3fac113SEmilio G. Cota unsigned int i; 3934c3fac113SEmilio G. Cota 39353468b59eSEmilio G. Cota for (i = 0; i < n_ctxs; i++) { 39363468b59eSEmilio G. Cota TCGContext *s = atomic_read(&tcg_ctxs[i]); 39373468b59eSEmilio G. Cota const TCGProfile *orig = &s->prof; 3938c3fac113SEmilio G. Cota 3939c3fac113SEmilio G. Cota if (counters) { 394072fd2efbSEmilio G. Cota PROF_ADD(prof, orig, cpu_exec_time); 3941c3fac113SEmilio G. Cota PROF_ADD(prof, orig, tb_count1); 3942c3fac113SEmilio G. Cota PROF_ADD(prof, orig, tb_count); 3943c3fac113SEmilio G. Cota PROF_ADD(prof, orig, op_count); 3944c3fac113SEmilio G. Cota PROF_MAX(prof, orig, op_count_max); 3945c3fac113SEmilio G. Cota PROF_ADD(prof, orig, temp_count); 3946c3fac113SEmilio G. Cota PROF_MAX(prof, orig, temp_count_max); 3947c3fac113SEmilio G. Cota PROF_ADD(prof, orig, del_op_count); 3948c3fac113SEmilio G. Cota PROF_ADD(prof, orig, code_in_len); 3949c3fac113SEmilio G. Cota PROF_ADD(prof, orig, code_out_len); 3950c3fac113SEmilio G. Cota PROF_ADD(prof, orig, search_out_len); 3951c3fac113SEmilio G. Cota PROF_ADD(prof, orig, interm_time); 3952c3fac113SEmilio G. Cota PROF_ADD(prof, orig, code_time); 3953c3fac113SEmilio G. Cota PROF_ADD(prof, orig, la_time); 3954c3fac113SEmilio G. Cota PROF_ADD(prof, orig, opt_time); 3955c3fac113SEmilio G. Cota PROF_ADD(prof, orig, restore_count); 3956c3fac113SEmilio G. Cota PROF_ADD(prof, orig, restore_time); 3957c3fac113SEmilio G. Cota } 3958c3fac113SEmilio G. Cota if (table) { 3959c896fe29Sbellard int i; 3960d70724ceSzhanghailiang 396115fc7daaSRichard Henderson for (i = 0; i < NB_OPS; i++) { 3962c3fac113SEmilio G. Cota PROF_ADD(prof, orig, table_op_count[i]); 3963c3fac113SEmilio G. Cota } 3964c3fac113SEmilio G. Cota } 3965c3fac113SEmilio G. Cota } 3966c3fac113SEmilio G. Cota } 3967c3fac113SEmilio G. Cota 3968c3fac113SEmilio G. Cota #undef PROF_ADD 3969c3fac113SEmilio G. Cota #undef PROF_MAX 3970c3fac113SEmilio G. Cota 3971c3fac113SEmilio G. Cota static void tcg_profile_snapshot_counters(TCGProfile *prof) 3972c3fac113SEmilio G. Cota { 3973c3fac113SEmilio G. Cota tcg_profile_snapshot(prof, true, false); 3974c3fac113SEmilio G. Cota } 3975c3fac113SEmilio G. Cota 3976c3fac113SEmilio G. Cota static void tcg_profile_snapshot_table(TCGProfile *prof) 3977c3fac113SEmilio G. Cota { 3978c3fac113SEmilio G. Cota tcg_profile_snapshot(prof, false, true); 3979c3fac113SEmilio G. Cota } 3980c3fac113SEmilio G. Cota 3981d4c51a0aSMarkus Armbruster void tcg_dump_op_count(void) 3982c3fac113SEmilio G. Cota { 3983c3fac113SEmilio G. Cota TCGProfile prof = {}; 3984c3fac113SEmilio G. Cota int i; 3985c3fac113SEmilio G. Cota 3986c3fac113SEmilio G. Cota tcg_profile_snapshot_table(&prof); 3987c3fac113SEmilio G. Cota for (i = 0; i < NB_OPS; i++) { 3988d4c51a0aSMarkus Armbruster qemu_printf("%s %" PRId64 "\n", tcg_op_defs[i].name, 3989c3fac113SEmilio G. Cota prof.table_op_count[i]); 3990c896fe29Sbellard } 3991c896fe29Sbellard } 399272fd2efbSEmilio G. Cota 399372fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void) 399472fd2efbSEmilio G. Cota { 399572fd2efbSEmilio G. Cota unsigned int n_ctxs = atomic_read(&n_tcg_ctxs); 399672fd2efbSEmilio G. Cota unsigned int i; 399772fd2efbSEmilio G. Cota int64_t ret = 0; 399872fd2efbSEmilio G. Cota 399972fd2efbSEmilio G. Cota for (i = 0; i < n_ctxs; i++) { 400072fd2efbSEmilio G. Cota const TCGContext *s = atomic_read(&tcg_ctxs[i]); 400172fd2efbSEmilio G. Cota const TCGProfile *prof = &s->prof; 400272fd2efbSEmilio G. Cota 400372fd2efbSEmilio G. Cota ret += atomic_read(&prof->cpu_exec_time); 400472fd2efbSEmilio G. Cota } 400572fd2efbSEmilio G. Cota return ret; 400672fd2efbSEmilio G. Cota } 4007246ae24dSMax Filippov #else 4008d4c51a0aSMarkus Armbruster void tcg_dump_op_count(void) 4009246ae24dSMax Filippov { 4010d4c51a0aSMarkus Armbruster qemu_printf("[TCG profiler not compiled]\n"); 4011246ae24dSMax Filippov } 401272fd2efbSEmilio G. Cota 401372fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void) 401472fd2efbSEmilio G. Cota { 401572fd2efbSEmilio G. Cota error_report("%s: TCG profiler not compiled", __func__); 401672fd2efbSEmilio G. Cota exit(EXIT_FAILURE); 401772fd2efbSEmilio G. Cota } 4018c896fe29Sbellard #endif 4019c896fe29Sbellard 4020c896fe29Sbellard 40215bd2ec3dSAlex Bennée int tcg_gen_code(TCGContext *s, TranslationBlock *tb) 4022c896fe29Sbellard { 4023c3fac113SEmilio G. Cota #ifdef CONFIG_PROFILER 4024c3fac113SEmilio G. Cota TCGProfile *prof = &s->prof; 4025c3fac113SEmilio G. Cota #endif 402615fa08f8SRichard Henderson int i, num_insns; 402715fa08f8SRichard Henderson TCGOp *op; 4028c896fe29Sbellard 402904fe6400SRichard Henderson #ifdef CONFIG_PROFILER 403004fe6400SRichard Henderson { 4031c1f543b7SEmilio G. Cota int n = 0; 403204fe6400SRichard Henderson 403315fa08f8SRichard Henderson QTAILQ_FOREACH(op, &s->ops, link) { 403415fa08f8SRichard Henderson n++; 403515fa08f8SRichard Henderson } 4036c3fac113SEmilio G. Cota atomic_set(&prof->op_count, prof->op_count + n); 4037c3fac113SEmilio G. Cota if (n > prof->op_count_max) { 4038c3fac113SEmilio G. Cota atomic_set(&prof->op_count_max, n); 403904fe6400SRichard Henderson } 404004fe6400SRichard Henderson 404104fe6400SRichard Henderson n = s->nb_temps; 4042c3fac113SEmilio G. Cota atomic_set(&prof->temp_count, prof->temp_count + n); 4043c3fac113SEmilio G. Cota if (n > prof->temp_count_max) { 4044c3fac113SEmilio G. Cota atomic_set(&prof->temp_count_max, n); 404504fe6400SRichard Henderson } 404604fe6400SRichard Henderson } 404704fe6400SRichard Henderson #endif 404804fe6400SRichard Henderson 4049c896fe29Sbellard #ifdef DEBUG_DISAS 4050d977e1c2SAlex Bennée if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP) 4051d977e1c2SAlex Bennée && qemu_log_in_addr_range(tb->pc))) { 4052fc59d2d8SRobert Foley FILE *logfile = qemu_log_lock(); 405393fcfe39Saliguori qemu_log("OP:\n"); 40541894f69aSRichard Henderson tcg_dump_ops(s, false); 405593fcfe39Saliguori qemu_log("\n"); 4056fc59d2d8SRobert Foley qemu_log_unlock(logfile); 4057c896fe29Sbellard } 4058c896fe29Sbellard #endif 4059c896fe29Sbellard 4060bef16ab4SRichard Henderson #ifdef CONFIG_DEBUG_TCG 4061bef16ab4SRichard Henderson /* Ensure all labels referenced have been emitted. */ 4062bef16ab4SRichard Henderson { 4063bef16ab4SRichard Henderson TCGLabel *l; 4064bef16ab4SRichard Henderson bool error = false; 4065bef16ab4SRichard Henderson 4066bef16ab4SRichard Henderson QSIMPLEQ_FOREACH(l, &s->labels, next) { 4067bef16ab4SRichard Henderson if (unlikely(!l->present) && l->refs) { 4068bef16ab4SRichard Henderson qemu_log_mask(CPU_LOG_TB_OP, 4069bef16ab4SRichard Henderson "$L%d referenced but not present.\n", l->id); 4070bef16ab4SRichard Henderson error = true; 4071bef16ab4SRichard Henderson } 4072bef16ab4SRichard Henderson } 4073bef16ab4SRichard Henderson assert(!error); 4074bef16ab4SRichard Henderson } 4075bef16ab4SRichard Henderson #endif 4076bef16ab4SRichard Henderson 4077c5cc28ffSAurelien Jarno #ifdef CONFIG_PROFILER 4078c3fac113SEmilio G. Cota atomic_set(&prof->opt_time, prof->opt_time - profile_getclock()); 4079c5cc28ffSAurelien Jarno #endif 4080c5cc28ffSAurelien Jarno 40818f2e8c07SKirill Batuzov #ifdef USE_TCG_OPTIMIZATIONS 4082c45cb8bbSRichard Henderson tcg_optimize(s); 40838f2e8c07SKirill Batuzov #endif 40848f2e8c07SKirill Batuzov 4085a23a9ec6Sbellard #ifdef CONFIG_PROFILER 4086c3fac113SEmilio G. Cota atomic_set(&prof->opt_time, prof->opt_time + profile_getclock()); 4087c3fac113SEmilio G. Cota atomic_set(&prof->la_time, prof->la_time - profile_getclock()); 4088a23a9ec6Sbellard #endif 4089c5cc28ffSAurelien Jarno 4090b4fc67c7SRichard Henderson reachable_code_pass(s); 4091b83eabeaSRichard Henderson liveness_pass_1(s); 40925a18407fSRichard Henderson 40935a18407fSRichard Henderson if (s->nb_indirects > 0) { 40945a18407fSRichard Henderson #ifdef DEBUG_DISAS 40955a18407fSRichard Henderson if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_IND) 40965a18407fSRichard Henderson && qemu_log_in_addr_range(tb->pc))) { 4097fc59d2d8SRobert Foley FILE *logfile = qemu_log_lock(); 40985a18407fSRichard Henderson qemu_log("OP before indirect lowering:\n"); 40991894f69aSRichard Henderson tcg_dump_ops(s, false); 41005a18407fSRichard Henderson qemu_log("\n"); 4101fc59d2d8SRobert Foley qemu_log_unlock(logfile); 41025a18407fSRichard Henderson } 41035a18407fSRichard Henderson #endif 41045a18407fSRichard Henderson /* Replace indirect temps with direct temps. */ 4105b83eabeaSRichard Henderson if (liveness_pass_2(s)) { 41065a18407fSRichard Henderson /* If changes were made, re-run liveness. */ 4107b83eabeaSRichard Henderson liveness_pass_1(s); 41085a18407fSRichard Henderson } 41095a18407fSRichard Henderson } 4110c5cc28ffSAurelien Jarno 4111a23a9ec6Sbellard #ifdef CONFIG_PROFILER 4112c3fac113SEmilio G. Cota atomic_set(&prof->la_time, prof->la_time + profile_getclock()); 4113a23a9ec6Sbellard #endif 4114c896fe29Sbellard 4115c896fe29Sbellard #ifdef DEBUG_DISAS 4116d977e1c2SAlex Bennée if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT) 4117d977e1c2SAlex Bennée && qemu_log_in_addr_range(tb->pc))) { 4118fc59d2d8SRobert Foley FILE *logfile = qemu_log_lock(); 4119c5cc28ffSAurelien Jarno qemu_log("OP after optimization and liveness analysis:\n"); 41201894f69aSRichard Henderson tcg_dump_ops(s, true); 412193fcfe39Saliguori qemu_log("\n"); 4122fc59d2d8SRobert Foley qemu_log_unlock(logfile); 4123c896fe29Sbellard } 4124c896fe29Sbellard #endif 4125c896fe29Sbellard 4126c896fe29Sbellard tcg_reg_alloc_start(s); 4127c896fe29Sbellard 4128e7e168f4SEmilio G. Cota s->code_buf = tb->tc.ptr; 4129e7e168f4SEmilio G. Cota s->code_ptr = tb->tc.ptr; 4130c896fe29Sbellard 4131659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS 41326001f772SLaurent Vivier QSIMPLEQ_INIT(&s->ldst_labels); 4133659ef5cbSRichard Henderson #endif 413457a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS 413557a26946SRichard Henderson s->pool_labels = NULL; 413657a26946SRichard Henderson #endif 41379ecefc84SRichard Henderson 4138fca8a500SRichard Henderson num_insns = -1; 413915fa08f8SRichard Henderson QTAILQ_FOREACH(op, &s->ops, link) { 4140c45cb8bbSRichard Henderson TCGOpcode opc = op->opc; 4141b3db8758Sblueswir1 4142c896fe29Sbellard #ifdef CONFIG_PROFILER 4143c3fac113SEmilio G. Cota atomic_set(&prof->table_op_count[opc], prof->table_op_count[opc] + 1); 4144c896fe29Sbellard #endif 4145c45cb8bbSRichard Henderson 4146c896fe29Sbellard switch (opc) { 4147c896fe29Sbellard case INDEX_op_mov_i32: 4148c896fe29Sbellard case INDEX_op_mov_i64: 4149d2fd745fSRichard Henderson case INDEX_op_mov_vec: 4150dd186292SRichard Henderson tcg_reg_alloc_mov(s, op); 4151c896fe29Sbellard break; 4152e8996ee0Sbellard case INDEX_op_movi_i32: 4153e8996ee0Sbellard case INDEX_op_movi_i64: 4154d2fd745fSRichard Henderson case INDEX_op_dupi_vec: 4155dd186292SRichard Henderson tcg_reg_alloc_movi(s, op); 4156e8996ee0Sbellard break; 4157bab1671fSRichard Henderson case INDEX_op_dup_vec: 4158bab1671fSRichard Henderson tcg_reg_alloc_dup(s, op); 4159bab1671fSRichard Henderson break; 4160765b842aSRichard Henderson case INDEX_op_insn_start: 4161fca8a500SRichard Henderson if (num_insns >= 0) { 41629f754620SRichard Henderson size_t off = tcg_current_code_size(s); 41639f754620SRichard Henderson s->gen_insn_end_off[num_insns] = off; 41649f754620SRichard Henderson /* Assert that we do not overflow our stored offset. */ 41659f754620SRichard Henderson assert(s->gen_insn_end_off[num_insns] == off); 4166fca8a500SRichard Henderson } 4167fca8a500SRichard Henderson num_insns++; 4168bad729e2SRichard Henderson for (i = 0; i < TARGET_INSN_START_WORDS; ++i) { 4169bad729e2SRichard Henderson target_ulong a; 4170bad729e2SRichard Henderson #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS 4171efee3746SRichard Henderson a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]); 4172bad729e2SRichard Henderson #else 4173efee3746SRichard Henderson a = op->args[i]; 4174bad729e2SRichard Henderson #endif 4175fca8a500SRichard Henderson s->gen_insn_data[num_insns][i] = a; 4176bad729e2SRichard Henderson } 4177c896fe29Sbellard break; 41785ff9d6a4Sbellard case INDEX_op_discard: 417943439139SRichard Henderson temp_dead(s, arg_temp(op->args[0])); 41805ff9d6a4Sbellard break; 4181c896fe29Sbellard case INDEX_op_set_label: 4182e8996ee0Sbellard tcg_reg_alloc_bb_end(s, s->reserved_regs); 4183efee3746SRichard Henderson tcg_out_label(s, arg_label(op->args[0]), s->code_ptr); 4184c896fe29Sbellard break; 4185c896fe29Sbellard case INDEX_op_call: 4186dd186292SRichard Henderson tcg_reg_alloc_call(s, op); 4187c45cb8bbSRichard Henderson break; 4188c896fe29Sbellard default: 418925c4d9ccSRichard Henderson /* Sanity check that we've not introduced any unhandled opcodes. */ 4190be0f34b5SRichard Henderson tcg_debug_assert(tcg_op_supported(opc)); 4191c896fe29Sbellard /* Note: in order to speed up the code, it would be much 4192c896fe29Sbellard faster to have specialized register allocator functions for 4193c896fe29Sbellard some common argument patterns */ 4194dd186292SRichard Henderson tcg_reg_alloc_op(s, op); 4195c896fe29Sbellard break; 4196c896fe29Sbellard } 41978d8fdbaeSAurelien Jarno #ifdef CONFIG_DEBUG_TCG 4198c896fe29Sbellard check_regs(s); 4199c896fe29Sbellard #endif 4200b125f9dcSRichard Henderson /* Test for (pending) buffer overflow. The assumption is that any 4201b125f9dcSRichard Henderson one operation beginning below the high water mark cannot overrun 4202b125f9dcSRichard Henderson the buffer completely. Thus we can test for overflow after 4203b125f9dcSRichard Henderson generating code without having to check during generation. */ 4204644da9b3SJohn Clarke if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) { 4205b125f9dcSRichard Henderson return -1; 4206b125f9dcSRichard Henderson } 42076e6c4efeSRichard Henderson /* Test for TB overflow, as seen by gen_insn_end_off. */ 42086e6c4efeSRichard Henderson if (unlikely(tcg_current_code_size(s) > UINT16_MAX)) { 42096e6c4efeSRichard Henderson return -2; 42106e6c4efeSRichard Henderson } 4211c896fe29Sbellard } 4212fca8a500SRichard Henderson tcg_debug_assert(num_insns >= 0); 4213fca8a500SRichard Henderson s->gen_insn_end_off[num_insns] = tcg_current_code_size(s); 4214c45cb8bbSRichard Henderson 4215b76f0d8cSYeongkyoon Lee /* Generate TB finalization at the end of block */ 4216659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS 4217aeee05f5SRichard Henderson i = tcg_out_ldst_finalize(s); 4218aeee05f5SRichard Henderson if (i < 0) { 4219aeee05f5SRichard Henderson return i; 422023dceda6SRichard Henderson } 4221659ef5cbSRichard Henderson #endif 422257a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS 42231768987bSRichard Henderson i = tcg_out_pool_finalize(s); 42241768987bSRichard Henderson if (i < 0) { 42251768987bSRichard Henderson return i; 422657a26946SRichard Henderson } 422757a26946SRichard Henderson #endif 42287ecd02a0SRichard Henderson if (!tcg_resolve_relocs(s)) { 42297ecd02a0SRichard Henderson return -2; 42307ecd02a0SRichard Henderson } 4231c896fe29Sbellard 4232c896fe29Sbellard /* flush instruction cache */ 42331813e175SRichard Henderson flush_icache_range((uintptr_t)s->code_buf, (uintptr_t)s->code_ptr); 42342aeabc08SStefan Weil 42351813e175SRichard Henderson return tcg_current_code_size(s); 4236c896fe29Sbellard } 4237c896fe29Sbellard 4238a23a9ec6Sbellard #ifdef CONFIG_PROFILER 42393de2faa9SMarkus Armbruster void tcg_dump_info(void) 4240a23a9ec6Sbellard { 4241c3fac113SEmilio G. Cota TCGProfile prof = {}; 4242c3fac113SEmilio G. Cota const TCGProfile *s; 4243c3fac113SEmilio G. Cota int64_t tb_count; 4244c3fac113SEmilio G. Cota int64_t tb_div_count; 4245c3fac113SEmilio G. Cota int64_t tot; 4246c3fac113SEmilio G. Cota 4247c3fac113SEmilio G. Cota tcg_profile_snapshot_counters(&prof); 4248c3fac113SEmilio G. Cota s = &prof; 4249c3fac113SEmilio G. Cota tb_count = s->tb_count; 4250c3fac113SEmilio G. Cota tb_div_count = tb_count ? tb_count : 1; 4251c3fac113SEmilio G. Cota tot = s->interm_time + s->code_time; 4252a23a9ec6Sbellard 42533de2faa9SMarkus Armbruster qemu_printf("JIT cycles %" PRId64 " (%0.3f s at 2.4 GHz)\n", 4254a23a9ec6Sbellard tot, tot / 2.4e9); 42553de2faa9SMarkus Armbruster qemu_printf("translated TBs %" PRId64 " (aborted=%" PRId64 42563de2faa9SMarkus Armbruster " %0.1f%%)\n", 4257fca8a500SRichard Henderson tb_count, s->tb_count1 - tb_count, 4258fca8a500SRichard Henderson (double)(s->tb_count1 - s->tb_count) 4259fca8a500SRichard Henderson / (s->tb_count1 ? s->tb_count1 : 1) * 100.0); 42603de2faa9SMarkus Armbruster qemu_printf("avg ops/TB %0.1f max=%d\n", 4261fca8a500SRichard Henderson (double)s->op_count / tb_div_count, s->op_count_max); 42623de2faa9SMarkus Armbruster qemu_printf("deleted ops/TB %0.2f\n", 4263fca8a500SRichard Henderson (double)s->del_op_count / tb_div_count); 42643de2faa9SMarkus Armbruster qemu_printf("avg temps/TB %0.2f max=%d\n", 4265fca8a500SRichard Henderson (double)s->temp_count / tb_div_count, s->temp_count_max); 42663de2faa9SMarkus Armbruster qemu_printf("avg host code/TB %0.1f\n", 4267fca8a500SRichard Henderson (double)s->code_out_len / tb_div_count); 42683de2faa9SMarkus Armbruster qemu_printf("avg search data/TB %0.1f\n", 4269fca8a500SRichard Henderson (double)s->search_out_len / tb_div_count); 4270a23a9ec6Sbellard 42713de2faa9SMarkus Armbruster qemu_printf("cycles/op %0.1f\n", 4272a23a9ec6Sbellard s->op_count ? (double)tot / s->op_count : 0); 42733de2faa9SMarkus Armbruster qemu_printf("cycles/in byte %0.1f\n", 4274a23a9ec6Sbellard s->code_in_len ? (double)tot / s->code_in_len : 0); 42753de2faa9SMarkus Armbruster qemu_printf("cycles/out byte %0.1f\n", 4276a23a9ec6Sbellard s->code_out_len ? (double)tot / s->code_out_len : 0); 42773de2faa9SMarkus Armbruster qemu_printf("cycles/search byte %0.1f\n", 4278fca8a500SRichard Henderson s->search_out_len ? (double)tot / s->search_out_len : 0); 4279fca8a500SRichard Henderson if (tot == 0) { 4280a23a9ec6Sbellard tot = 1; 4281fca8a500SRichard Henderson } 42823de2faa9SMarkus Armbruster qemu_printf(" gen_interm time %0.1f%%\n", 4283a23a9ec6Sbellard (double)s->interm_time / tot * 100.0); 42843de2faa9SMarkus Armbruster qemu_printf(" gen_code time %0.1f%%\n", 4285a23a9ec6Sbellard (double)s->code_time / tot * 100.0); 42863de2faa9SMarkus Armbruster qemu_printf("optim./code time %0.1f%%\n", 4287c5cc28ffSAurelien Jarno (double)s->opt_time / (s->code_time ? s->code_time : 1) 4288c5cc28ffSAurelien Jarno * 100.0); 42893de2faa9SMarkus Armbruster qemu_printf("liveness/code time %0.1f%%\n", 4290a23a9ec6Sbellard (double)s->la_time / (s->code_time ? s->code_time : 1) * 100.0); 42913de2faa9SMarkus Armbruster qemu_printf("cpu_restore count %" PRId64 "\n", 4292a23a9ec6Sbellard s->restore_count); 42933de2faa9SMarkus Armbruster qemu_printf(" avg cycles %0.1f\n", 4294a23a9ec6Sbellard s->restore_count ? (double)s->restore_time / s->restore_count : 0); 4295a23a9ec6Sbellard } 4296a23a9ec6Sbellard #else 42973de2faa9SMarkus Armbruster void tcg_dump_info(void) 4298a23a9ec6Sbellard { 42993de2faa9SMarkus Armbruster qemu_printf("[TCG profiler not compiled]\n"); 4300a23a9ec6Sbellard } 4301a23a9ec6Sbellard #endif 4302813da627SRichard Henderson 4303813da627SRichard Henderson #ifdef ELF_HOST_MACHINE 43045872bbf2SRichard Henderson /* In order to use this feature, the backend needs to do three things: 43055872bbf2SRichard Henderson 43065872bbf2SRichard Henderson (1) Define ELF_HOST_MACHINE to indicate both what value to 43075872bbf2SRichard Henderson put into the ELF image and to indicate support for the feature. 43085872bbf2SRichard Henderson 43095872bbf2SRichard Henderson (2) Define tcg_register_jit. This should create a buffer containing 43105872bbf2SRichard Henderson the contents of a .debug_frame section that describes the post- 43115872bbf2SRichard Henderson prologue unwind info for the tcg machine. 43125872bbf2SRichard Henderson 43135872bbf2SRichard Henderson (3) Call tcg_register_jit_int, with the constructed .debug_frame. 43145872bbf2SRichard Henderson */ 4315813da627SRichard Henderson 4316813da627SRichard Henderson /* Begin GDB interface. THE FOLLOWING MUST MATCH GDB DOCS. */ 4317813da627SRichard Henderson typedef enum { 4318813da627SRichard Henderson JIT_NOACTION = 0, 4319813da627SRichard Henderson JIT_REGISTER_FN, 4320813da627SRichard Henderson JIT_UNREGISTER_FN 4321813da627SRichard Henderson } jit_actions_t; 4322813da627SRichard Henderson 4323813da627SRichard Henderson struct jit_code_entry { 4324813da627SRichard Henderson struct jit_code_entry *next_entry; 4325813da627SRichard Henderson struct jit_code_entry *prev_entry; 4326813da627SRichard Henderson const void *symfile_addr; 4327813da627SRichard Henderson uint64_t symfile_size; 4328813da627SRichard Henderson }; 4329813da627SRichard Henderson 4330813da627SRichard Henderson struct jit_descriptor { 4331813da627SRichard Henderson uint32_t version; 4332813da627SRichard Henderson uint32_t action_flag; 4333813da627SRichard Henderson struct jit_code_entry *relevant_entry; 4334813da627SRichard Henderson struct jit_code_entry *first_entry; 4335813da627SRichard Henderson }; 4336813da627SRichard Henderson 4337813da627SRichard Henderson void __jit_debug_register_code(void) __attribute__((noinline)); 4338813da627SRichard Henderson void __jit_debug_register_code(void) 4339813da627SRichard Henderson { 4340813da627SRichard Henderson asm(""); 4341813da627SRichard Henderson } 4342813da627SRichard Henderson 4343813da627SRichard Henderson /* Must statically initialize the version, because GDB may check 4344813da627SRichard Henderson the version before we can set it. */ 4345813da627SRichard Henderson struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 }; 4346813da627SRichard Henderson 4347813da627SRichard Henderson /* End GDB interface. */ 4348813da627SRichard Henderson 4349813da627SRichard Henderson static int find_string(const char *strtab, const char *str) 4350813da627SRichard Henderson { 4351813da627SRichard Henderson const char *p = strtab + 1; 4352813da627SRichard Henderson 4353813da627SRichard Henderson while (1) { 4354813da627SRichard Henderson if (strcmp(p, str) == 0) { 4355813da627SRichard Henderson return p - strtab; 4356813da627SRichard Henderson } 4357813da627SRichard Henderson p += strlen(p) + 1; 4358813da627SRichard Henderson } 4359813da627SRichard Henderson } 4360813da627SRichard Henderson 43615872bbf2SRichard Henderson static void tcg_register_jit_int(void *buf_ptr, size_t buf_size, 43622c90784aSRichard Henderson const void *debug_frame, 43632c90784aSRichard Henderson size_t debug_frame_size) 4364813da627SRichard Henderson { 43655872bbf2SRichard Henderson struct __attribute__((packed)) DebugInfo { 43665872bbf2SRichard Henderson uint32_t len; 43675872bbf2SRichard Henderson uint16_t version; 43685872bbf2SRichard Henderson uint32_t abbrev; 43695872bbf2SRichard Henderson uint8_t ptr_size; 43705872bbf2SRichard Henderson uint8_t cu_die; 43715872bbf2SRichard Henderson uint16_t cu_lang; 43725872bbf2SRichard Henderson uintptr_t cu_low_pc; 43735872bbf2SRichard Henderson uintptr_t cu_high_pc; 43745872bbf2SRichard Henderson uint8_t fn_die; 43755872bbf2SRichard Henderson char fn_name[16]; 43765872bbf2SRichard Henderson uintptr_t fn_low_pc; 43775872bbf2SRichard Henderson uintptr_t fn_high_pc; 43785872bbf2SRichard Henderson uint8_t cu_eoc; 43795872bbf2SRichard Henderson }; 4380813da627SRichard Henderson 4381813da627SRichard Henderson struct ElfImage { 4382813da627SRichard Henderson ElfW(Ehdr) ehdr; 4383813da627SRichard Henderson ElfW(Phdr) phdr; 43845872bbf2SRichard Henderson ElfW(Shdr) shdr[7]; 43855872bbf2SRichard Henderson ElfW(Sym) sym[2]; 43865872bbf2SRichard Henderson struct DebugInfo di; 43875872bbf2SRichard Henderson uint8_t da[24]; 43885872bbf2SRichard Henderson char str[80]; 43895872bbf2SRichard Henderson }; 43905872bbf2SRichard Henderson 43915872bbf2SRichard Henderson struct ElfImage *img; 43925872bbf2SRichard Henderson 43935872bbf2SRichard Henderson static const struct ElfImage img_template = { 43945872bbf2SRichard Henderson .ehdr = { 43955872bbf2SRichard Henderson .e_ident[EI_MAG0] = ELFMAG0, 43965872bbf2SRichard Henderson .e_ident[EI_MAG1] = ELFMAG1, 43975872bbf2SRichard Henderson .e_ident[EI_MAG2] = ELFMAG2, 43985872bbf2SRichard Henderson .e_ident[EI_MAG3] = ELFMAG3, 43995872bbf2SRichard Henderson .e_ident[EI_CLASS] = ELF_CLASS, 44005872bbf2SRichard Henderson .e_ident[EI_DATA] = ELF_DATA, 44015872bbf2SRichard Henderson .e_ident[EI_VERSION] = EV_CURRENT, 44025872bbf2SRichard Henderson .e_type = ET_EXEC, 44035872bbf2SRichard Henderson .e_machine = ELF_HOST_MACHINE, 44045872bbf2SRichard Henderson .e_version = EV_CURRENT, 44055872bbf2SRichard Henderson .e_phoff = offsetof(struct ElfImage, phdr), 44065872bbf2SRichard Henderson .e_shoff = offsetof(struct ElfImage, shdr), 44075872bbf2SRichard Henderson .e_ehsize = sizeof(ElfW(Shdr)), 44085872bbf2SRichard Henderson .e_phentsize = sizeof(ElfW(Phdr)), 44095872bbf2SRichard Henderson .e_phnum = 1, 44105872bbf2SRichard Henderson .e_shentsize = sizeof(ElfW(Shdr)), 44115872bbf2SRichard Henderson .e_shnum = ARRAY_SIZE(img->shdr), 44125872bbf2SRichard Henderson .e_shstrndx = ARRAY_SIZE(img->shdr) - 1, 4413abbb3eaeSRichard Henderson #ifdef ELF_HOST_FLAGS 4414abbb3eaeSRichard Henderson .e_flags = ELF_HOST_FLAGS, 4415abbb3eaeSRichard Henderson #endif 4416abbb3eaeSRichard Henderson #ifdef ELF_OSABI 4417abbb3eaeSRichard Henderson .e_ident[EI_OSABI] = ELF_OSABI, 4418abbb3eaeSRichard Henderson #endif 44195872bbf2SRichard Henderson }, 44205872bbf2SRichard Henderson .phdr = { 44215872bbf2SRichard Henderson .p_type = PT_LOAD, 44225872bbf2SRichard Henderson .p_flags = PF_X, 44235872bbf2SRichard Henderson }, 44245872bbf2SRichard Henderson .shdr = { 44255872bbf2SRichard Henderson [0] = { .sh_type = SHT_NULL }, 44265872bbf2SRichard Henderson /* Trick: The contents of code_gen_buffer are not present in 44275872bbf2SRichard Henderson this fake ELF file; that got allocated elsewhere. Therefore 44285872bbf2SRichard Henderson we mark .text as SHT_NOBITS (similar to .bss) so that readers 44295872bbf2SRichard Henderson will not look for contents. We can record any address. */ 44305872bbf2SRichard Henderson [1] = { /* .text */ 44315872bbf2SRichard Henderson .sh_type = SHT_NOBITS, 44325872bbf2SRichard Henderson .sh_flags = SHF_EXECINSTR | SHF_ALLOC, 44335872bbf2SRichard Henderson }, 44345872bbf2SRichard Henderson [2] = { /* .debug_info */ 44355872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 44365872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, di), 44375872bbf2SRichard Henderson .sh_size = sizeof(struct DebugInfo), 44385872bbf2SRichard Henderson }, 44395872bbf2SRichard Henderson [3] = { /* .debug_abbrev */ 44405872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 44415872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, da), 44425872bbf2SRichard Henderson .sh_size = sizeof(img->da), 44435872bbf2SRichard Henderson }, 44445872bbf2SRichard Henderson [4] = { /* .debug_frame */ 44455872bbf2SRichard Henderson .sh_type = SHT_PROGBITS, 44465872bbf2SRichard Henderson .sh_offset = sizeof(struct ElfImage), 44475872bbf2SRichard Henderson }, 44485872bbf2SRichard Henderson [5] = { /* .symtab */ 44495872bbf2SRichard Henderson .sh_type = SHT_SYMTAB, 44505872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, sym), 44515872bbf2SRichard Henderson .sh_size = sizeof(img->sym), 44525872bbf2SRichard Henderson .sh_info = 1, 44535872bbf2SRichard Henderson .sh_link = ARRAY_SIZE(img->shdr) - 1, 44545872bbf2SRichard Henderson .sh_entsize = sizeof(ElfW(Sym)), 44555872bbf2SRichard Henderson }, 44565872bbf2SRichard Henderson [6] = { /* .strtab */ 44575872bbf2SRichard Henderson .sh_type = SHT_STRTAB, 44585872bbf2SRichard Henderson .sh_offset = offsetof(struct ElfImage, str), 44595872bbf2SRichard Henderson .sh_size = sizeof(img->str), 44605872bbf2SRichard Henderson } 44615872bbf2SRichard Henderson }, 44625872bbf2SRichard Henderson .sym = { 44635872bbf2SRichard Henderson [1] = { /* code_gen_buffer */ 44645872bbf2SRichard Henderson .st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC), 44655872bbf2SRichard Henderson .st_shndx = 1, 44665872bbf2SRichard Henderson } 44675872bbf2SRichard Henderson }, 44685872bbf2SRichard Henderson .di = { 44695872bbf2SRichard Henderson .len = sizeof(struct DebugInfo) - 4, 44705872bbf2SRichard Henderson .version = 2, 44715872bbf2SRichard Henderson .ptr_size = sizeof(void *), 44725872bbf2SRichard Henderson .cu_die = 1, 44735872bbf2SRichard Henderson .cu_lang = 0x8001, /* DW_LANG_Mips_Assembler */ 44745872bbf2SRichard Henderson .fn_die = 2, 44755872bbf2SRichard Henderson .fn_name = "code_gen_buffer" 44765872bbf2SRichard Henderson }, 44775872bbf2SRichard Henderson .da = { 44785872bbf2SRichard Henderson 1, /* abbrev number (the cu) */ 44795872bbf2SRichard Henderson 0x11, 1, /* DW_TAG_compile_unit, has children */ 44805872bbf2SRichard Henderson 0x13, 0x5, /* DW_AT_language, DW_FORM_data2 */ 44815872bbf2SRichard Henderson 0x11, 0x1, /* DW_AT_low_pc, DW_FORM_addr */ 44825872bbf2SRichard Henderson 0x12, 0x1, /* DW_AT_high_pc, DW_FORM_addr */ 44835872bbf2SRichard Henderson 0, 0, /* end of abbrev */ 44845872bbf2SRichard Henderson 2, /* abbrev number (the fn) */ 44855872bbf2SRichard Henderson 0x2e, 0, /* DW_TAG_subprogram, no children */ 44865872bbf2SRichard Henderson 0x3, 0x8, /* DW_AT_name, DW_FORM_string */ 44875872bbf2SRichard Henderson 0x11, 0x1, /* DW_AT_low_pc, DW_FORM_addr */ 44885872bbf2SRichard Henderson 0x12, 0x1, /* DW_AT_high_pc, DW_FORM_addr */ 44895872bbf2SRichard Henderson 0, 0, /* end of abbrev */ 44905872bbf2SRichard Henderson 0 /* no more abbrev */ 44915872bbf2SRichard Henderson }, 44925872bbf2SRichard Henderson .str = "\0" ".text\0" ".debug_info\0" ".debug_abbrev\0" 44935872bbf2SRichard Henderson ".debug_frame\0" ".symtab\0" ".strtab\0" "code_gen_buffer", 4494813da627SRichard Henderson }; 4495813da627SRichard Henderson 4496813da627SRichard Henderson /* We only need a single jit entry; statically allocate it. */ 4497813da627SRichard Henderson static struct jit_code_entry one_entry; 4498813da627SRichard Henderson 44995872bbf2SRichard Henderson uintptr_t buf = (uintptr_t)buf_ptr; 4500813da627SRichard Henderson size_t img_size = sizeof(struct ElfImage) + debug_frame_size; 45012c90784aSRichard Henderson DebugFrameHeader *dfh; 4502813da627SRichard Henderson 45035872bbf2SRichard Henderson img = g_malloc(img_size); 45045872bbf2SRichard Henderson *img = img_template; 4505813da627SRichard Henderson 45065872bbf2SRichard Henderson img->phdr.p_vaddr = buf; 45075872bbf2SRichard Henderson img->phdr.p_paddr = buf; 45085872bbf2SRichard Henderson img->phdr.p_memsz = buf_size; 4509813da627SRichard Henderson 45105872bbf2SRichard Henderson img->shdr[1].sh_name = find_string(img->str, ".text"); 45115872bbf2SRichard Henderson img->shdr[1].sh_addr = buf; 45125872bbf2SRichard Henderson img->shdr[1].sh_size = buf_size; 4513813da627SRichard Henderson 45145872bbf2SRichard Henderson img->shdr[2].sh_name = find_string(img->str, ".debug_info"); 45155872bbf2SRichard Henderson img->shdr[3].sh_name = find_string(img->str, ".debug_abbrev"); 45165872bbf2SRichard Henderson 45175872bbf2SRichard Henderson img->shdr[4].sh_name = find_string(img->str, ".debug_frame"); 45185872bbf2SRichard Henderson img->shdr[4].sh_size = debug_frame_size; 45195872bbf2SRichard Henderson 45205872bbf2SRichard Henderson img->shdr[5].sh_name = find_string(img->str, ".symtab"); 45215872bbf2SRichard Henderson img->shdr[6].sh_name = find_string(img->str, ".strtab"); 45225872bbf2SRichard Henderson 45235872bbf2SRichard Henderson img->sym[1].st_name = find_string(img->str, "code_gen_buffer"); 45245872bbf2SRichard Henderson img->sym[1].st_value = buf; 45255872bbf2SRichard Henderson img->sym[1].st_size = buf_size; 45265872bbf2SRichard Henderson 45275872bbf2SRichard Henderson img->di.cu_low_pc = buf; 452845aba097SRichard Henderson img->di.cu_high_pc = buf + buf_size; 45295872bbf2SRichard Henderson img->di.fn_low_pc = buf; 453045aba097SRichard Henderson img->di.fn_high_pc = buf + buf_size; 4531813da627SRichard Henderson 45322c90784aSRichard Henderson dfh = (DebugFrameHeader *)(img + 1); 45332c90784aSRichard Henderson memcpy(dfh, debug_frame, debug_frame_size); 45342c90784aSRichard Henderson dfh->fde.func_start = buf; 45352c90784aSRichard Henderson dfh->fde.func_len = buf_size; 45362c90784aSRichard Henderson 4537813da627SRichard Henderson #ifdef DEBUG_JIT 4538813da627SRichard Henderson /* Enable this block to be able to debug the ELF image file creation. 4539813da627SRichard Henderson One can use readelf, objdump, or other inspection utilities. */ 4540813da627SRichard Henderson { 4541813da627SRichard Henderson FILE *f = fopen("/tmp/qemu.jit", "w+b"); 4542813da627SRichard Henderson if (f) { 45435872bbf2SRichard Henderson if (fwrite(img, img_size, 1, f) != img_size) { 4544813da627SRichard Henderson /* Avoid stupid unused return value warning for fwrite. */ 4545813da627SRichard Henderson } 4546813da627SRichard Henderson fclose(f); 4547813da627SRichard Henderson } 4548813da627SRichard Henderson } 4549813da627SRichard Henderson #endif 4550813da627SRichard Henderson 4551813da627SRichard Henderson one_entry.symfile_addr = img; 4552813da627SRichard Henderson one_entry.symfile_size = img_size; 4553813da627SRichard Henderson 4554813da627SRichard Henderson __jit_debug_descriptor.action_flag = JIT_REGISTER_FN; 4555813da627SRichard Henderson __jit_debug_descriptor.relevant_entry = &one_entry; 4556813da627SRichard Henderson __jit_debug_descriptor.first_entry = &one_entry; 4557813da627SRichard Henderson __jit_debug_register_code(); 4558813da627SRichard Henderson } 4559813da627SRichard Henderson #else 45605872bbf2SRichard Henderson /* No support for the feature. Provide the entry point expected by exec.c, 45615872bbf2SRichard Henderson and implement the internal function we declared earlier. */ 4562813da627SRichard Henderson 4563813da627SRichard Henderson static void tcg_register_jit_int(void *buf, size_t size, 45642c90784aSRichard Henderson const void *debug_frame, 45652c90784aSRichard Henderson size_t debug_frame_size) 4566813da627SRichard Henderson { 4567813da627SRichard Henderson } 4568813da627SRichard Henderson 4569813da627SRichard Henderson void tcg_register_jit(void *buf, size_t buf_size) 4570813da627SRichard Henderson { 4571813da627SRichard Henderson } 4572813da627SRichard Henderson #endif /* ELF_HOST_MACHINE */ 4573db432672SRichard Henderson 4574db432672SRichard Henderson #if !TCG_TARGET_MAYBE_vec 4575db432672SRichard Henderson void tcg_expand_vec_op(TCGOpcode o, TCGType t, unsigned e, TCGArg a0, ...) 4576db432672SRichard Henderson { 4577db432672SRichard Henderson g_assert_not_reached(); 4578db432672SRichard Henderson } 4579db432672SRichard Henderson #endif 4580