xref: /qemu/accel/tcg/translator.c (revision cfd405eae6ad7a0e20b006e3295c5e8edab3ce3f)
1bb2e0039SLluís Vilanova /*
2bb2e0039SLluís Vilanova  * Generic intermediate code generation.
3bb2e0039SLluís Vilanova  *
4bb2e0039SLluís Vilanova  * Copyright (C) 2016-2017 Lluís Vilanova <vilanova@ac.upc.edu>
5bb2e0039SLluís Vilanova  *
6bb2e0039SLluís Vilanova  * This work is licensed under the terms of the GNU GPL, version 2 or later.
7bb2e0039SLluís Vilanova  * See the COPYING file in the top-level directory.
8bb2e0039SLluís Vilanova  */
9bb2e0039SLluís Vilanova 
10bb2e0039SLluís Vilanova #include "qemu/osdep.h"
11bb2e0039SLluís Vilanova #include "qemu/error-report.h"
12bb2e0039SLluís Vilanova #include "cpu.h"
13bb2e0039SLluís Vilanova #include "tcg/tcg.h"
14bb2e0039SLluís Vilanova #include "tcg/tcg-op.h"
15bb2e0039SLluís Vilanova #include "exec/exec-all.h"
16bb2e0039SLluís Vilanova #include "exec/gen-icount.h"
17bb2e0039SLluís Vilanova #include "exec/log.h"
18bb2e0039SLluís Vilanova #include "exec/translator.h"
196ba6f818SEmilio G. Cota #include "exec/plugin-gen.h"
20fda8458bSPavel Dovgalyuk #include "sysemu/replay.h"
21bb2e0039SLluís Vilanova 
22bb2e0039SLluís Vilanova /* Pairs with tcg_clear_temp_count.
23bb2e0039SLluís Vilanova    To be called by #TranslatorOps.{translate_insn,tb_stop} if
24bb2e0039SLluís Vilanova    (1) the target is sufficiently clean to support reporting,
25bb2e0039SLluís Vilanova    (2) as and when all temporaries are known to be consumed.
26bb2e0039SLluís Vilanova    For most targets, (2) is at the end of translate_insn.  */
27bb2e0039SLluís Vilanova void translator_loop_temp_check(DisasContextBase *db)
28bb2e0039SLluís Vilanova {
29bb2e0039SLluís Vilanova     if (tcg_check_temp_count()) {
30bb2e0039SLluís Vilanova         qemu_log("warning: TCG temporary leaks before "
31bb2e0039SLluís Vilanova                  TARGET_FMT_lx "\n", db->pc_next);
32bb2e0039SLluís Vilanova     }
33bb2e0039SLluís Vilanova }
34bb2e0039SLluís Vilanova 
35bb2e0039SLluís Vilanova void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
368b86d6d2SRichard Henderson                      CPUState *cpu, TranslationBlock *tb, int max_insns)
37bb2e0039SLluís Vilanova {
38f9f1f56eSPavel Dovgalyuk     int bp_insn = 0;
396ba6f818SEmilio G. Cota     bool plugin_enabled;
40f9f1f56eSPavel Dovgalyuk 
41bb2e0039SLluís Vilanova     /* Initialize DisasContext */
42bb2e0039SLluís Vilanova     db->tb = tb;
43bb2e0039SLluís Vilanova     db->pc_first = tb->pc;
44bb2e0039SLluís Vilanova     db->pc_next = db->pc_first;
45bb2e0039SLluís Vilanova     db->is_jmp = DISAS_NEXT;
46bb2e0039SLluís Vilanova     db->num_insns = 0;
478b86d6d2SRichard Henderson     db->max_insns = max_insns;
48bb2e0039SLluís Vilanova     db->singlestep_enabled = cpu->singlestep_enabled;
49bb2e0039SLluís Vilanova 
50b542683dSEmilio G. Cota     ops->init_disas_context(db, cpu);
51bb2e0039SLluís Vilanova     tcg_debug_assert(db->is_jmp == DISAS_NEXT);  /* no early exit */
52bb2e0039SLluís Vilanova 
53bb2e0039SLluís Vilanova     /* Reset the temp count so that we can identify leaks */
54bb2e0039SLluís Vilanova     tcg_clear_temp_count();
55bb2e0039SLluís Vilanova 
56bb2e0039SLluís Vilanova     /* Start translating.  */
57bb2e0039SLluís Vilanova     gen_tb_start(db->tb);
58bb2e0039SLluís Vilanova     ops->tb_start(db, cpu);
59bb2e0039SLluís Vilanova     tcg_debug_assert(db->is_jmp == DISAS_NEXT);  /* no early exit */
60bb2e0039SLluís Vilanova 
61*cfd405eaSAlex Bennée     plugin_enabled = plugin_gen_tb_start(cpu, tb,
62*cfd405eaSAlex Bennée                                          tb_cflags(db->tb) & CF_MEMI_ONLY);
636ba6f818SEmilio G. Cota 
64bb2e0039SLluís Vilanova     while (true) {
65bb2e0039SLluís Vilanova         db->num_insns++;
66bb2e0039SLluís Vilanova         ops->insn_start(db, cpu);
67bb2e0039SLluís Vilanova         tcg_debug_assert(db->is_jmp == DISAS_NEXT);  /* no early exit */
68bb2e0039SLluís Vilanova 
696ba6f818SEmilio G. Cota         if (plugin_enabled) {
706ba6f818SEmilio G. Cota             plugin_gen_insn_start(cpu, db);
716ba6f818SEmilio G. Cota         }
726ba6f818SEmilio G. Cota 
73bb2e0039SLluís Vilanova         /* Pass breakpoint hits to target for further processing */
74f9f1f56eSPavel Dovgalyuk         if (!db->singlestep_enabled
75f9f1f56eSPavel Dovgalyuk             && unlikely(!QTAILQ_EMPTY(&cpu->breakpoints))) {
76bb2e0039SLluís Vilanova             CPUBreakpoint *bp;
77bb2e0039SLluís Vilanova             QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) {
78bb2e0039SLluís Vilanova                 if (bp->pc == db->pc_next) {
79bb2e0039SLluís Vilanova                     if (ops->breakpoint_check(db, cpu, bp)) {
80f9f1f56eSPavel Dovgalyuk                         bp_insn = 1;
81bb2e0039SLluís Vilanova                         break;
82bb2e0039SLluís Vilanova                     }
83bb2e0039SLluís Vilanova                 }
84bb2e0039SLluís Vilanova             }
85bb2e0039SLluís Vilanova             /* The breakpoint_check hook may use DISAS_TOO_MANY to indicate
86bb2e0039SLluís Vilanova                that only one more instruction is to be executed.  Otherwise
87bb2e0039SLluís Vilanova                it should use DISAS_NORETURN when generating an exception,
88bb2e0039SLluís Vilanova                but may use a DISAS_TARGET_* value for Something Else.  */
89bb2e0039SLluís Vilanova             if (db->is_jmp > DISAS_TOO_MANY) {
90bb2e0039SLluís Vilanova                 break;
91bb2e0039SLluís Vilanova             }
92bb2e0039SLluís Vilanova         }
93bb2e0039SLluís Vilanova 
94bb2e0039SLluís Vilanova         /* Disassemble one instruction.  The translate_insn hook should
95bb2e0039SLluís Vilanova            update db->pc_next and db->is_jmp to indicate what should be
96bb2e0039SLluís Vilanova            done next -- either exiting this loop or locate the start of
97bb2e0039SLluís Vilanova            the next instruction.  */
98b542683dSEmilio G. Cota         if (db->num_insns == db->max_insns
99b542683dSEmilio G. Cota             && (tb_cflags(db->tb) & CF_LAST_IO)) {
100bb2e0039SLluís Vilanova             /* Accept I/O on the last instruction.  */
101bb2e0039SLluís Vilanova             gen_io_start();
102bb2e0039SLluís Vilanova             ops->translate_insn(db, cpu);
103bb2e0039SLluís Vilanova         } else {
104*cfd405eaSAlex Bennée             /* we should only see CF_MEMI_ONLY for io_recompile */
105*cfd405eaSAlex Bennée             tcg_debug_assert(!(tb_cflags(db->tb) & CF_MEMI_ONLY));
106bb2e0039SLluís Vilanova             ops->translate_insn(db, cpu);
107bb2e0039SLluís Vilanova         }
108bb2e0039SLluís Vilanova 
109bb2e0039SLluís Vilanova         /* Stop translation if translate_insn so indicated.  */
110bb2e0039SLluís Vilanova         if (db->is_jmp != DISAS_NEXT) {
111bb2e0039SLluís Vilanova             break;
112bb2e0039SLluís Vilanova         }
113bb2e0039SLluís Vilanova 
1146ba6f818SEmilio G. Cota         /*
1156ba6f818SEmilio G. Cota          * We can't instrument after instructions that change control
1166ba6f818SEmilio G. Cota          * flow although this only really affects post-load operations.
1176ba6f818SEmilio G. Cota          */
1186ba6f818SEmilio G. Cota         if (plugin_enabled) {
1196ba6f818SEmilio G. Cota             plugin_gen_insn_end();
1206ba6f818SEmilio G. Cota         }
1216ba6f818SEmilio G. Cota 
122bb2e0039SLluís Vilanova         /* Stop translation if the output buffer is full,
123bb2e0039SLluís Vilanova            or we have executed all of the allowed instructions.  */
124b542683dSEmilio G. Cota         if (tcg_op_buf_full() || db->num_insns >= db->max_insns) {
125bb2e0039SLluís Vilanova             db->is_jmp = DISAS_TOO_MANY;
126bb2e0039SLluís Vilanova             break;
127bb2e0039SLluís Vilanova         }
128bb2e0039SLluís Vilanova     }
129bb2e0039SLluís Vilanova 
130bb2e0039SLluís Vilanova     /* Emit code to exit the TB, as indicated by db->is_jmp.  */
131bb2e0039SLluís Vilanova     ops->tb_stop(db, cpu);
132f9f1f56eSPavel Dovgalyuk     gen_tb_end(db->tb, db->num_insns - bp_insn);
133bb2e0039SLluís Vilanova 
1346ba6f818SEmilio G. Cota     if (plugin_enabled) {
1356ba6f818SEmilio G. Cota         plugin_gen_tb_end(cpu);
1366ba6f818SEmilio G. Cota     }
1376ba6f818SEmilio G. Cota 
138bb2e0039SLluís Vilanova     /* The disas_log hook may use these values rather than recompute.  */
139d9971435SRichard Henderson     tb->size = db->pc_next - db->pc_first;
140d9971435SRichard Henderson     tb->icount = db->num_insns;
141bb2e0039SLluís Vilanova 
142bb2e0039SLluís Vilanova #ifdef DEBUG_DISAS
143bb2e0039SLluís Vilanova     if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
144bb2e0039SLluís Vilanova         && qemu_log_in_addr_range(db->pc_first)) {
145fc59d2d8SRobert Foley         FILE *logfile = qemu_log_lock();
146bb2e0039SLluís Vilanova         qemu_log("----------------\n");
147bb2e0039SLluís Vilanova         ops->disas_log(db, cpu);
148bb2e0039SLluís Vilanova         qemu_log("\n");
149fc59d2d8SRobert Foley         qemu_log_unlock(logfile);
150bb2e0039SLluís Vilanova     }
151bb2e0039SLluís Vilanova #endif
152bb2e0039SLluís Vilanova }
153