tcg.c revision 8a68de6c5784b93a29226925982506d6d9c2d82e
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync/*
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Tiny Code Generator for QEMU
1ce069685b24d243eb0464f46d4c56b250c64445vboxsync *
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Copyright (c) 2008 Fabrice Bellard
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync *
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Permission is hereby granted, free of charge, to any person obtaining a copy
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync * of this software and associated documentation files (the "Software"), to deal
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * in the Software without restriction, including without limitation the rights
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * copies of the Software, and to permit persons to whom the Software is
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * furnished to do so, subject to the following conditions:
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync *
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * The above copyright notice and this permission notice shall be included in
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * all copies or substantial portions of the Software.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync *
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * THE SOFTWARE.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync/* define it to use liveness analysis (better code) */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#define USE_LIVENESS_ANALYSIS
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#include "config.h"
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#if !defined(CONFIG_DEBUG_TCG) && !defined(NDEBUG)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync/* define it to suppress various consistency checks (faster) */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#define NDEBUG
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#endif
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#ifndef VBOX
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#include <stdarg.h>
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#include <stdlib.h>
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#include <stdio.h>
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#include <string.h>
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#include <inttypes.h>
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#ifdef _WIN32
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync#include <malloc.h>
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync#endif
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#ifdef _AIX
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#include <alloca.h>
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#endif
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#else /* VBOX */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync# include <stdio.h>
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync# include "osdep.h"
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#endif /* VBOX */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#include "qemu-common.h"
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#include "cache-utils.h"
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#include "host-utils.h"
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#include "qemu-timer.h"
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync/* Note: the long term plan is to reduce the dependancies on the QEMU
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync CPU definitions. Currently they are used for qemu_ld/st
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync instructions */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#define NO_CPU_IO_DEFS
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#include "cpu.h"
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#include "exec-all.h"
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#include "tcg-op.h"
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#include "elf.h"
376b92d26cc4fad78e813cf33afcc0784adc9b19vboxsync
89aedeb1d8af54aba6ae46dbbd256281315c1be6vboxsync#if defined(CONFIG_USE_GUEST_BASE) && !defined(TCG_TARGET_HAS_GUEST_BASE)
89aedeb1d8af54aba6ae46dbbd256281315c1be6vboxsync#error GUEST_BASE not supported on this host.
89aedeb1d8af54aba6ae46dbbd256281315c1be6vboxsync#endif
89aedeb1d8af54aba6ae46dbbd256281315c1be6vboxsync
89aedeb1d8af54aba6ae46dbbd256281315c1be6vboxsync#ifdef VBOX
89aedeb1d8af54aba6ae46dbbd256281315c1be6vboxsync/*
89aedeb1d8af54aba6ae46dbbd256281315c1be6vboxsync * Liveness analysis doesn't work well with 32-bit hosts and 64-bit targets,
89aedeb1d8af54aba6ae46dbbd256281315c1be6vboxsync * second element of the register pair to store 64-bit value is considered
89aedeb1d8af54aba6ae46dbbd256281315c1be6vboxsync * dead, it seems. */
89aedeb1d8af54aba6ae46dbbd256281315c1be6vboxsync /** @todo re-test this */
89aedeb1d8af54aba6ae46dbbd256281315c1be6vboxsync# if defined(TARGET_X86_64) && (TCG_TARGET_REG_BITS == 32)
376b92d26cc4fad78e813cf33afcc0784adc9b19vboxsync# undef USE_LIVENESS_ANALYSIS
89aedeb1d8af54aba6ae46dbbd256281315c1be6vboxsync# endif
89aedeb1d8af54aba6ae46dbbd256281315c1be6vboxsync#endif /* VBOX */
89aedeb1d8af54aba6ae46dbbd256281315c1be6vboxsync
89aedeb1d8af54aba6ae46dbbd256281315c1be6vboxsyncstatic void tcg_target_init(TCGContext *s);
89aedeb1d8af54aba6ae46dbbd256281315c1be6vboxsyncstatic void tcg_target_qemu_prologue(TCGContext *s);
89aedeb1d8af54aba6ae46dbbd256281315c1be6vboxsyncstatic void patch_reloc(uint8_t *code_ptr, int type,
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync tcg_target_long value, tcg_target_long addend);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncstatic TCGOpDef tcg_op_defs[] = {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#define DEF(s, oargs, iargs, cargs, flags) { #s, oargs, iargs, cargs, iargs + oargs + cargs, flags },
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#include "tcg-opc.h"
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#undef DEF
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync};
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncstatic TCGRegSet tcg_target_available_regs[2];
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncstatic TCGRegSet tcg_target_call_clobber_regs;
508452243fd3328f7b9e0405d39fb9dc004e31b8vboxsync
508452243fd3328f7b9e0405d39fb9dc004e31b8vboxsync/* XXX: move that inside the context */
508452243fd3328f7b9e0405d39fb9dc004e31b8vboxsyncuint16_t *gen_opc_ptr;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncTCGArg *gen_opparam_ptr;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncstatic inline void tcg_out8(TCGContext *s, uint8_t v)
f409459bdd4c15cdb8d7fb6c6d54338cce9ac814vboxsync{
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync *s->code_ptr++ = v;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync}
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncstatic inline void tcg_out16(TCGContext *s, uint16_t v)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync{
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync *(uint16_t *)s->code_ptr = v;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync s->code_ptr += 2;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync}
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncstatic inline void tcg_out32(TCGContext *s, uint32_t v)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync{
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync *(uint32_t *)s->code_ptr = v;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync s->code_ptr += 4;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync}
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync/* label relocation processing */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncstatic void tcg_out_reloc(TCGContext *s, uint8_t *code_ptr, int type,
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync int label_index, tcg_target_long addend)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync{
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync TCGLabel *l;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync TCGRelocation *r;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync l = &s->labels[label_index];
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync if (l->has_value) {
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync /* FIXME: This may break relocations on RISC targets that
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync modify instruction fields in place. The caller may not have
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync written the initial value. */
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync patch_reloc(code_ptr, type, l->u.value, addend);
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync } else {
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync /* add a new relocation entry */
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync r = tcg_malloc(sizeof(TCGRelocation));
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync r->type = type;
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync r->ptr = code_ptr;
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync r->addend = addend;
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync r->next = l->u.first_reloc;
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync l->u.first_reloc = r;
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync }
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync}
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsyncstatic void tcg_out_label(TCGContext *s, int label_index,
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync tcg_target_long value)
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync{
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync TCGLabel *l;
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync TCGRelocation *r;
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync l = &s->labels[label_index];
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync if (l->has_value)
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync tcg_abort();
657b2c9f6d33f08001e5fa6f6e0572dcf0391013vboxsync r = l->u.first_reloc;
657b2c9f6d33f08001e5fa6f6e0572dcf0391013vboxsync while (r != NULL) {
657b2c9f6d33f08001e5fa6f6e0572dcf0391013vboxsync patch_reloc(r->ptr, r->type, value, r->addend);
657b2c9f6d33f08001e5fa6f6e0572dcf0391013vboxsync r = r->next;
657b2c9f6d33f08001e5fa6f6e0572dcf0391013vboxsync }
657b2c9f6d33f08001e5fa6f6e0572dcf0391013vboxsync l->has_value = 1;
657b2c9f6d33f08001e5fa6f6e0572dcf0391013vboxsync l->u.value = value;
657b2c9f6d33f08001e5fa6f6e0572dcf0391013vboxsync}
657b2c9f6d33f08001e5fa6f6e0572dcf0391013vboxsync
657b2c9f6d33f08001e5fa6f6e0572dcf0391013vboxsyncint gen_new_label(void)
657b2c9f6d33f08001e5fa6f6e0572dcf0391013vboxsync{
9cb702c3a5fd2287c57c7c1e98a61ba9e357b4devboxsync TCGContext *s = &tcg_ctx;
657b2c9f6d33f08001e5fa6f6e0572dcf0391013vboxsync int idx;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync TCGLabel *l;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (s->nb_labels >= TCG_MAX_LABELS)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync tcg_abort();
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync idx = s->nb_labels++;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync l = &s->labels[idx];
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync l->has_value = 0;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync l->u.first_reloc = NULL;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return idx;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync}
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#include "tcg-target.c"
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync/* pool based memory allocation */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncvoid *tcg_malloc_internal(TCGContext *s, int size)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync{
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync TCGPool *p;
ae017640afff8b6cc50453182a4edf2eb0903a12vboxsync int pool_size;
7e837ad8d6aeb3f86520ea7adb61e4eb15f2087evboxsync
7e837ad8d6aeb3f86520ea7adb61e4eb15f2087evboxsync if (size > TCG_POOL_CHUNK_SIZE) {
7e837ad8d6aeb3f86520ea7adb61e4eb15f2087evboxsync /* big malloc: insert a new pool (XXX: could optimize) */
7e837ad8d6aeb3f86520ea7adb61e4eb15f2087evboxsync p = qemu_malloc(sizeof(TCGPool) + size);
7e837ad8d6aeb3f86520ea7adb61e4eb15f2087evboxsync p->size = size;
7e837ad8d6aeb3f86520ea7adb61e4eb15f2087evboxsync if (s->pool_current)
7e837ad8d6aeb3f86520ea7adb61e4eb15f2087evboxsync s->pool_current->next = p;
7e837ad8d6aeb3f86520ea7adb61e4eb15f2087evboxsync else
7e837ad8d6aeb3f86520ea7adb61e4eb15f2087evboxsync s->pool_first = p;
7e837ad8d6aeb3f86520ea7adb61e4eb15f2087evboxsync p->next = s->pool_current;
7e837ad8d6aeb3f86520ea7adb61e4eb15f2087evboxsync } else {
7e837ad8d6aeb3f86520ea7adb61e4eb15f2087evboxsync p = s->pool_current;
7e837ad8d6aeb3f86520ea7adb61e4eb15f2087evboxsync if (!p) {
7e837ad8d6aeb3f86520ea7adb61e4eb15f2087evboxsync p = s->pool_first;
7e837ad8d6aeb3f86520ea7adb61e4eb15f2087evboxsync if (!p)
7e837ad8d6aeb3f86520ea7adb61e4eb15f2087evboxsync goto new_pool;
ae017640afff8b6cc50453182a4edf2eb0903a12vboxsync } else {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (!p->next) {
b986941f0aa5155c7fd37da0aa5876675a7680e4vboxsync new_pool:
b986941f0aa5155c7fd37da0aa5876675a7680e4vboxsync pool_size = TCG_POOL_CHUNK_SIZE;
b986941f0aa5155c7fd37da0aa5876675a7680e4vboxsync p = qemu_malloc(sizeof(TCGPool) + pool_size);
b986941f0aa5155c7fd37da0aa5876675a7680e4vboxsync p->size = pool_size;
b986941f0aa5155c7fd37da0aa5876675a7680e4vboxsync p->next = NULL;
b986941f0aa5155c7fd37da0aa5876675a7680e4vboxsync if (s->pool_current)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync s->pool_current->next = p;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync else
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync s->pool_first = p;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync } else {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync p = p->next;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync }
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync }
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync }
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync s->pool_current = p;
b986941f0aa5155c7fd37da0aa5876675a7680e4vboxsync s->pool_cur = p->data + size;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync s->pool_end = p->data + p->size;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return p->data;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync}
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncvoid tcg_pool_reset(TCGContext *s)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync{
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync s->pool_cur = s->pool_end = NULL;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync s->pool_current = NULL;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync}
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncvoid tcg_context_init(TCGContext *s)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync{
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync int op, total_args, n;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync TCGOpDef *def;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync TCGArgConstraint *args_ct;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync int *sorted_args;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync memset(s, 0, sizeof(*s));
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync s->temps = s->static_temps;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync s->nb_globals = 0;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync /* Count total number of arguments and allocate the corresponding
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync space */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync total_args = 0;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync for(op = 0; op < NB_OPS; op++) {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync def = &tcg_op_defs[op];
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync n = def->nb_iargs + def->nb_oargs;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync total_args += n;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync }
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync args_ct = qemu_malloc(sizeof(TCGArgConstraint) * total_args);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync sorted_args = qemu_malloc(sizeof(int) * total_args);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
42aef05f4b27fb393967e581be04be455064c80avboxsync for(op = 0; op < NB_OPS; op++) {
42aef05f4b27fb393967e581be04be455064c80avboxsync def = &tcg_op_defs[op];
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync def->args_ct = args_ct;
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync def->sorted_args = sorted_args;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync n = def->nb_iargs + def->nb_oargs;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync sorted_args += n;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync args_ct += n;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync }
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync tcg_target_init(s);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync}
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsyncvoid tcg_prologue_init(TCGContext *s)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync{
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync /* init global prologue and epilogue */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync s->code_buf = code_gen_prologue;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync s->code_ptr = s->code_buf;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync tcg_target_qemu_prologue(s);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync flush_icache_range((uintptr_t)s->code_buf,
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync (uintptr_t)s->code_ptr);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync}
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsyncvoid tcg_set_frame(TCGContext *s, int reg,
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync tcg_target_long start, tcg_target_long size)
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync{
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync s->frame_start = start;
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync s->frame_end = start + size;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync s->frame_reg = reg;
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync}
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncvoid tcg_func_start(TCGContext *s)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync{
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync int i;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync tcg_pool_reset(s);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync s->nb_temps = s->nb_globals;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync for(i = 0; i < (TCG_TYPE_COUNT * 2); i++)
89aedeb1d8af54aba6ae46dbbd256281315c1be6vboxsync s->first_free_temp[i] = -1;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync s->labels = tcg_malloc(sizeof(TCGLabel) * TCG_MAX_LABELS);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync s->nb_labels = 0;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync s->current_frame_offset = s->frame_start;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync gen_opc_ptr = gen_opc_buf;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync gen_opparam_ptr = gen_opparam_buf;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync}
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncstatic inline void tcg_temp_alloc(TCGContext *s, int n)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync{
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (n > TCG_MAX_TEMPS)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync tcg_abort();
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync}
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncstatic inline int tcg_global_reg_new_internal(TCGType type, int reg,
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync const char *name)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync{
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync TCGContext *s = &tcg_ctx;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync TCGTemp *ts;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync int idx;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#if TCG_TARGET_REG_BITS == 32
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (type != TCG_TYPE_I32)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync tcg_abort();
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#endif
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (tcg_regset_test_reg(s->reserved_regs, reg))
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync tcg_abort();
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync idx = s->nb_globals;
e48239695d41f806ff02d8a60b97dc20d4822d7avboxsync tcg_temp_alloc(s, s->nb_globals + 1);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync ts = &s->temps[s->nb_globals];
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync ts->base_type = type;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync ts->type = type;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync ts->fixed_reg = 1;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync ts->reg = reg;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync ts->name = name;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync s->nb_globals++;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync tcg_regset_set_reg(s->reserved_regs, reg);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return idx;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync}
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncTCGv_i32 tcg_global_reg_new_i32(int reg, const char *name)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync{
89aedeb1d8af54aba6ae46dbbd256281315c1be6vboxsync int idx;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync idx = tcg_global_reg_new_internal(TCG_TYPE_I32, reg, name);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return MAKE_TCGV_I32(idx);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync}
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncTCGv_i64 tcg_global_reg_new_i64(int reg, const char *name)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync{
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync int idx;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync idx = tcg_global_reg_new_internal(TCG_TYPE_I64, reg, name);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return MAKE_TCGV_I64(idx);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync}
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncstatic inline int tcg_global_mem_new_internal(TCGType type, int reg,
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync tcg_target_long offset,
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync const char *name)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync{
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync TCGContext *s = &tcg_ctx;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync TCGTemp *ts;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync int idx;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync idx = s->nb_globals;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#if TCG_TARGET_REG_BITS == 32
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (type == TCG_TYPE_I64) {
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync char buf[64];
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync tcg_temp_alloc(s, s->nb_globals + 2);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync ts = &s->temps[s->nb_globals];
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync ts->base_type = type;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync ts->type = TCG_TYPE_I32;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync ts->fixed_reg = 0;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync ts->mem_allocated = 1;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync ts->mem_reg = reg;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#ifdef TCG_TARGET_WORDS_BIGENDIAN
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync ts->mem_offset = offset + 4;
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync#else
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync ts->mem_offset = offset;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#endif
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync pstrcpy(buf, sizeof(buf), name);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync pstrcat(buf, sizeof(buf), "_0");
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync ts->name = strdup(buf);
89aedeb1d8af54aba6ae46dbbd256281315c1be6vboxsync ts++;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync ts->base_type = type;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync ts->type = TCG_TYPE_I32;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync ts->fixed_reg = 0;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync ts->mem_allocated = 1;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync ts->mem_reg = reg;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#ifdef TCG_TARGET_WORDS_BIGENDIAN
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync ts->mem_offset = offset;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#else
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync ts->mem_offset = offset + 4;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#endif
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync pstrcpy(buf, sizeof(buf), name);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync pstrcat(buf, sizeof(buf), "_1");
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync ts->name = strdup(buf);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync s->nb_globals += 2;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync } else
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#endif
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync tcg_temp_alloc(s, s->nb_globals + 1);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync ts = &s->temps[s->nb_globals];
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync ts->base_type = type;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync ts->type = type;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync ts->fixed_reg = 0;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync ts->mem_allocated = 1;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync ts->mem_reg = reg;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync ts->mem_offset = offset;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync ts->name = name;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync s->nb_globals++;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync }
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return idx;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync}
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
e48239695d41f806ff02d8a60b97dc20d4822d7avboxsyncTCGv_i32 tcg_global_mem_new_i32(int reg, tcg_target_long offset,
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync const char *name)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync{
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync int idx;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync idx = tcg_global_mem_new_internal(TCG_TYPE_I32, reg, offset, name);
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync return MAKE_TCGV_I32(idx);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync}
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4f3d37f3c8ea851c3d57304fac430764b77a84dcvboxsyncTCGv_i64 tcg_global_mem_new_i64(int reg, tcg_target_long offset,
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync const char *name)
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync{
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync int idx;
89aedeb1d8af54aba6ae46dbbd256281315c1be6vboxsync
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync idx = tcg_global_mem_new_internal(TCG_TYPE_I64, reg, offset, name);
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync return MAKE_TCGV_I64(idx);
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync}
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsyncstatic inline int tcg_temp_new_internal(TCGType type, int temp_local)
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync{
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync TCGContext *s = &tcg_ctx;
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync TCGTemp *ts;
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync int idx, k;
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync k = type;
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync if (temp_local)
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync k += TCG_TYPE_COUNT;
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync idx = s->first_free_temp[k];
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync if (idx != -1) {
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync /* There is already an available temp with the
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync right type */
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync ts = &s->temps[idx];
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync s->first_free_temp[k] = ts->next_free_temp;
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync ts->temp_allocated = 1;
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync assert(ts->temp_local == temp_local);
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync } else {
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync idx = s->nb_temps;
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync#if TCG_TARGET_REG_BITS == 32
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync if (type == TCG_TYPE_I64) {
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync tcg_temp_alloc(s, s->nb_temps + 2);
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync ts = &s->temps[s->nb_temps];
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync ts->base_type = type;
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync ts->type = TCG_TYPE_I32;
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync ts->temp_allocated = 1;
4f3d37f3c8ea851c3d57304fac430764b77a84dcvboxsync ts->temp_local = temp_local;
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync ts->name = NULL;
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync ts++;
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync ts->base_type = TCG_TYPE_I32;
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync ts->type = TCG_TYPE_I32;
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync ts->temp_allocated = 1;
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync ts->temp_local = temp_local;
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync ts->name = NULL;
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync s->nb_temps += 2;
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync } else
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync#endif
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync {
8ccde4f32d77b1ad3f02111f28a48ee85abf6779vboxsync tcg_temp_alloc(s, s->nb_temps + 1);
8ccde4f32d77b1ad3f02111f28a48ee85abf6779vboxsync ts = &s->temps[s->nb_temps];
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync ts->base_type = type;
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync ts->type = type;
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync ts->temp_allocated = 1;
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync ts->temp_local = temp_local;
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync ts->name = NULL;
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync s->nb_temps++;
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync }
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync }
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync return idx;
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync}
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsyncTCGv_i32 tcg_temp_new_internal_i32(int temp_local)
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync{
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync int idx;
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync idx = tcg_temp_new_internal(TCG_TYPE_I32, temp_local);
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync return MAKE_TCGV_I32(idx);
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync}
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsyncTCGv_i64 tcg_temp_new_internal_i64(int temp_local)
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync{
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync int idx;
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync idx = tcg_temp_new_internal(TCG_TYPE_I64, temp_local);
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync return MAKE_TCGV_I64(idx);
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync}
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsyncstatic inline void tcg_temp_free_internal(int idx)
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync{
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync TCGContext *s = &tcg_ctx;
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync TCGTemp *ts;
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync int k;
8ccde4f32d77b1ad3f02111f28a48ee85abf6779vboxsync
8ccde4f32d77b1ad3f02111f28a48ee85abf6779vboxsync assert(idx >= s->nb_globals && idx < s->nb_temps);
8ccde4f32d77b1ad3f02111f28a48ee85abf6779vboxsync ts = &s->temps[idx];
8ccde4f32d77b1ad3f02111f28a48ee85abf6779vboxsync assert(ts->temp_allocated != 0);
8ccde4f32d77b1ad3f02111f28a48ee85abf6779vboxsync ts->temp_allocated = 0;
8ccde4f32d77b1ad3f02111f28a48ee85abf6779vboxsync k = ts->base_type;
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync if (ts->temp_local)
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync k += TCG_TYPE_COUNT;
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync ts->next_free_temp = s->first_free_temp[k];
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync s->first_free_temp[k] = idx;
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync}
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsyncvoid tcg_temp_free_i32(TCGv_i32 arg)
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync{
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync tcg_temp_free_internal(GET_TCGV_I32(arg));
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync}
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
89aedeb1d8af54aba6ae46dbbd256281315c1be6vboxsyncvoid tcg_temp_free_i64(TCGv_i64 arg)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync{
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync tcg_temp_free_internal(GET_TCGV_I64(arg));
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync}
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncTCGv_i32 tcg_const_i32(int32_t val)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync{
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync TCGv_i32 t0;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync t0 = tcg_temp_new_i32();
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync tcg_gen_movi_i32(t0, val);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return t0;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync}
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncTCGv_i64 tcg_const_i64(int64_t val)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync{
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync TCGv_i64 t0;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync t0 = tcg_temp_new_i64();
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync tcg_gen_movi_i64(t0, val);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return t0;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync}
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncTCGv_i32 tcg_const_local_i32(int32_t val)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync{
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync TCGv_i32 t0;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync t0 = tcg_temp_local_new_i32();
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync tcg_gen_movi_i32(t0, val);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return t0;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync}
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncTCGv_i64 tcg_const_local_i64(int64_t val)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync{
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync TCGv_i64 t0;
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync t0 = tcg_temp_local_new_i64();
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync tcg_gen_movi_i64(t0, val);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return t0;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync}
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncvoid tcg_register_helper(void *func, const char *name)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync{
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync TCGContext *s = &tcg_ctx;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync int n;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if ((s->nb_helpers + 1) > s->allocated_helpers) {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync n = s->allocated_helpers;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (n == 0) {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync n = 4;
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync } else {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync n *= 2;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync }
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#ifdef VBOX
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync s->helpers = qemu_realloc(s->helpers, n * sizeof(TCGHelperInfo));
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#else
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync s->helpers = realloc(s->helpers, n * sizeof(TCGHelperInfo));
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#endif
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync s->allocated_helpers = n;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync }
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync s->helpers[s->nb_helpers].func = (tcg_target_ulong)func;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync s->helpers[s->nb_helpers].name = name;
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync s->nb_helpers++;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync}
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync/* Note: we convert the 64 bit args to 32 bit and do some alignment
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync and endian swap. Maybe it would be better to do the alignment
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync and endian swap in tcg_reg_alloc_call(). */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncvoid tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags,
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync int sizemask, TCGArg ret, int nargs, TCGArg *args)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync{
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#ifdef TCG_TARGET_I386
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync int call_type;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#endif
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync int i;
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync int real_args;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync int nb_rets;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync TCGArg *nparam;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#if defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync for (i = 0; i < nargs; ++i) {
e48239695d41f806ff02d8a60b97dc20d4822d7avboxsync int is_64bit = sizemask & (1 << (i+1)*2);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync int is_signed = sizemask & (2 << (i+1)*2);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (!is_64bit) {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync TCGv_i64 temp = tcg_temp_new_i64();
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync TCGv_i64 orig = MAKE_TCGV_I64(args[i]);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (is_signed) {
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync tcg_gen_ext32s_i64(temp, orig);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync } else {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync tcg_gen_ext32u_i64(temp, orig);
3933885bc0c2c93436d858a14564c6179ec72872vboxsync }
3933885bc0c2c93436d858a14564c6179ec72872vboxsync args[i] = GET_TCGV_I64(temp);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync }
3933885bc0c2c93436d858a14564c6179ec72872vboxsync }
3933885bc0c2c93436d858a14564c6179ec72872vboxsync#endif /* TCG_TARGET_EXTEND_ARGS */
3933885bc0c2c93436d858a14564c6179ec72872vboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync *gen_opc_ptr++ = INDEX_op_call;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync nparam = gen_opparam_ptr++;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#ifdef TCG_TARGET_I386
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync call_type = (flags & TCG_CALL_TYPE_MASK);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#endif
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (ret != TCG_CALL_DUMMY_ARG) {
3933885bc0c2c93436d858a14564c6179ec72872vboxsync#if TCG_TARGET_REG_BITS < 64
3933885bc0c2c93436d858a14564c6179ec72872vboxsync if (sizemask & 1) {
3933885bc0c2c93436d858a14564c6179ec72872vboxsync#ifdef TCG_TARGET_WORDS_BIGENDIAN
3933885bc0c2c93436d858a14564c6179ec72872vboxsync *gen_opparam_ptr++ = ret + 1;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync *gen_opparam_ptr++ = ret;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#else
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync *gen_opparam_ptr++ = ret;
3933885bc0c2c93436d858a14564c6179ec72872vboxsync *gen_opparam_ptr++ = ret + 1;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#endif
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync nb_rets = 2;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync } else
3933885bc0c2c93436d858a14564c6179ec72872vboxsync#endif
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync *gen_opparam_ptr++ = ret;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync nb_rets = 1;
3933885bc0c2c93436d858a14564c6179ec72872vboxsync }
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync } else {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync nb_rets = 0;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync }
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync real_args = 0;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync for (i = 0; i < nargs; i++) {
36a04912b64bea8318327fe0723535f1b3f041b0vboxsync#if TCG_TARGET_REG_BITS < 64
36a04912b64bea8318327fe0723535f1b3f041b0vboxsync int is_64bit = sizemask & (1 << (i+1)*2);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (is_64bit) {
36a04912b64bea8318327fe0723535f1b3f041b0vboxsync#ifdef TCG_TARGET_I386
36a04912b64bea8318327fe0723535f1b3f041b0vboxsync /* REGPARM case: if the third parameter is 64 bit, it is
36a04912b64bea8318327fe0723535f1b3f041b0vboxsync allocated on the stack */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (i == 2 && call_type == TCG_CALL_TYPE_REGPARM) {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync call_type = TCG_CALL_TYPE_REGPARM_2;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync flags = (flags & ~TCG_CALL_TYPE_MASK) | call_type;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync }
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#endif
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#ifdef TCG_TARGET_CALL_ALIGN_ARGS
a72b5355eb89aafe6bfcc8912cf02645d7cccceavboxsync /* some targets want aligned 64 bit args */
3933885bc0c2c93436d858a14564c6179ec72872vboxsync if (real_args & 1) {
3933885bc0c2c93436d858a14564c6179ec72872vboxsync *gen_opparam_ptr++ = TCG_CALL_DUMMY_ARG;
3933885bc0c2c93436d858a14564c6179ec72872vboxsync real_args++;
3933885bc0c2c93436d858a14564c6179ec72872vboxsync }
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#endif
3933885bc0c2c93436d858a14564c6179ec72872vboxsync /* If stack grows up, then we will be placing successive
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync arguments at lower addresses, which means we need to
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync reverse the order compared to how we would normally
3933885bc0c2c93436d858a14564c6179ec72872vboxsync treat either big or little-endian. For those arguments
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync that will wind up in registers, this still works for
3933885bc0c2c93436d858a14564c6179ec72872vboxsync HPPA (the only current STACK_GROWSUP target) since the
3933885bc0c2c93436d858a14564c6179ec72872vboxsync argument registers are *also* allocated in decreasing
3933885bc0c2c93436d858a14564c6179ec72872vboxsync order. If another such target is added, this logic may
3933885bc0c2c93436d858a14564c6179ec72872vboxsync have to get more complicated to differentiate between
3933885bc0c2c93436d858a14564c6179ec72872vboxsync stack arguments and register arguments. */
3933885bc0c2c93436d858a14564c6179ec72872vboxsync#if defined(TCG_TARGET_WORDS_BIGENDIAN) != defined(TCG_TARGET_STACK_GROWSUP)
3933885bc0c2c93436d858a14564c6179ec72872vboxsync *gen_opparam_ptr++ = args[i] + 1;
3933885bc0c2c93436d858a14564c6179ec72872vboxsync *gen_opparam_ptr++ = args[i];
3933885bc0c2c93436d858a14564c6179ec72872vboxsync#else
3933885bc0c2c93436d858a14564c6179ec72872vboxsync *gen_opparam_ptr++ = args[i];
3933885bc0c2c93436d858a14564c6179ec72872vboxsync *gen_opparam_ptr++ = args[i] + 1;
3933885bc0c2c93436d858a14564c6179ec72872vboxsync#endif
3933885bc0c2c93436d858a14564c6179ec72872vboxsync real_args += 2;
3933885bc0c2c93436d858a14564c6179ec72872vboxsync continue;
3933885bc0c2c93436d858a14564c6179ec72872vboxsync }
3933885bc0c2c93436d858a14564c6179ec72872vboxsync#endif /* TCG_TARGET_REG_BITS < 64 */
3933885bc0c2c93436d858a14564c6179ec72872vboxsync
3933885bc0c2c93436d858a14564c6179ec72872vboxsync *gen_opparam_ptr++ = args[i];
3933885bc0c2c93436d858a14564c6179ec72872vboxsync real_args++;
3933885bc0c2c93436d858a14564c6179ec72872vboxsync }
3933885bc0c2c93436d858a14564c6179ec72872vboxsync *gen_opparam_ptr++ = GET_TCGV_PTR(func);
3933885bc0c2c93436d858a14564c6179ec72872vboxsync
060f7ec6ae5c99df18341ef2e1f3e91f4b0c89f1vboxsync *gen_opparam_ptr++ = flags;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
060f7ec6ae5c99df18341ef2e1f3e91f4b0c89f1vboxsync *nparam = (nb_rets << 16) | (real_args + 1);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync /* total parameters, needed to go backward in the instruction stream */
cc74f15083bf80fbc96723a89faa06c15d0dead8vboxsync *gen_opparam_ptr++ = 1 + nb_rets + real_args + 3;
70ca8d009d026a301bf7fa08cd18c6494c45fdeevboxsync
70ca8d009d026a301bf7fa08cd18c6494c45fdeevboxsync#if defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
70ca8d009d026a301bf7fa08cd18c6494c45fdeevboxsync for (i = 0; i < nargs; ++i) {
70ca8d009d026a301bf7fa08cd18c6494c45fdeevboxsync int is_64bit = sizemask & (1 << (i+1)*2);
70ca8d009d026a301bf7fa08cd18c6494c45fdeevboxsync if (!is_64bit) {
70ca8d009d026a301bf7fa08cd18c6494c45fdeevboxsync TCGv_i64 temp = MAKE_TCGV_I64(args[i]);
70ca8d009d026a301bf7fa08cd18c6494c45fdeevboxsync tcg_temp_free_i64(temp);
3933885bc0c2c93436d858a14564c6179ec72872vboxsync }
3933885bc0c2c93436d858a14564c6179ec72872vboxsync }
3933885bc0c2c93436d858a14564c6179ec72872vboxsync#endif /* TCG_TARGET_EXTEND_ARGS */
3933885bc0c2c93436d858a14564c6179ec72872vboxsync}
70ca8d009d026a301bf7fa08cd18c6494c45fdeevboxsync
3933885bc0c2c93436d858a14564c6179ec72872vboxsync#if TCG_TARGET_REG_BITS == 32
3933885bc0c2c93436d858a14564c6179ec72872vboxsyncvoid tcg_gen_shifti_i64(TCGv_i64 ret, TCGv_i64 arg1,
3933885bc0c2c93436d858a14564c6179ec72872vboxsync int c, int right, int arith)
3933885bc0c2c93436d858a14564c6179ec72872vboxsync{
3933885bc0c2c93436d858a14564c6179ec72872vboxsync if (c == 0) {
3933885bc0c2c93436d858a14564c6179ec72872vboxsync tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg1));
3933885bc0c2c93436d858a14564c6179ec72872vboxsync tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1));
3933885bc0c2c93436d858a14564c6179ec72872vboxsync } else if (c >= 32) {
70ca8d009d026a301bf7fa08cd18c6494c45fdeevboxsync c -= 32;
3933885bc0c2c93436d858a14564c6179ec72872vboxsync if (right) {
3933885bc0c2c93436d858a14564c6179ec72872vboxsync if (arith) {
3933885bc0c2c93436d858a14564c6179ec72872vboxsync tcg_gen_sari_i32(TCGV_LOW(ret), TCGV_HIGH(arg1), c);
3933885bc0c2c93436d858a14564c6179ec72872vboxsync tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), 31);
3933885bc0c2c93436d858a14564c6179ec72872vboxsync } else {
3933885bc0c2c93436d858a14564c6179ec72872vboxsync tcg_gen_shri_i32(TCGV_LOW(ret), TCGV_HIGH(arg1), c);
cc74f15083bf80fbc96723a89faa06c15d0dead8vboxsync tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
3933885bc0c2c93436d858a14564c6179ec72872vboxsync }
3933885bc0c2c93436d858a14564c6179ec72872vboxsync } else {
3933885bc0c2c93436d858a14564c6179ec72872vboxsync tcg_gen_shli_i32(TCGV_HIGH(ret), TCGV_LOW(arg1), c);
3933885bc0c2c93436d858a14564c6179ec72872vboxsync tcg_gen_movi_i32(TCGV_LOW(ret), 0);
3933885bc0c2c93436d858a14564c6179ec72872vboxsync }
3933885bc0c2c93436d858a14564c6179ec72872vboxsync } else {
3933885bc0c2c93436d858a14564c6179ec72872vboxsync TCGv_i32 t0, t1;
3933885bc0c2c93436d858a14564c6179ec72872vboxsync
3933885bc0c2c93436d858a14564c6179ec72872vboxsync t0 = tcg_temp_new_i32();
3933885bc0c2c93436d858a14564c6179ec72872vboxsync t1 = tcg_temp_new_i32();
3933885bc0c2c93436d858a14564c6179ec72872vboxsync if (right) {
3933885bc0c2c93436d858a14564c6179ec72872vboxsync tcg_gen_shli_i32(t0, TCGV_HIGH(arg1), 32 - c);
3933885bc0c2c93436d858a14564c6179ec72872vboxsync if (arith)
3933885bc0c2c93436d858a14564c6179ec72872vboxsync tcg_gen_sari_i32(t1, TCGV_HIGH(arg1), c);
70ca8d009d026a301bf7fa08cd18c6494c45fdeevboxsync else
70ca8d009d026a301bf7fa08cd18c6494c45fdeevboxsync tcg_gen_shri_i32(t1, TCGV_HIGH(arg1), c);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync tcg_gen_shri_i32(TCGV_LOW(ret), TCGV_LOW(arg1), c);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync tcg_gen_or_i32(TCGV_LOW(ret), TCGV_LOW(ret), t0);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync tcg_gen_mov_i32(TCGV_HIGH(ret), t1);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync } else {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync tcg_gen_shri_i32(t0, TCGV_LOW(arg1), 32 - c);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync /* Note: ret can be the same as arg1, so we use t1 */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync tcg_gen_shli_i32(t1, TCGV_LOW(arg1), c);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync tcg_gen_shli_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), c);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync tcg_gen_or_i32(TCGV_HIGH(ret), TCGV_HIGH(ret), t0);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync tcg_gen_mov_i32(TCGV_LOW(ret), t1);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync }
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync tcg_temp_free_i32(t0);
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync tcg_temp_free_i32(t1);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync }
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync}
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#endif
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncstatic void tcg_reg_alloc_start(TCGContext *s)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync{
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync int i;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync TCGTemp *ts;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync for(i = 0; i < s->nb_globals; i++) {
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync ts = &s->temps[i];
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync if (ts->fixed_reg) {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync ts->val_type = TEMP_VAL_REG;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync } else {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync ts->val_type = TEMP_VAL_MEM;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync }
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync }
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync for(i = s->nb_globals; i < s->nb_temps; i++) {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync ts = &s->temps[i];
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync ts->val_type = TEMP_VAL_DEAD;
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync ts->mem_allocated = 0;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync ts->fixed_reg = 0;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync }
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync s->reg_to_temp[i] = -1;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync }
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync}
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncstatic char *tcg_get_arg_str_idx(TCGContext *s, char *buf, int buf_size,
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync int idx)
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync{
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync TCGTemp *ts;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync ts = &s->temps[idx];
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (idx < s->nb_globals) {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync pstrcpy(buf, buf_size, ts->name);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync } else {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (ts->temp_local)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync snprintf(buf, buf_size, "loc%d", idx - s->nb_globals);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync else
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync }
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return buf;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync}
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncchar *tcg_get_arg_str_i32(TCGContext *s, char *buf, int buf_size, TCGv_i32 arg)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync{
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return tcg_get_arg_str_idx(s, buf, buf_size, GET_TCGV_I32(arg));
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync}
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncchar *tcg_get_arg_str_i64(TCGContext *s, char *buf, int buf_size, TCGv_i64 arg)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync{
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return tcg_get_arg_str_idx(s, buf, buf_size, GET_TCGV_I64(arg));
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync}
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncstatic int helper_cmp(const void *p1, const void *p2)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync{
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync const TCGHelperInfo *th1 = p1;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync const TCGHelperInfo *th2 = p2;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (th1->func < th2->func)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return -1;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync else if (th1->func == th2->func)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return 0;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync else
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return 1;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync}
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync/* find helper definition (Note: A hash table would be better) */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncstatic TCGHelperInfo *tcg_find_helper(TCGContext *s, tcg_target_ulong val)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync{
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync int m, m_min, m_max;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync TCGHelperInfo *th;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync tcg_target_ulong v;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (unlikely(!s->helpers_sorted)) {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#ifdef VBOX
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync qemu_qsort(s->helpers, s->nb_helpers, sizeof(TCGHelperInfo),
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync helper_cmp);
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync#else
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync qsort(s->helpers, s->nb_helpers, sizeof(TCGHelperInfo),
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync helper_cmp);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#endif
c9e3f6ad81ea9a279ffb537720699e552882c40avboxsync s->helpers_sorted = 1;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync }
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync /* binary search */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync m_min = 0;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync m_max = s->nb_helpers - 1;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync while (m_min <= m_max) {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync m = (m_min + m_max) >> 1;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync th = &s->helpers[m];
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync v = th->func;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (v == val)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return th;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync else if (val < v) {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync m_max = m - 1;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync } else {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync m_min = m + 1;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync }
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync }
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return NULL;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync}
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncstatic const char * const cond_name[] =
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync{
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync [TCG_COND_EQ] = "eq",
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync [TCG_COND_NE] = "ne",
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync [TCG_COND_LT] = "lt",
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync [TCG_COND_GE] = "ge",
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync [TCG_COND_LE] = "le",
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync [TCG_COND_GT] = "gt",
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync [TCG_COND_LTU] = "ltu",
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync [TCG_COND_GEU] = "geu",
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync [TCG_COND_LEU] = "leu",
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync [TCG_COND_GTU] = "gtu"
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync};
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncvoid tcg_dump_ops(TCGContext *s, FILE *outfile)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync{
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync const uint16_t *opc_ptr;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync const TCGArg *args;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync TCGArg arg;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync TCGOpcode c;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync int i, k, nb_oargs, nb_iargs, nb_cargs, first_insn;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync const TCGOpDef *def;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync char buf[128];
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync first_insn = 1;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync opc_ptr = gen_opc_buf;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync args = gen_opparam_buf;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync while (opc_ptr < gen_opc_ptr) {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync c = *opc_ptr++;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync def = &tcg_op_defs[c];
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (c == INDEX_op_debug_insn_start) {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync uint64_t pc;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync pc = ((uint64_t)args[1] << 32) | args[0];
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#else
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync pc = args[0];
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#endif
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (!first_insn)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync fprintf(outfile, "\n");
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync fprintf(outfile, " ---- 0x%" PRIx64, pc);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync first_insn = 0;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync nb_oargs = def->nb_oargs;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync nb_iargs = def->nb_iargs;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync nb_cargs = def->nb_cargs;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync } else if (c == INDEX_op_call) {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync TCGArg arg;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync /* variable number of arguments */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync arg = *args++;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync nb_oargs = arg >> 16;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync nb_iargs = arg & 0xffff;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync nb_cargs = def->nb_cargs;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync fprintf(outfile, " %s ", def->name);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync /* function name */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync fprintf(outfile, "%s",
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync tcg_get_arg_str_idx(s, buf, sizeof(buf), args[nb_oargs + nb_iargs - 1]));
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync /* flags */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync fprintf(outfile, ",$0x%" TCG_PRIlx,
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync args[nb_oargs + nb_iargs]);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync /* nb out args */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync fprintf(outfile, ",$%d", nb_oargs);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync for(i = 0; i < nb_oargs; i++) {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync fprintf(outfile, ",");
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync fprintf(outfile, "%s",
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync tcg_get_arg_str_idx(s, buf, sizeof(buf), args[i]));
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync }
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync for(i = 0; i < (nb_iargs - 1); i++) {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync fprintf(outfile, ",");
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (args[nb_oargs + i] == TCG_CALL_DUMMY_ARG) {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync fprintf(outfile, "<dummy>");
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync } else {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync fprintf(outfile, "%s",
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync tcg_get_arg_str_idx(s, buf, sizeof(buf), args[nb_oargs + i]));
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync }
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync }
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync } else if (c == INDEX_op_movi_i32
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#if TCG_TARGET_REG_BITS == 64
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync || c == INDEX_op_movi_i64
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#endif
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync ) {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync tcg_target_ulong val;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync TCGHelperInfo *th;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync nb_oargs = def->nb_oargs;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync nb_iargs = def->nb_iargs;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync nb_cargs = def->nb_cargs;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync fprintf(outfile, " %s %s,$", def->name,
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync tcg_get_arg_str_idx(s, buf, sizeof(buf), args[0]));
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync val = args[1];
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync th = tcg_find_helper(s, val);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (th) {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync fprintf(outfile, "%s", th->name);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync } else {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (c == INDEX_op_movi_i32)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync fprintf(outfile, "0x%x", (uint32_t)val);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync else
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync fprintf(outfile, "0x%" PRIx64 , (uint64_t)val);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync }
c9e3f6ad81ea9a279ffb537720699e552882c40avboxsync } else {
21ed14a0d745501ffc9a68be81c0abadc777b628vboxsync fprintf(outfile, " %s ", def->name);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (c == INDEX_op_nopn) {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync /* variable number of arguments */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync nb_cargs = *args;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync nb_oargs = 0;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync nb_iargs = 0;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync } else {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync nb_oargs = def->nb_oargs;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync nb_iargs = def->nb_iargs;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync nb_cargs = def->nb_cargs;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync }
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync k = 0;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync for(i = 0; i < nb_oargs; i++) {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (k != 0)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync fprintf(outfile, ",");
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync fprintf(outfile, "%s",
629169500a4e1696f37dd3118a791d68278f71davboxsync tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++]));
629169500a4e1696f37dd3118a791d68278f71davboxsync }
629169500a4e1696f37dd3118a791d68278f71davboxsync for(i = 0; i < nb_iargs; i++) {
629169500a4e1696f37dd3118a791d68278f71davboxsync if (k != 0)
629169500a4e1696f37dd3118a791d68278f71davboxsync fprintf(outfile, ",");
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync fprintf(outfile, "%s",
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++]));
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync }
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync switch (c) {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync case INDEX_op_brcond_i32:
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#if TCG_TARGET_REG_BITS == 32
b2c92fb03e119c7de54f86a32fae9c1d59bc479evboxsync case INDEX_op_brcond2_i32:
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#elif TCG_TARGET_REG_BITS == 64
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync case INDEX_op_brcond_i64:
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#endif
4c13f0d619c9707412b40eae8e3beafae5cf1858vboxsync case INDEX_op_setcond_i32:
4c13f0d619c9707412b40eae8e3beafae5cf1858vboxsync#if TCG_TARGET_REG_BITS == 32
4c13f0d619c9707412b40eae8e3beafae5cf1858vboxsync case INDEX_op_setcond2_i32:
4c13f0d619c9707412b40eae8e3beafae5cf1858vboxsync#elif TCG_TARGET_REG_BITS == 64
4c13f0d619c9707412b40eae8e3beafae5cf1858vboxsync case INDEX_op_setcond_i64:
4c13f0d619c9707412b40eae8e3beafae5cf1858vboxsync#endif
4c13f0d619c9707412b40eae8e3beafae5cf1858vboxsync if (args[k] < ARRAY_SIZE(cond_name) && cond_name[args[k]])
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync fprintf(outfile, ",%s", cond_name[args[k++]]);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync else
fb1975a6972d89de9e515bed0248db93f04ec9d8vboxsync fprintf(outfile, ",$0x%" TCG_PRIlx, args[k++]);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync i = 1;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync break;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync default:
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync i = 0;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync break;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync }
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync for(; i < nb_cargs; i++) {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (k != 0)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync fprintf(outfile, ",");
4c13f0d619c9707412b40eae8e3beafae5cf1858vboxsync arg = args[k++];
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync fprintf(outfile, "$0x%" TCG_PRIlx, arg);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync }
b2c92fb03e119c7de54f86a32fae9c1d59bc479evboxsync }
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync fprintf(outfile, "\n");
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync args += nb_iargs + nb_oargs + nb_cargs;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync }
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync}
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync/* we give more priority to constraints with less registers */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncstatic int get_constraint_priority(const TCGOpDef *def, int k)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync{
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync const TCGArgConstraint *arg_ct;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync int i, n;
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync arg_ct = &def->args_ct[k];
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync if (arg_ct->ct & TCG_CT_ALIAS) {
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync /* an alias is equivalent to a single register */
b2c92fb03e119c7de54f86a32fae9c1d59bc479evboxsync n = 1;
b2c92fb03e119c7de54f86a32fae9c1d59bc479evboxsync } else {
b2c92fb03e119c7de54f86a32fae9c1d59bc479evboxsync if (!(arg_ct->ct & TCG_CT_REG))
b2c92fb03e119c7de54f86a32fae9c1d59bc479evboxsync return 0;
b2c92fb03e119c7de54f86a32fae9c1d59bc479evboxsync n = 0;
b2c92fb03e119c7de54f86a32fae9c1d59bc479evboxsync for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
b2c92fb03e119c7de54f86a32fae9c1d59bc479evboxsync if (tcg_regset_test_reg(arg_ct->u.regs, i))
b2c92fb03e119c7de54f86a32fae9c1d59bc479evboxsync n++;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync }
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync }
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return TCG_TARGET_NB_REGS - n + 1;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync}
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync/* sort from highest priority to lowest */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncstatic void sort_constraints(TCGOpDef *def, int start, int n)
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync{
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync int i, j, p1, p2, tmp;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync for(i = 0; i < n; i++)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync def->sorted_args[start + i] = start + i;
1ce069685b24d243eb0464f46d4c56b250c64445vboxsync if (n <= 1)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync for(i = 0; i < n - 1; i++) {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync for(j = i + 1; j < n; j++) {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync p1 = get_constraint_priority(def, def->sorted_args[start + i]);
825c2485cf84eec495985ffd605a1c9cddee8c32vboxsync p2 = get_constraint_priority(def, def->sorted_args[start + j]);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (p1 < p2) {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync tmp = def->sorted_args[start + i];
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync def->sorted_args[start + i] = def->sorted_args[start + j];
def->sorted_args[start + j] = tmp;
}
}
}
}
void tcg_add_target_add_op_defs(const TCGTargetOpDef *tdefs)
{
TCGOpcode op;
TCGOpDef *def;
const char *ct_str;
int i, nb_args;
for(;;) {
if (tdefs->op == (TCGOpcode)-1)
break;
op = tdefs->op;
assert((unsigned)op < (unsigned)NB_OPS);
def = &tcg_op_defs[op];
#if defined(CONFIG_DEBUG_TCG)
/* Duplicate entry in op definitions? */
assert(!def->used);
def->used = 1;
#endif
nb_args = def->nb_iargs + def->nb_oargs;
for(i = 0; i < nb_args; i++) {
ct_str = tdefs->args_ct_str[i];
/* Incomplete TCGTargetOpDef entry? */
assert(ct_str != NULL);
tcg_regset_clear(def->args_ct[i].u.regs);
def->args_ct[i].ct = 0;
if (ct_str[0] >= '0' && ct_str[0] <= '9') {
int oarg;
oarg = ct_str[0] - '0';
assert(oarg < def->nb_oargs);
assert(def->args_ct[oarg].ct & TCG_CT_REG);
/* TCG_CT_ALIAS is for the output arguments. The input
argument is tagged with TCG_CT_IALIAS. */
def->args_ct[i] = def->args_ct[oarg];
def->args_ct[oarg].ct = TCG_CT_ALIAS;
def->args_ct[oarg].alias_index = i;
def->args_ct[i].ct |= TCG_CT_IALIAS;
def->args_ct[i].alias_index = oarg;
} else {
for(;;) {
if (*ct_str == '\0')
break;
switch(*ct_str) {
case 'i':
def->args_ct[i].ct |= TCG_CT_CONST;
ct_str++;
break;
default:
if (target_parse_constraint(&def->args_ct[i], &ct_str) < 0) {
fprintf(stderr, "Invalid constraint '%s' for arg %d of operation '%s'\n",
ct_str, i, def->name);
#ifndef VBOX
exit(1);
#else
tcg_exit(1);
#endif
}
}
}
}
}
/* TCGTargetOpDef entry with too much information? */
assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL);
/* sort the constraints (XXX: this is just an heuristic) */
sort_constraints(def, 0, def->nb_oargs);
sort_constraints(def, def->nb_oargs, def->nb_iargs);
#if 0
{
int i;
printf("%s: sorted=", def->name);
for(i = 0; i < def->nb_oargs + def->nb_iargs; i++)
printf(" %d", def->sorted_args[i]);
printf("\n");
}
#endif
tdefs++;
}
#if defined(CONFIG_DEBUG_TCG)
i = 0;
for (op = 0; op < ARRAY_SIZE(tcg_op_defs); op++) {
if (op < INDEX_op_call || op == INDEX_op_debug_insn_start) {
/* Wrong entry in op definitions? */
if (tcg_op_defs[op].used) {
fprintf(stderr, "Invalid op definition for %s\n",
tcg_op_defs[op].name);
i = 1;
}
} else {
/* Missing entry in op definitions? */
if (!tcg_op_defs[op].used) {
fprintf(stderr, "Missing op definition for %s\n",
tcg_op_defs[op].name);
i = 1;
}
}
}
if (i == 1) {
tcg_abort();
}
#endif
}
#ifdef USE_LIVENESS_ANALYSIS
/* set a nop for an operation using 'nb_args' */
static inline void tcg_set_nop(TCGContext *s, uint16_t *opc_ptr,
TCGArg *args, int nb_args)
{
if (nb_args == 0) {
*opc_ptr = INDEX_op_nop;
} else {
*opc_ptr = INDEX_op_nopn;
args[0] = nb_args;
args[nb_args - 1] = nb_args;
}
}
/* liveness analysis: end of function: globals are live, temps are
dead. */
/* XXX: at this stage, not used as there would be little gains because
most TBs end with a conditional jump. */
static inline void tcg_la_func_end(TCGContext *s, uint8_t *dead_temps)
{
memset(dead_temps, 0, s->nb_globals);
memset(dead_temps + s->nb_globals, 1, s->nb_temps - s->nb_globals);
}
/* liveness analysis: end of basic block: globals are live, temps are
dead, local temps are live. */
static inline void tcg_la_bb_end(TCGContext *s, uint8_t *dead_temps)
{
int i;
TCGTemp *ts;
memset(dead_temps, 0, s->nb_globals);
ts = &s->temps[s->nb_globals];
for(i = s->nb_globals; i < s->nb_temps; i++) {
if (ts->temp_local)
dead_temps[i] = 0;
else
dead_temps[i] = 1;
ts++;
}
}
/* Liveness analysis : update the opc_dead_iargs array to tell if a
given input arguments is dead. Instructions updating dead
temporaries are removed. */
static void tcg_liveness_analysis(TCGContext *s)
{
int i, op_index, nb_args, nb_iargs, nb_oargs, arg, nb_ops;
TCGOpcode op;
TCGArg *args;
const TCGOpDef *def;
uint8_t *dead_temps;
unsigned int dead_iargs;
gen_opc_ptr++; /* skip end */
nb_ops = gen_opc_ptr - gen_opc_buf;
s->op_dead_iargs = tcg_malloc(nb_ops * sizeof(uint16_t));
dead_temps = tcg_malloc(s->nb_temps);
memset(dead_temps, 1, s->nb_temps);
args = gen_opparam_ptr;
op_index = nb_ops - 1;
while (op_index >= 0) {
op = gen_opc_buf[op_index];
def = &tcg_op_defs[op];
switch(op) {
case INDEX_op_call:
{
int call_flags;
nb_args = args[-1];
args -= nb_args;
nb_iargs = args[0] & 0xffff;
nb_oargs = args[0] >> 16;
args++;
call_flags = args[nb_oargs + nb_iargs];
/* pure functions can be removed if their result is not
used */
if (call_flags & TCG_CALL_PURE) {
for(i = 0; i < nb_oargs; i++) {
arg = args[i];
if (!dead_temps[arg])
goto do_not_remove_call;
}
tcg_set_nop(s, gen_opc_buf + op_index,
args - 1, nb_args);
} else {
do_not_remove_call:
/* output args are dead */
for(i = 0; i < nb_oargs; i++) {
arg = args[i];
dead_temps[arg] = 1;
}
if (!(call_flags & TCG_CALL_CONST)) {
/* globals are live (they may be used by the call) */
memset(dead_temps, 0, s->nb_globals);
}
/* input args are live */
dead_iargs = 0;
for(i = 0; i < nb_iargs; i++) {
arg = args[i + nb_oargs];
if (arg != TCG_CALL_DUMMY_ARG) {
if (dead_temps[arg]) {
dead_iargs |= (1 << i);
}
dead_temps[arg] = 0;
}
}
s->op_dead_iargs[op_index] = dead_iargs;
}
args--;
}
break;
case INDEX_op_set_label:
args--;
/* mark end of basic block */
tcg_la_bb_end(s, dead_temps);
break;
case INDEX_op_debug_insn_start:
args -= def->nb_args;
break;
case INDEX_op_nopn:
nb_args = args[-1];
args -= nb_args;
break;
case INDEX_op_discard:
args--;
/* mark the temporary as dead */
dead_temps[args[0]] = 1;
break;
case INDEX_op_end:
break;
/* XXX: optimize by hardcoding common cases (e.g. triadic ops) */
default:
args -= def->nb_args;
nb_iargs = def->nb_iargs;
nb_oargs = def->nb_oargs;
/* Test if the operation can be removed because all
its outputs are dead. We assume that nb_oargs == 0
implies side effects */
if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) {
for(i = 0; i < nb_oargs; i++) {
arg = args[i];
if (!dead_temps[arg])
goto do_not_remove;
}
tcg_set_nop(s, gen_opc_buf + op_index, args, def->nb_args);
#ifdef CONFIG_PROFILER
s->del_op_count++;
#endif
} else {
do_not_remove:
/* output args are dead */
for(i = 0; i < nb_oargs; i++) {
arg = args[i];
dead_temps[arg] = 1;
}
/* if end of basic block, update */
if (def->flags & TCG_OPF_BB_END) {
tcg_la_bb_end(s, dead_temps);
} else if (def->flags & TCG_OPF_CALL_CLOBBER) {
/* globals are live */
memset(dead_temps, 0, s->nb_globals);
}
/* input args are live */
dead_iargs = 0;
for(i = 0; i < nb_iargs; i++) {
arg = args[i + nb_oargs];
if (dead_temps[arg]) {
dead_iargs |= (1 << i);
}
dead_temps[arg] = 0;
}
s->op_dead_iargs[op_index] = dead_iargs;
}
break;
}
op_index--;
}
if (args != gen_opparam_buf)
tcg_abort();
}
#else
/* dummy liveness analysis */
static void tcg_liveness_analysis(TCGContext *s)
{
int nb_ops;
nb_ops = gen_opc_ptr - gen_opc_buf;
s->op_dead_iargs = tcg_malloc(nb_ops * sizeof(uint16_t));
memset(s->op_dead_iargs, 0, nb_ops * sizeof(uint16_t));
}
#endif
#ifndef NDEBUG
static void dump_regs(TCGContext *s)
{
TCGTemp *ts;
int i;
char buf[64];
for(i = 0; i < s->nb_temps; i++) {
ts = &s->temps[i];
printf(" %10s: ", tcg_get_arg_str_idx(s, buf, sizeof(buf), i));
switch(ts->val_type) {
case TEMP_VAL_REG:
printf("%s", tcg_target_reg_names[ts->reg]);
break;
case TEMP_VAL_MEM:
printf("%d(%s)", (int)ts->mem_offset, tcg_target_reg_names[ts->mem_reg]);
break;
case TEMP_VAL_CONST:
printf("$0x%" TCG_PRIlx, ts->val);
break;
case TEMP_VAL_DEAD:
printf("D");
break;
default:
printf("???");
break;
}
printf("\n");
}
for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
if (s->reg_to_temp[i] >= 0) {
printf("%s: %s\n",
tcg_target_reg_names[i],
tcg_get_arg_str_idx(s, buf, sizeof(buf), s->reg_to_temp[i]));
}
}
}
static void check_regs(TCGContext *s)
{
int reg, k;
TCGTemp *ts;
char buf[64];
for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
k = s->reg_to_temp[reg];
if (k >= 0) {
ts = &s->temps[k];
if (ts->val_type != TEMP_VAL_REG ||
ts->reg != reg) {
printf("Inconsistency for register %s:\n",
tcg_target_reg_names[reg]);
goto fail;
}
}
}
for(k = 0; k < s->nb_temps; k++) {
ts = &s->temps[k];
if (ts->val_type == TEMP_VAL_REG &&
!ts->fixed_reg &&
s->reg_to_temp[ts->reg] != k) {
printf("Inconsistency for temp %s:\n",
tcg_get_arg_str_idx(s, buf, sizeof(buf), k));
fail:
printf("reg state:\n");
dump_regs(s);
tcg_abort();
}
}
}
#endif
static void temp_allocate_frame(TCGContext *s, int temp)
{
TCGTemp *ts;
ts = &s->temps[temp];
s->current_frame_offset = (s->current_frame_offset + sizeof(tcg_target_long) - 1) & ~(sizeof(tcg_target_long) - 1);
#ifndef VBOX
if (s->current_frame_offset + sizeof(tcg_target_long) > s->frame_end)
#else
if ((tcg_target_long)s->current_frame_offset + sizeof(tcg_target_long) > s->frame_end)
#endif
tcg_abort();
ts->mem_offset = s->current_frame_offset;
ts->mem_reg = s->frame_reg;
ts->mem_allocated = 1;
s->current_frame_offset += sizeof(tcg_target_long);
}
/* free register 'reg' by spilling the corresponding temporary if necessary */
static void tcg_reg_free(TCGContext *s, int reg)
{
TCGTemp *ts;
int temp;
temp = s->reg_to_temp[reg];
if (temp != -1) {
ts = &s->temps[temp];
assert(ts->val_type == TEMP_VAL_REG);
if (!ts->mem_coherent) {
if (!ts->mem_allocated)
temp_allocate_frame(s, temp);
tcg_out_st(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
}
ts->val_type = TEMP_VAL_MEM;
s->reg_to_temp[reg] = -1;
}
}
/* Allocate a register belonging to reg1 & ~reg2 */
static int tcg_reg_alloc(TCGContext *s, TCGRegSet reg1, TCGRegSet reg2)
{
int i, reg;
TCGRegSet reg_ct;
tcg_regset_andnot(reg_ct, reg1, reg2);
/* first try free registers */
for(i = 0; i < ARRAY_SIZE(tcg_target_reg_alloc_order); i++) {
reg = tcg_target_reg_alloc_order[i];
if (tcg_regset_test_reg(reg_ct, reg) && s->reg_to_temp[reg] == -1)
return reg;
}
/* XXX: do better spill choice */
for(i = 0; i < ARRAY_SIZE(tcg_target_reg_alloc_order); i++) {
reg = tcg_target_reg_alloc_order[i];
if (tcg_regset_test_reg(reg_ct, reg)) {
tcg_reg_free(s, reg);
return reg;
}
}
tcg_abort();
}
/* save a temporary to memory. 'allocated_regs' is used in case a
temporary registers needs to be allocated to store a constant. */
static void temp_save(TCGContext *s, int temp, TCGRegSet allocated_regs)
{
TCGTemp *ts;
int reg;
ts = &s->temps[temp];
if (!ts->fixed_reg) {
switch(ts->val_type) {
case TEMP_VAL_REG:
tcg_reg_free(s, ts->reg);
break;
case TEMP_VAL_DEAD:
ts->val_type = TEMP_VAL_MEM;
break;
case TEMP_VAL_CONST:
reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],
allocated_regs);
if (!ts->mem_allocated)
temp_allocate_frame(s, temp);
tcg_out_movi(s, ts->type, reg, ts->val);
tcg_out_st(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
ts->val_type = TEMP_VAL_MEM;
break;
case TEMP_VAL_MEM:
break;
default:
tcg_abort();
}
}
}
/* save globals to their cannonical location and assume they can be
modified be the following code. 'allocated_regs' is used in case a
temporary registers needs to be allocated to store a constant. */
static void save_globals(TCGContext *s, TCGRegSet allocated_regs)
{
int i;
for(i = 0; i < s->nb_globals; i++) {
temp_save(s, i, allocated_regs);
}
}
/* at the end of a basic block, we assume all temporaries are dead and
all globals are stored at their canonical location. */
static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs)
{
TCGTemp *ts;
int i;
for(i = s->nb_globals; i < s->nb_temps; i++) {
ts = &s->temps[i];
if (ts->temp_local) {
temp_save(s, i, allocated_regs);
} else {
if (ts->val_type == TEMP_VAL_REG) {
s->reg_to_temp[ts->reg] = -1;
}
ts->val_type = TEMP_VAL_DEAD;
}
}
save_globals(s, allocated_regs);
}
#define IS_DEAD_IARG(n) ((dead_iargs >> (n)) & 1)
static void tcg_reg_alloc_movi(TCGContext *s, const TCGArg *args)
{
TCGTemp *ots;
tcg_target_ulong val;
ots = &s->temps[args[0]];
val = args[1];
if (ots->fixed_reg) {
/* for fixed registers, we do not do any constant
propagation */
tcg_out_movi(s, ots->type, ots->reg, val);
} else {
/* The movi is not explicitly generated here */
if (ots->val_type == TEMP_VAL_REG)
s->reg_to_temp[ots->reg] = -1;
ots->val_type = TEMP_VAL_CONST;
ots->val = val;
}
}
static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def,
const TCGArg *args,
unsigned int dead_iargs)
{
TCGTemp *ts, *ots;
int reg;
const TCGArgConstraint *arg_ct;
ots = &s->temps[args[0]];
ts = &s->temps[args[1]];
arg_ct = &def->args_ct[0];
/* XXX: always mark arg dead if IS_DEAD_IARG(0) */
if (ts->val_type == TEMP_VAL_REG) {
if (IS_DEAD_IARG(0) && !ts->fixed_reg && !ots->fixed_reg) {
/* the mov can be suppressed */
if (ots->val_type == TEMP_VAL_REG)
s->reg_to_temp[ots->reg] = -1;
reg = ts->reg;
s->reg_to_temp[reg] = -1;
ts->val_type = TEMP_VAL_DEAD;
} else {
if (ots->val_type == TEMP_VAL_REG) {
reg = ots->reg;
} else {
reg = tcg_reg_alloc(s, arg_ct->u.regs, s->reserved_regs);
}
if (ts->reg != reg) {
tcg_out_mov(s, ots->type, reg, ts->reg);
}
}
} else if (ts->val_type == TEMP_VAL_MEM) {
if (ots->val_type == TEMP_VAL_REG) {
reg = ots->reg;
} else {
reg = tcg_reg_alloc(s, arg_ct->u.regs, s->reserved_regs);
}
tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
} else if (ts->val_type == TEMP_VAL_CONST) {
if (ots->fixed_reg) {
reg = ots->reg;
tcg_out_movi(s, ots->type, reg, ts->val);
} else {
/* propagate constant */
if (ots->val_type == TEMP_VAL_REG)
s->reg_to_temp[ots->reg] = -1;
ots->val_type = TEMP_VAL_CONST;
ots->val = ts->val;
return;
}
} else {
tcg_abort();
}
s->reg_to_temp[reg] = args[0];
ots->reg = reg;
ots->val_type = TEMP_VAL_REG;
ots->mem_coherent = 0;
}
static void tcg_reg_alloc_op(TCGContext *s,
const TCGOpDef *def, TCGOpcode opc,
const TCGArg *args,
unsigned int dead_iargs)
{
TCGRegSet allocated_regs;
int i, k, nb_iargs, nb_oargs, reg;
TCGArg arg;
const TCGArgConstraint *arg_ct;
TCGTemp *ts;
TCGArg new_args[TCG_MAX_OP_ARGS];
int const_args[TCG_MAX_OP_ARGS];
nb_oargs = def->nb_oargs;
nb_iargs = def->nb_iargs;
/* copy constants */
memcpy(new_args + nb_oargs + nb_iargs,
args + nb_oargs + nb_iargs,
sizeof(TCGArg) * def->nb_cargs);
/* satisfy input constraints */
tcg_regset_set(allocated_regs, s->reserved_regs);
for(k = 0; k < nb_iargs; k++) {
i = def->sorted_args[nb_oargs + k];
arg = args[i];
arg_ct = &def->args_ct[i];
ts = &s->temps[arg];
if (ts->val_type == TEMP_VAL_MEM) {
reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
ts->val_type = TEMP_VAL_REG;
ts->reg = reg;
ts->mem_coherent = 1;
s->reg_to_temp[reg] = arg;
} else if (ts->val_type == TEMP_VAL_CONST) {
if (tcg_target_const_match(ts->val, arg_ct)) {
/* constant is OK for instruction */
const_args[i] = 1;
new_args[i] = ts->val;
goto iarg_end;
} else {
/* need to move to a register */
reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
tcg_out_movi(s, ts->type, reg, ts->val);
ts->val_type = TEMP_VAL_REG;
ts->reg = reg;
ts->mem_coherent = 0;
s->reg_to_temp[reg] = arg;
}
}
assert(ts->val_type == TEMP_VAL_REG);
if (arg_ct->ct & TCG_CT_IALIAS) {
if (ts->fixed_reg) {
/* if fixed register, we must allocate a new register
if the alias is not the same register */
if (arg != args[arg_ct->alias_index])
goto allocate_in_reg;
} else {
/* if the input is aliased to an output and if it is
not dead after the instruction, we must allocate
a new register and move it */
if (!IS_DEAD_IARG(i - nb_oargs))
goto allocate_in_reg;
}
}
reg = ts->reg;
if (tcg_regset_test_reg(arg_ct->u.regs, reg)) {
/* nothing to do : the constraint is satisfied */
} else {
allocate_in_reg:
/* allocate a new register matching the constraint
and move the temporary register into it */
reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
tcg_out_mov(s, ts->type, reg, ts->reg);
}
new_args[i] = reg;
const_args[i] = 0;
tcg_regset_set_reg(allocated_regs, reg);
iarg_end: ;
}
if (def->flags & TCG_OPF_BB_END) {
tcg_reg_alloc_bb_end(s, allocated_regs);
} else {
/* mark dead temporaries and free the associated registers */
for(i = 0; i < nb_iargs; i++) {
arg = args[nb_oargs + i];
if (IS_DEAD_IARG(i)) {
ts = &s->temps[arg];
if (!ts->fixed_reg) {
if (ts->val_type == TEMP_VAL_REG)
s->reg_to_temp[ts->reg] = -1;
ts->val_type = TEMP_VAL_DEAD;
}
}
}
if (def->flags & TCG_OPF_CALL_CLOBBER) {
/* XXX: permit generic clobber register list ? */
for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
if (tcg_regset_test_reg(tcg_target_call_clobber_regs, reg)) {
tcg_reg_free(s, reg);
}
}
/* XXX: for load/store we could do that only for the slow path
(i.e. when a memory callback is called) */
/* store globals and free associated registers (we assume the insn
can modify any global. */
save_globals(s, allocated_regs);
}
/* satisfy the output constraints */
tcg_regset_set(allocated_regs, s->reserved_regs);
for(k = 0; k < nb_oargs; k++) {
i = def->sorted_args[k];
arg = args[i];
arg_ct = &def->args_ct[i];
ts = &s->temps[arg];
if (arg_ct->ct & TCG_CT_ALIAS) {
reg = new_args[arg_ct->alias_index];
} else {
/* if fixed register, we try to use it */
reg = ts->reg;
if (ts->fixed_reg &&
tcg_regset_test_reg(arg_ct->u.regs, reg)) {
goto oarg_end;
}
reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
}
tcg_regset_set_reg(allocated_regs, reg);
/* if a fixed register is used, then a move will be done afterwards */
if (!ts->fixed_reg) {
if (ts->val_type == TEMP_VAL_REG)
s->reg_to_temp[ts->reg] = -1;
ts->val_type = TEMP_VAL_REG;
ts->reg = reg;
/* temp value is modified, so the value kept in memory is
potentially not the same */
ts->mem_coherent = 0;
s->reg_to_temp[reg] = arg;
}
oarg_end:
new_args[i] = reg;
}
}
/* emit instruction */
tcg_out_op(s, opc, new_args, const_args);
/* move the outputs in the correct register if needed */
for(i = 0; i < nb_oargs; i++) {
ts = &s->temps[args[i]];
reg = new_args[i];
if (ts->fixed_reg && ts->reg != reg) {
tcg_out_mov(s, ts->type, ts->reg, reg);
}
}
}
#ifdef TCG_TARGET_STACK_GROWSUP
#define STACK_DIR(x) (-(x))
#else
#define STACK_DIR(x) (x)
#endif
static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def,
TCGOpcode opc, const TCGArg *args,
unsigned int dead_iargs)
{
int nb_iargs, nb_oargs, flags, nb_regs, i, reg, nb_params;
TCGArg arg, func_arg;
TCGTemp *ts;
tcg_target_long stack_offset, call_stack_size, func_addr;
int const_func_arg, allocate_args;
TCGRegSet allocated_regs;
const TCGArgConstraint *arg_ct;
arg = *args++;
nb_oargs = arg >> 16;
nb_iargs = arg & 0xffff;
nb_params = nb_iargs - 1;
flags = args[nb_oargs + nb_iargs];
nb_regs = tcg_target_get_call_iarg_regs_count(flags);
if (nb_regs > nb_params)
nb_regs = nb_params;
/* assign stack slots first */
/* XXX: preallocate call stack */
call_stack_size = (nb_params - nb_regs) * sizeof(tcg_target_long);
call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) &
~(TCG_TARGET_STACK_ALIGN - 1);
allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE);
if (allocate_args) {
tcg_out_addi(s, TCG_REG_CALL_STACK, -STACK_DIR(call_stack_size));
}
stack_offset = TCG_TARGET_CALL_STACK_OFFSET;
for(i = nb_regs; i < nb_params; i++) {
arg = args[nb_oargs + i];
#ifdef TCG_TARGET_STACK_GROWSUP
stack_offset -= sizeof(tcg_target_long);
#endif
if (arg != TCG_CALL_DUMMY_ARG) {
ts = &s->temps[arg];
if (ts->val_type == TEMP_VAL_REG) {
tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, stack_offset);
} else if (ts->val_type == TEMP_VAL_MEM) {
reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],
s->reserved_regs);
/* XXX: not correct if reading values from the stack */
tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
tcg_out_st(s, ts->type, reg, TCG_REG_CALL_STACK, stack_offset);
} else if (ts->val_type == TEMP_VAL_CONST) {
reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],
s->reserved_regs);
/* XXX: sign extend may be needed on some targets */
tcg_out_movi(s, ts->type, reg, ts->val);
tcg_out_st(s, ts->type, reg, TCG_REG_CALL_STACK, stack_offset);
} else {
tcg_abort();
}
}
#ifndef TCG_TARGET_STACK_GROWSUP
stack_offset += sizeof(tcg_target_long);
#endif
}
/* assign input registers */
tcg_regset_set(allocated_regs, s->reserved_regs);
for(i = 0; i < nb_regs; i++) {
arg = args[nb_oargs + i];
if (arg != TCG_CALL_DUMMY_ARG) {
ts = &s->temps[arg];
reg = tcg_target_call_iarg_regs[i];
tcg_reg_free(s, reg);
if (ts->val_type == TEMP_VAL_REG) {
if (ts->reg != reg) {
tcg_out_mov(s, ts->type, reg, ts->reg);
}
} else if (ts->val_type == TEMP_VAL_MEM) {
tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
} else if (ts->val_type == TEMP_VAL_CONST) {
/* XXX: sign extend ? */
tcg_out_movi(s, ts->type, reg, ts->val);
} else {
tcg_abort();
}
tcg_regset_set_reg(allocated_regs, reg);
}
}
/* assign function address */
func_arg = args[nb_oargs + nb_iargs - 1];
arg_ct = &def->args_ct[0];
ts = &s->temps[func_arg];
func_addr = ts->val;
const_func_arg = 0;
if (ts->val_type == TEMP_VAL_MEM) {
reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
func_arg = reg;
tcg_regset_set_reg(allocated_regs, reg);
} else if (ts->val_type == TEMP_VAL_REG) {
reg = ts->reg;
if (!tcg_regset_test_reg(arg_ct->u.regs, reg)) {
reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
tcg_out_mov(s, ts->type, reg, ts->reg);
}
func_arg = reg;
tcg_regset_set_reg(allocated_regs, reg);
} else if (ts->val_type == TEMP_VAL_CONST) {
if (tcg_target_const_match(func_addr, arg_ct)) {
const_func_arg = 1;
func_arg = func_addr;
} else {
reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
tcg_out_movi(s, ts->type, reg, func_addr);
func_arg = reg;
tcg_regset_set_reg(allocated_regs, reg);
}
} else {
tcg_abort();
}
/* mark dead temporaries and free the associated registers */
for(i = 0; i < nb_iargs; i++) {
arg = args[nb_oargs + i];
if (IS_DEAD_IARG(i)) {
ts = &s->temps[arg];
if (!ts->fixed_reg) {
if (ts->val_type == TEMP_VAL_REG)
s->reg_to_temp[ts->reg] = -1;
ts->val_type = TEMP_VAL_DEAD;
}
}
}
/* clobber call registers */
for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
if (tcg_regset_test_reg(tcg_target_call_clobber_regs, reg)) {
tcg_reg_free(s, reg);
}
}
/* store globals and free associated registers (we assume the call
can modify any global. */
if (!(flags & TCG_CALL_CONST)) {
save_globals(s, allocated_regs);
}
tcg_out_op(s, opc, &func_arg, &const_func_arg);
if (allocate_args) {
tcg_out_addi(s, TCG_REG_CALL_STACK, STACK_DIR(call_stack_size));
}
/* assign output registers and emit moves if needed */
for(i = 0; i < nb_oargs; i++) {
arg = args[i];
ts = &s->temps[arg];
reg = tcg_target_call_oarg_regs[i];
assert(s->reg_to_temp[reg] == -1);
if (ts->fixed_reg) {
if (ts->reg != reg) {
tcg_out_mov(s, ts->type, ts->reg, reg);
}
} else {
if (ts->val_type == TEMP_VAL_REG)
s->reg_to_temp[ts->reg] = -1;
ts->val_type = TEMP_VAL_REG;
ts->reg = reg;
ts->mem_coherent = 0;
s->reg_to_temp[reg] = arg;
}
}
return nb_iargs + nb_oargs + def->nb_cargs + 1;
}
#ifdef CONFIG_PROFILER
static int64_t tcg_table_op_count[NB_OPS];
static void dump_op_count(void)
{
int i;
FILE *f;
f = fopen("/tmp/op.log", "w");
for(i = INDEX_op_end; i < NB_OPS; i++) {
fprintf(f, "%s %" PRId64 "\n", tcg_op_defs[i].name, tcg_table_op_count[i]);
}
fclose(f);
}
#endif
static inline int tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf,
intptr_t search_pc)
{
TCGOpcode opc;
int op_index;
const TCGOpDef *def;
unsigned int dead_iargs;
const TCGArg *args;
#ifdef DEBUG_DISAS
if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP))) {
qemu_log("OP:\n");
tcg_dump_ops(s, logfile);
qemu_log("\n");
}
#endif
#ifdef CONFIG_PROFILER
s->la_time -= profile_getclock();
#endif
tcg_liveness_analysis(s);
#ifdef CONFIG_PROFILER
s->la_time += profile_getclock();
#endif
#ifdef DEBUG_DISAS
# ifdef USE_LIVENESS_ANALYSIS /* vbox */
if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT))) {
qemu_log("OP after liveness analysis:\n");
tcg_dump_ops(s, logfile);
qemu_log("\n");
}
# endif /* USE_LIVENESS_ANALYSIS - vbox */
#endif
tcg_reg_alloc_start(s);
s->code_buf = gen_code_buf;
s->code_ptr = gen_code_buf;
args = gen_opparam_buf;
op_index = 0;
for(;;) {
opc = gen_opc_buf[op_index];
#ifdef CONFIG_PROFILER
tcg_table_op_count[opc]++;
#endif
def = &tcg_op_defs[opc];
#if 0
printf("%s: %d %d %d\n", def->name,
def->nb_oargs, def->nb_iargs, def->nb_cargs);
// dump_regs(s);
#endif
switch(opc) {
case INDEX_op_mov_i32:
#if TCG_TARGET_REG_BITS == 64
case INDEX_op_mov_i64:
#endif
dead_iargs = s->op_dead_iargs[op_index];
tcg_reg_alloc_mov(s, def, args, dead_iargs);
break;
case INDEX_op_movi_i32:
#if TCG_TARGET_REG_BITS == 64
case INDEX_op_movi_i64:
#endif
tcg_reg_alloc_movi(s, args);
break;
case INDEX_op_debug_insn_start:
/* debug instruction */
break;
case INDEX_op_nop:
case INDEX_op_nop1:
case INDEX_op_nop2:
case INDEX_op_nop3:
break;
case INDEX_op_nopn:
args += args[0];
goto next;
case INDEX_op_discard:
{
TCGTemp *ts;
ts = &s->temps[args[0]];
/* mark the temporary as dead */
if (!ts->fixed_reg) {
if (ts->val_type == TEMP_VAL_REG)
s->reg_to_temp[ts->reg] = -1;
ts->val_type = TEMP_VAL_DEAD;
}
}
break;
case INDEX_op_set_label:
tcg_reg_alloc_bb_end(s, s->reserved_regs);
tcg_out_label(s, args[0], (intptr_t)s->code_ptr);
break;
case INDEX_op_call:
dead_iargs = s->op_dead_iargs[op_index];
args += tcg_reg_alloc_call(s, def, opc, args, dead_iargs);
goto next;
case INDEX_op_end:
goto the_end;
default:
/* Note: in order to speed up the code, it would be much
faster to have specialized register allocator functions for
some common argument patterns */
dead_iargs = s->op_dead_iargs[op_index];
tcg_reg_alloc_op(s, def, opc, args, dead_iargs);
break;
}
args += def->nb_args;
next:
if (search_pc >= 0 && search_pc < s->code_ptr - gen_code_buf) {
return op_index;
}
op_index++;
#ifndef NDEBUG
check_regs(s);
#endif
}
the_end:
return -1;
}
int tcg_gen_code(TCGContext *s, uint8_t *gen_code_buf)
{
#ifdef CONFIG_PROFILER
{
int n;
n = (gen_opc_ptr - gen_opc_buf);
s->op_count += n;
if (n > s->op_count_max)
s->op_count_max = n;
s->temp_count += s->nb_temps;
if (s->nb_temps > s->temp_count_max)
s->temp_count_max = s->nb_temps;
}
#endif
tcg_gen_code_common(s, gen_code_buf, -1);
/* flush instruction cache */
flush_icache_range((uintptr_t)gen_code_buf,
(uintptr_t)s->code_ptr);
return s->code_ptr - gen_code_buf;
}
/* Return the index of the micro operation such as the pc after is <
offset bytes from the start of the TB. The contents of gen_code_buf must
not be changed, though writing the same values is ok.
Return -1 if not found. */
int tcg_gen_code_search_pc(TCGContext *s, uint8_t *gen_code_buf, intptr_t offset)
{
return tcg_gen_code_common(s, gen_code_buf, offset);
}
#ifdef CONFIG_PROFILER
void tcg_dump_info(FILE *f,
int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
{
TCGContext *s = &tcg_ctx;
int64_t tot;
tot = s->interm_time + s->code_time;
cpu_fprintf(f, "JIT cycles %" PRId64 " (%0.3f s at 2.4 GHz)\n",
tot, tot / 2.4e9);
cpu_fprintf(f, "translated TBs %" PRId64 " (aborted=%" PRId64 " %0.1f%%)\n",
s->tb_count,
s->tb_count1 - s->tb_count,
s->tb_count1 ? (double)(s->tb_count1 - s->tb_count) / s->tb_count1 * 100.0 : 0);
cpu_fprintf(f, "avg ops/TB %0.1f max=%d\n",
s->tb_count ? (double)s->op_count / s->tb_count : 0, s->op_count_max);
cpu_fprintf(f, "deleted ops/TB %0.2f\n",
s->tb_count ?
(double)s->del_op_count / s->tb_count : 0);
cpu_fprintf(f, "avg temps/TB %0.2f max=%d\n",
s->tb_count ?
(double)s->temp_count / s->tb_count : 0,
s->temp_count_max);
cpu_fprintf(f, "cycles/op %0.1f\n",
s->op_count ? (double)tot / s->op_count : 0);
cpu_fprintf(f, "cycles/in byte %0.1f\n",
s->code_in_len ? (double)tot / s->code_in_len : 0);
cpu_fprintf(f, "cycles/out byte %0.1f\n",
s->code_out_len ? (double)tot / s->code_out_len : 0);
if (tot == 0)
tot = 1;
cpu_fprintf(f, " gen_interm time %0.1f%%\n",
(double)s->interm_time / tot * 100.0);
cpu_fprintf(f, " gen_code time %0.1f%%\n",
(double)s->code_time / tot * 100.0);
cpu_fprintf(f, "liveness/code time %0.1f%%\n",
(double)s->la_time / (s->code_time ? s->code_time : 1) * 100.0);
cpu_fprintf(f, "cpu_restore count %" PRId64 "\n",
s->restore_count);
cpu_fprintf(f, " avg cycles %0.1f\n",
s->restore_count ? (double)s->restore_time / s->restore_count : 0);
dump_op_count();
}
#else
void tcg_dump_info(FILE *f,
int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
{
cpu_fprintf(f, "[TCG profiler not compiled]\n");
}
#endif