summary refs log tree commit diff stats
path: root/accel/tcg/translate-all.c
diff options
context:
space:
mode:
Diffstat (limited to 'accel/tcg/translate-all.c')
-rw-r--r--accel/tcg/translate-all.c102
1 files changed, 70 insertions, 32 deletions
diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
index 8f593b926f..20b59f93f4 100644
--- a/accel/tcg/translate-all.c
+++ b/accel/tcg/translate-all.c
@@ -50,6 +50,7 @@
 #include "translate-all.h"
 #include "qemu/bitmap.h"
 #include "qemu/error-report.h"
+#include "qemu/qemu-print.h"
 #include "qemu/timer.h"
 #include "qemu/main-loop.h"
 #include "exec/log.h"
@@ -1673,7 +1674,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
     tb_page_addr_t phys_pc, phys_page2;
     target_ulong virt_page2;
     tcg_insn_unit *gen_code_buf;
-    int gen_code_size, search_size;
+    int gen_code_size, search_size, max_insns;
 #ifdef CONFIG_PROFILER
     TCGProfile *prof = &tcg_ctx->prof;
     int64_t ti;
@@ -1691,6 +1692,17 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
     cflags &= ~CF_CLUSTER_MASK;
     cflags |= cpu->cluster_index << CF_CLUSTER_SHIFT;
 
+    max_insns = cflags & CF_COUNT_MASK;
+    if (max_insns == 0) {
+        max_insns = CF_COUNT_MASK;
+    }
+    if (max_insns > TCG_MAX_INSNS) {
+        max_insns = TCG_MAX_INSNS;
+    }
+    if (cpu->singlestep_enabled || singlestep) {
+        max_insns = 1;
+    }
+
  buffer_overflow:
     tb = tb_alloc(pc);
     if (unlikely(!tb)) {
@@ -1710,6 +1722,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
     tb->cflags = cflags;
     tb->trace_vcpu_dstate = *cpu->trace_dstate;
     tcg_ctx->tb_cflags = cflags;
+ tb_overflow:
 
 #ifdef CONFIG_PROFILER
     /* includes aborted translations because of exceptions */
@@ -1720,7 +1733,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
     tcg_func_start(tcg_ctx);
 
     tcg_ctx->cpu = ENV_GET_CPU(env);
-    gen_intermediate_code(cpu, tb);
+    gen_intermediate_code(cpu, tb, max_insns);
     tcg_ctx->cpu = NULL;
 
     trace_translate_block(tb, tb->pc, tb->tc.ptr);
@@ -1743,14 +1756,39 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
     ti = profile_getclock();
 #endif
 
-    /* ??? Overflow could be handled better here.  In particular, we
-       don't need to re-do gen_intermediate_code, nor should we re-do
-       the tcg optimization currently hidden inside tcg_gen_code.  All
-       that should be required is to flush the TBs, allocate a new TB,
-       re-initialize it per above, and re-do the actual code generation.  */
     gen_code_size = tcg_gen_code(tcg_ctx, tb);
     if (unlikely(gen_code_size < 0)) {
-        goto buffer_overflow;
+        switch (gen_code_size) {
+        case -1:
+            /*
+             * Overflow of code_gen_buffer, or the current slice of it.
+             *
+             * TODO: We don't need to re-do gen_intermediate_code, nor
+             * should we re-do the tcg optimization currently hidden
+             * inside tcg_gen_code.  All that should be required is to
+             * flush the TBs, allocate a new TB, re-initialize it per
+             * above, and re-do the actual code generation.
+             */
+            goto buffer_overflow;
+
+        case -2:
+            /*
+             * The code generated for the TranslationBlock is too large.
+             * The maximum size allowed by the unwind info is 64k.
+             * There may be stricter constraints from relocations
+             * in the tcg backend.
+             *
+             * Try again with half as many insns as we attempted this time.
+             * If a single insn overflows, there's a bug somewhere...
+             */
+            max_insns = tb->icount;
+            assert(max_insns > 1);
+            max_insns /= 2;
+            goto tb_overflow;
+
+        default:
+            g_assert_not_reached();
+        }
     }
     search_size = encode_search(tb, (void *)gen_code_buf + gen_code_size);
     if (unlikely(search_size < 0)) {
@@ -2214,8 +2252,7 @@ void tb_flush_jmp_cache(CPUState *cpu, target_ulong addr)
     tb_jmp_cache_clear_page(cpu, addr);
 }
 
-static void print_qht_statistics(FILE *f, fprintf_function cpu_fprintf,
-                                 struct qht_stats hst)
+static void print_qht_statistics(struct qht_stats hst)
 {
     uint32_t hgram_opts;
     size_t hgram_bins;
@@ -2224,7 +2261,7 @@ static void print_qht_statistics(FILE *f, fprintf_function cpu_fprintf,
     if (!hst.head_buckets) {
         return;
     }
-    cpu_fprintf(f, "TB hash buckets     %zu/%zu (%0.2f%% head buckets used)\n",
+    qemu_printf("TB hash buckets     %zu/%zu (%0.2f%% head buckets used)\n",
                 hst.used_head_buckets, hst.head_buckets,
                 (double)hst.used_head_buckets / hst.head_buckets * 100);
 
@@ -2234,7 +2271,7 @@ static void print_qht_statistics(FILE *f, fprintf_function cpu_fprintf,
         hgram_opts |= QDIST_PR_NODECIMAL;
     }
     hgram = qdist_pr(&hst.occupancy, 10, hgram_opts);
-    cpu_fprintf(f, "TB hash occupancy   %0.2f%% avg chain occ. Histogram: %s\n",
+    qemu_printf("TB hash occupancy   %0.2f%% avg chain occ. Histogram: %s\n",
                 qdist_avg(&hst.occupancy) * 100, hgram);
     g_free(hgram);
 
@@ -2247,7 +2284,7 @@ static void print_qht_statistics(FILE *f, fprintf_function cpu_fprintf,
         hgram_opts |= QDIST_PR_NODECIMAL | QDIST_PR_NOBINRANGE;
     }
     hgram = qdist_pr(&hst.chain, hgram_bins, hgram_opts);
-    cpu_fprintf(f, "TB hash avg chain   %0.3f buckets. Histogram: %s\n",
+    qemu_printf("TB hash avg chain   %0.3f buckets. Histogram: %s\n",
                 qdist_avg(&hst.chain), hgram);
     g_free(hgram);
 }
@@ -2285,7 +2322,7 @@ static gboolean tb_tree_stats_iter(gpointer key, gpointer value, gpointer data)
     return false;
 }
 
-void dump_exec_info(FILE *f, fprintf_function cpu_fprintf)
+void dump_exec_info(void)
 {
     struct tb_tree_stats tst = {};
     struct qht_stats hst;
@@ -2294,48 +2331,49 @@ void dump_exec_info(FILE *f, fprintf_function cpu_fprintf)
     tcg_tb_foreach(tb_tree_stats_iter, &tst);
     nb_tbs = tst.nb_tbs;
     /* XXX: avoid using doubles ? */
-    cpu_fprintf(f, "Translation buffer state:\n");
+    qemu_printf("Translation buffer state:\n");
     /*
      * Report total code size including the padding and TB structs;
      * otherwise users might think "-tb-size" is not honoured.
      * For avg host size we use the precise numbers from tb_tree_stats though.
      */
-    cpu_fprintf(f, "gen code size       %zu/%zu\n",
+    qemu_printf("gen code size       %zu/%zu\n",
                 tcg_code_size(), tcg_code_capacity());
-    cpu_fprintf(f, "TB count            %zu\n", nb_tbs);
-    cpu_fprintf(f, "TB avg target size  %zu max=%zu bytes\n",
+    qemu_printf("TB count            %zu\n", nb_tbs);
+    qemu_printf("TB avg target size  %zu max=%zu bytes\n",
                 nb_tbs ? tst.target_size / nb_tbs : 0,
                 tst.max_target_size);
-    cpu_fprintf(f, "TB avg host size    %zu bytes (expansion ratio: %0.1f)\n",
+    qemu_printf("TB avg host size    %zu bytes (expansion ratio: %0.1f)\n",
                 nb_tbs ? tst.host_size / nb_tbs : 0,
                 tst.target_size ? (double)tst.host_size / tst.target_size : 0);
-    cpu_fprintf(f, "cross page TB count %zu (%zu%%)\n", tst.cross_page,
-            nb_tbs ? (tst.cross_page * 100) / nb_tbs : 0);
-    cpu_fprintf(f, "direct jump count   %zu (%zu%%) (2 jumps=%zu %zu%%)\n",
+    qemu_printf("cross page TB count %zu (%zu%%)\n", tst.cross_page,
+                nb_tbs ? (tst.cross_page * 100) / nb_tbs : 0);
+    qemu_printf("direct jump count   %zu (%zu%%) (2 jumps=%zu %zu%%)\n",
                 tst.direct_jmp_count,
                 nb_tbs ? (tst.direct_jmp_count * 100) / nb_tbs : 0,
                 tst.direct_jmp2_count,
                 nb_tbs ? (tst.direct_jmp2_count * 100) / nb_tbs : 0);
 
     qht_statistics_init(&tb_ctx.htable, &hst);
-    print_qht_statistics(f, cpu_fprintf, hst);
+    print_qht_statistics(hst);
     qht_statistics_destroy(&hst);
 
-    cpu_fprintf(f, "\nStatistics:\n");
-    cpu_fprintf(f, "TB flush count      %u\n",
+    qemu_printf("\nStatistics:\n");
+    qemu_printf("TB flush count      %u\n",
                 atomic_read(&tb_ctx.tb_flush_count));
-    cpu_fprintf(f, "TB invalidate count %zu\n", tcg_tb_phys_invalidate_count());
+    qemu_printf("TB invalidate count %zu\n",
+                tcg_tb_phys_invalidate_count());
 
     tlb_flush_counts(&flush_full, &flush_part, &flush_elide);
-    cpu_fprintf(f, "TLB full flushes    %zu\n", flush_full);
-    cpu_fprintf(f, "TLB partial flushes %zu\n", flush_part);
-    cpu_fprintf(f, "TLB elided flushes  %zu\n", flush_elide);
-    tcg_dump_info(f, cpu_fprintf);
+    qemu_printf("TLB full flushes    %zu\n", flush_full);
+    qemu_printf("TLB partial flushes %zu\n", flush_part);
+    qemu_printf("TLB elided flushes  %zu\n", flush_elide);
+    tcg_dump_info();
 }
 
-void dump_opcount_info(FILE *f, fprintf_function cpu_fprintf)
+void dump_opcount_info(void)
 {
-    tcg_dump_op_count(f, cpu_fprintf);
+    tcg_dump_op_count();
 }
 
 #else /* CONFIG_USER_ONLY */