/*
 *  (C) 2010 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
 *      See COPYRIGHT in top-level directory.
 *
 *   This file implements the basic optimization schemes including indirect
 *   branch target cache (IBTC), indirect branch chain (IB chain), and trace
 *   profiling and prediction routines.
 */

#ifndef __LLVM_STATE_H
#define __LLVM_STATE_H

#define COPY_STATE(_dst, _src, _e) do { _dst->_e = _src->_e; } while(0)

/*
 * The following data structure and routine are used to save/restore the states
 * of CPUArchState. Only the states that could affect decoding the guest binary by
 * the TCG front-end are saved/restored. Such states are saved when translating
 * the block at the first time because the states could change later and are
 * restored to the saved values when the block is decoded again during the
 * trace formation.
 */
#if defined(TARGET_I386) || defined(TARGET_X86_64)
typedef struct i386_env {
    int singlestep_enabled;
    uint32_t hflags;
    target_ulong eflags;
} cpustate;
#elif defined(TARGET_ARM)
typedef struct arm_env {
    int singlestep_enabled;
    uint32_t pstate;
    uint32_t aarch64;
    struct {
        uint32_t c15_cpar;
        uint64_t scr_el3;
    } cp15;
    uint32_t uncached_cpsr;
    uint64_t features;
} cpustate;
#elif defined(TARGET_PPC) || defined(TARGET_PPC64)
typedef struct ppc_env {
    int singlestep_enabled;
    target_ulong msr;
    int mmu_idx;
    uint32_t flags;
    uint64_t insns_flags;
    uint64_t insns_flags2;
    target_ulong hflags;
} cpustate;
#elif defined(TARGET_SH4)
typedef struct sh4_env {
    int singlestep_enabled;
    uint32_t sr;	/* status register */
    uint32_t fpscr;	/* floating point status/control register */
    uint32_t features;
} cpustate;
#elif defined(TARGET_M68K)
typedef struct m68k_env {
    int singlestep_enabled;
    uint32_t sr;	/* status register */
    uint32_t fpcr;	/* floating point status/control register */
} cpustate;
#elif defined(TARGET_MIPS)
typedef struct mips_env {
    int singlestep_enabled;
    target_ulong btarget;
} cpustate;
#else
typedef struct dummy_env {
    int dummy;
} cpustate;
#endif

static inline void tcg_save_state(CPUArchState *env, TranslationBlock *tb)
{
#if defined(TARGET_I386) || defined(TARGET_X86_64)
    CPUState *cpu = ENV_GET_CPU(env);
    struct i386_env *s = new struct i386_env;
    COPY_STATE(s, cpu, singlestep_enabled);
    COPY_STATE(s, env, hflags);
    COPY_STATE(s, env, eflags);
#elif defined(TARGET_ARM)
    CPUState *cpu = ENV_GET_CPU(env);
    struct arm_env *s = new struct arm_env;
    COPY_STATE(s, cpu, singlestep_enabled);
    COPY_STATE(s, env, cp15.c15_cpar);
    COPY_STATE(s, env, cp15.scr_el3);
    COPY_STATE(s, env, uncached_cpsr);
    COPY_STATE(s, env, features);
    COPY_STATE(s, env, pstate);
    COPY_STATE(s, env, aarch64);
#elif defined(TARGET_PPC) || defined(TARGET_PPC64)
    CPUState *cpu = ENV_GET_CPU(env);
    struct ppc_env *s = new struct ppc_env;
    COPY_STATE(s, cpu, singlestep_enabled);
    COPY_STATE(s, env, msr);
    COPY_STATE(s, env, mmu_idx);
    COPY_STATE(s, env, flags);
    COPY_STATE(s, env, insns_flags);
    COPY_STATE(s, env, insns_flags2);
    COPY_STATE(s, env, hflags);
#elif defined(TARGET_SH4)
    CPUState *cpu = ENV_GET_CPU(env);
    struct sh4_env *s = new struct sh4_env;
    COPY_STATE(s, cpu, singlestep_enabled);
    COPY_STATE(s, env, sr);
    COPY_STATE(s, env, fpscr);
    COPY_STATE(s, env, features);
#elif defined(TARGET_M68K)
    CPUState *cpu = ENV_GET_CPU(env);
    struct m68k_env *s = new struct m68k_env;
    COPY_STATE(s, cpu, singlestep_enabled);
    COPY_STATE(s, env, sr);
    COPY_STATE(s, env, fpcr);
#elif defined(TARGET_MIPS)
    CPUState *cpu = ENV_GET_CPU(env);
    struct mips_env *s = new struct mips_env;
    COPY_STATE(s, cpu, singlestep_enabled);
    COPY_STATE(s, env, btarget);
#else
    void *s = nullptr;
#endif

    tb->state = (void *)s;
}

/*
 * tcg_restore_state()
 *  Reset states to those when the block is first translated.
 */
static inline void tcg_copy_state(CPUArchState *env, TranslationBlock *tb)
{
#if defined(TARGET_I386) || defined(TARGET_X86_64)
    CPUState *cpu = ENV_GET_CPU(env);
    struct i386_env *i386e = (struct i386_env *)tb->state;
    COPY_STATE(cpu, i386e, singlestep_enabled);
    COPY_STATE(env, i386e, hflags);
    COPY_STATE(env, i386e, eflags);
#elif defined(TARGET_ARM)
    CPUState *cpu = ENV_GET_CPU(env);
    struct arm_env *arme = (struct arm_env *)tb->state;
    COPY_STATE(cpu, arme, singlestep_enabled);
    COPY_STATE(env, arme, cp15.c15_cpar);
    COPY_STATE(env, arme, cp15.scr_el3);
    COPY_STATE(env, arme, uncached_cpsr);
    COPY_STATE(env, arme, features);
    COPY_STATE(env, arme, pstate);
    COPY_STATE(env, arme, aarch64);
#elif defined(TARGET_PPC) || defined(TARGET_PPC64)
    CPUState *cpu = ENV_GET_CPU(env);
    struct ppc_env *ppce = (struct ppc_env *)tb->state;
    COPY_STATE(cpu, ppce, singlestep_enabled);
    COPY_STATE(env, ppce, msr);
    COPY_STATE(env, ppce, mmu_idx);
    COPY_STATE(env, ppce, flags);
    COPY_STATE(env, ppce, insns_flags);
    COPY_STATE(env, ppce, insns_flags2);
    COPY_STATE(env, ppce, hflags);
#elif defined(TARGET_SH4)
    CPUState *cpu = ENV_GET_CPU(env);
    struct sh4_env *sh4e = (struct sh4_env *)tb->state;
    COPY_STATE(cpu, sh4e, singlestep_enabled);
    COPY_STATE(env, sh4e, sr);
    COPY_STATE(env, sh4e, fpscr);
    COPY_STATE(env, sh4e, features);
#elif defined(TARGET_M68K)
    CPUState *cpu = ENV_GET_CPU(env);
    struct m68k_env *m68ke = (struct m68k_env *)tb->state;
    COPY_STATE(cpu, m68ke, singlestep_enabled);
    COPY_STATE(env, m68ke, sr);
    COPY_STATE(env, m68ke, fpcr);
#elif defined(TARGET_MIPS)
    CPUState *cpu = ENV_GET_CPU(env);
    struct mips_env *mipse = (struct mips_env *)tb->state;
    COPY_STATE(cpu, mipse, singlestep_enabled);
    COPY_STATE(env, mipse, btarget);
#endif
}

static inline void delete_state(TranslationBlock *tb)
{
    delete (cpustate *)tb->state;
    tb->state = nullptr;
}

#undef COPY_STATE
#endif  /* __LLVM_STATE_H */


/*
 * vim: ts=8 sts=4 sw=4 expandtab
 */