qemu/accel/tcg/translator.c
<<
>>
Prefs
   1/*
   2 * Generic intermediate code generation.
   3 *
   4 * Copyright (C) 2016-2017 LluĂ­s Vilanova <vilanova@ac.upc.edu>
   5 *
   6 * This work is licensed under the terms of the GNU GPL, version 2 or later.
   7 * See the COPYING file in the top-level directory.
   8 */
   9
  10#include "qemu/osdep.h"
  11#include "qemu-common.h"
  12#include "qemu/error-report.h"
  13#include "cpu.h"
  14#include "tcg/tcg.h"
  15#include "tcg/tcg-op.h"
  16#include "exec/exec-all.h"
  17#include "exec/gen-icount.h"
  18#include "exec/log.h"
  19#include "exec/translator.h"
  20
  21/* Pairs with tcg_clear_temp_count.
  22   To be called by #TranslatorOps.{translate_insn,tb_stop} if
  23   (1) the target is sufficiently clean to support reporting,
  24   (2) as and when all temporaries are known to be consumed.
  25   For most targets, (2) is at the end of translate_insn.  */
  26void translator_loop_temp_check(DisasContextBase *db)
  27{
  28    if (tcg_check_temp_count()) {
  29        qemu_log("warning: TCG temporary leaks before "
  30                 TARGET_FMT_lx "\n", db->pc_next);
  31    }
  32}
  33
  34void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
  35                     CPUState *cpu, TranslationBlock *tb)
  36{
  37    int bp_insn = 0;
  38
  39    /* Initialize DisasContext */
  40    db->tb = tb;
  41    db->pc_first = tb->pc;
  42    db->pc_next = db->pc_first;
  43    db->is_jmp = DISAS_NEXT;
  44    db->num_insns = 0;
  45    db->singlestep_enabled = cpu->singlestep_enabled;
  46
  47    /* Instruction counting */
  48    db->max_insns = tb_cflags(db->tb) & CF_COUNT_MASK;
  49    if (db->max_insns == 0) {
  50        db->max_insns = CF_COUNT_MASK;
  51    }
  52    if (db->max_insns > TCG_MAX_INSNS) {
  53        db->max_insns = TCG_MAX_INSNS;
  54    }
  55    if (db->singlestep_enabled || singlestep) {
  56        db->max_insns = 1;
  57    }
  58
  59    ops->init_disas_context(db, cpu);
  60    tcg_debug_assert(db->is_jmp == DISAS_NEXT);  /* no early exit */
  61
  62    /* Reset the temp count so that we can identify leaks */
  63    tcg_clear_temp_count();
  64
  65    /* Start translating.  */
  66    gen_tb_start(db->tb);
  67    ops->tb_start(db, cpu);
  68    tcg_debug_assert(db->is_jmp == DISAS_NEXT);  /* no early exit */
  69
  70    while (true) {
  71        db->num_insns++;
  72        ops->insn_start(db, cpu);
  73        tcg_debug_assert(db->is_jmp == DISAS_NEXT);  /* no early exit */
  74
  75        /* Pass breakpoint hits to target for further processing */
  76        if (!db->singlestep_enabled
  77            && unlikely(!QTAILQ_EMPTY(&cpu->breakpoints))) {
  78            CPUBreakpoint *bp;
  79            QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) {
  80                if (bp->pc == db->pc_next) {
  81                    if (ops->breakpoint_check(db, cpu, bp)) {
  82                        bp_insn = 1;
  83                        break;
  84                    }
  85                }
  86            }
  87            /* The breakpoint_check hook may use DISAS_TOO_MANY to indicate
  88               that only one more instruction is to be executed.  Otherwise
  89               it should use DISAS_NORETURN when generating an exception,
  90               but may use a DISAS_TARGET_* value for Something Else.  */
  91            if (db->is_jmp > DISAS_TOO_MANY) {
  92                break;
  93            }
  94        }
  95
  96        /* Disassemble one instruction.  The translate_insn hook should
  97           update db->pc_next and db->is_jmp to indicate what should be
  98           done next -- either exiting this loop or locate the start of
  99           the next instruction.  */
 100        if (db->num_insns == db->max_insns
 101            && (tb_cflags(db->tb) & CF_LAST_IO)) {
 102            /* Accept I/O on the last instruction.  */
 103            gen_io_start();
 104            ops->translate_insn(db, cpu);
 105            gen_io_end();
 106        } else {
 107            ops->translate_insn(db, cpu);
 108        }
 109
 110        /* Stop translation if translate_insn so indicated.  */
 111        if (db->is_jmp != DISAS_NEXT) {
 112            break;
 113        }
 114
 115        /* Stop translation if the output buffer is full,
 116           or we have executed all of the allowed instructions.  */
 117        if (tcg_op_buf_full() || db->num_insns >= db->max_insns) {
 118            db->is_jmp = DISAS_TOO_MANY;
 119            break;
 120        }
 121    }
 122
 123    /* Emit code to exit the TB, as indicated by db->is_jmp.  */
 124    ops->tb_stop(db, cpu);
 125    gen_tb_end(db->tb, db->num_insns - bp_insn);
 126
 127    /* The disas_log hook may use these values rather than recompute.  */
 128    db->tb->size = db->pc_next - db->pc_first;
 129    db->tb->icount = db->num_insns;
 130
 131#ifdef DEBUG_DISAS
 132    if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
 133        && qemu_log_in_addr_range(db->pc_first)) {
 134        qemu_log_lock();
 135        qemu_log("----------------\n");
 136        ops->disas_log(db, cpu);
 137        qemu_log("\n");
 138        qemu_log_unlock();
 139    }
 140#endif
 141}
 142