summaryrefslogtreecommitdiffstats
path: root/src/llvm/optimization.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/llvm/optimization.cpp')
-rw-r--r--src/llvm/optimization.cpp317
1 files changed, 317 insertions, 0 deletions
diff --git a/src/llvm/optimization.cpp b/src/llvm/optimization.cpp
new file mode 100644
index 0000000..15597bf
--- /dev/null
+++ b/src/llvm/optimization.cpp
@@ -0,0 +1,317 @@
+/*
+ * (C) 2010 by Computer System Laboratory, IIS, Academia Sinica, Taiwan.
+ * See COPYRIGHT in top-level directory.
+ *
+ * This file implements the basic optimization schemes including
+ * (1) instruction TLB (iTLB),
+ * (2) indirect branch target cache (IBTC),
+ * (3) cross-page block linking (CPBL), and
+ * (4) large page table (LPT).
+ */
+
+#include "tracer.h"
+#include "optimization.h"
+
+
+#if defined(ENALBE_CPU_PROFILE)
+# define PROFILE(X) do { X; } while (0)
+#else
+# define PROFILE(X) do { } while (0)
+#endif
+
+/* The following implements routines of the C interfaces for QEMU. */
+extern "C" {
+
+TranslationBlock *tbs;
+unsigned long alignment_count[2]; /* 0: misaligned, 1: aligned. */
+unsigned long aligned_boundary = 16;
+
+extern uint8_t *ibtc_ret_addr;
+
+/*
+ * iTLB (Instruction TLB)
+ */
+void itlb_update_entry(CPUArchState *env, TranslationBlock *tb)
+{
+ ITLB &itlb = cpu_get_itlb(env);
+ itlb.insert(tb->pc, tb->page_addr[0] & TARGET_PAGE_MASK);
+ if (tb->page_addr[1] != (tb_page_addr_t)-1)
+ itlb.insert(tb->pc + tb->size, tb->page_addr[1] & TARGET_PAGE_MASK);
+}
+
+int itlb_lookup(CPUArchState *env, target_ulong pc, uint64_t paddr)
+{
+ ITLB &itlb = cpu_get_itlb(env);
+ return itlb.get(pc) == (paddr & TARGET_PAGE_MASK);
+}
+
+/*
+ * IBTC (Indirect Branch Translation Cache)
+ */
+#if defined(ENABLE_IBTC)
+
+/* Update IBTC hash table.
+ * Note: we do not cache TBs that cross page boundary. */
+void ibtc_update_entry(CPUArchState *env, TranslationBlock *tb)
+{
+ IBTC &ibtc = cpu_get_ibtc(env);
+ if (!ibtc.needUpdate())
+ return;
+
+ ibtc.resetUpdate();
+
+#if defined(CONFIG_SOFTMMU)
+ if (tb->page_addr[1] != (tb_page_addr_t)-1)
+ return;
+#endif
+
+ ibtc.insert(tb->pc, tb);
+}
+
+/* Helper function to lookup the IBTC hash table. */
+void *helper_lookup_ibtc(CPUArchState *env)
+{
+ CPUState *cpu = ENV_GET_CPU(env);
+ if (unlikely(cpu->tcg_exit_req != 0)) {
+ cpu->tcg_exit_req = 0;
+ return ibtc_ret_addr;
+ }
+
+ /* A match of 'pc', 'cs_base' and 'flags' results in a IBTC hit. Since
+ * cs_base is only meaningful with x86 guest and system mode (cs_base is
+ * always 0 for user-mode emulation and non-x86 guest), we only compare
+ * cs_base with system mode emulation of x86 guest. */
+
+ target_ulong pc = cpu_get_pc(env);
+ IBTC &ibtc = cpu_get_ibtc(env);
+ TranslationBlock *next_tb = ibtc.get(pc);
+
+ PROFILE( ibtc.incTotal() );
+
+ if (likely(next_tb)) {
+#if defined(CONFIG_SOFTMMU)
+ if (likely(itlb_lookup(env, pc, next_tb->page_addr[0])))
+#endif
+ if (likely(cpu_check_state(env, next_tb->cs_base, next_tb->flags))) {
+ cpu->current_tb = next_tb;
+ return next_tb->opt_ptr;
+ }
+ }
+
+ PROFILE( ibtc.incMiss() );
+
+ ibtc.setUpdate();
+ return ibtc_ret_addr;
+}
+#else
+void ibtc_update_entry(CPUArchState *env, TranslationBlock *tb) {}
+void *helper_lookup_ibtc(CPUArchState *env) { return ibtc_ret_addr; }
+#endif /* ENABLE_IBTC */
+
+
+/*
+ * CPBL (Cross-Page Block Linking)
+ */
+#if defined(ENABLE_CPBL)
+void *helper_lookup_cpbl(CPUArchState *env)
+{
+ CPUState *cpu = ENV_GET_CPU(env);
+ if (unlikely(cpu->tcg_exit_req != 0)) {
+ cpu->tcg_exit_req = 0;
+ return ibtc_ret_addr;
+ }
+
+ /* A match of 'pc', 'cs_base' and 'flags' results in a CPBL hit. Since
+ * cs_base is only meaningful with x86 guest and system mode (cs_base is
+ * always 0 for user-mode emulation and non-x86 guest), we only compare
+ * cs_base with system mode emulation of x86 guest. */
+
+ target_ulong pc = cpu_get_pc(env);
+ TranslationBlock *next_tb = cpu->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
+
+ PROFILE( cpu_get_cpbl(env).incTotal() );
+
+ if (likely(next_tb && next_tb->pc == pc))
+ if (likely(cpu_check_state(env, next_tb->cs_base, next_tb->flags))) {
+ cpu->current_tb = next_tb;
+ return next_tb->opt_ptr;
+ }
+
+ PROFILE( cpu_get_cpbl(env).incMiss() );
+
+ return ibtc_ret_addr;
+}
+
+int helper_validate_cpbl(CPUArchState *env, target_ulong pc, int id)
+{
+ TranslationBlock *tb = &tbs[id];
+
+ PROFILE( cpu_get_cpbl(env).incValidateTotal() );
+ if (tb->page_addr[1] == (tb_page_addr_t)-1 &&
+ likely(itlb_lookup(env, pc, tb->page_addr[0])))
+ return 1;
+ if (likely(itlb_lookup(env, pc + TARGET_PAGE_SIZE, tb->page_addr[1])))
+ return 1;
+ PROFILE( cpu_get_cpbl(env).incValidateMiss() );
+ return 0;
+}
+
+#else
+void *helper_lookup_cpbl(CPUArchState *env) { return ibtc_ret_addr; }
+int helper_validate_cpbl(CPUArchState *env, target_ulong pc, int id) { return 0; }
+#endif /* ENABLE_CPBL */
+
+
+#if defined(ENABLE_LPAGE)
+int lpt_reset(CPUArchState *env)
+{
+ if (env->opt_link == nullptr)
+ return 0;
+ LargePageTable &lpt = cpu_get_lpt(env);
+ lpt.reset();
+ return 1;
+}
+/* Add a large page to LPT. */
+int lpt_add_page(CPUArchState *env, target_ulong addr, target_ulong size)
+{
+ LargePageTable &lpt = cpu_get_lpt(env);
+ lpt.insert(addr, size);
+ return 1;
+}
+
+/* Given an address, return 1 if this address overlaps with any tracked
+ * large page and return 0 otherwise. The large page record is NOT removed
+ * if it is found. */
+int lpt_search_page(CPUArchState *env, target_ulong addr, target_ulong *addrp,
+ target_ulong *sizep)
+{
+ LargePageTable &lpt = cpu_get_lpt(env);
+ return lpt.search(addr, LargePageTable::SEARCH, addrp, sizep);
+}
+
+/* Given an address, return the pte index if this address overlaps with
+ * any tracked large page and return -1 otherwise. If a large page is found,
+ * remove it from the list. */
+int lpt_flush_page(CPUArchState *env, target_ulong addr, target_ulong *addrp,
+ target_ulong *sizep)
+{
+ LargePageTable &lpt = cpu_get_lpt(env);
+ PROFILE( lpt.incTotal() );
+ if (lpt.search(addr, LargePageTable::FLUSH, addrp, sizep))
+ return 1;
+ PROFILE( lpt.incMiss() );
+ return 0;
+}
+#else
+int lpt_reset(CPUArchState *env) { return 0; }
+int lpt_add_page(CPUArchState *env, target_ulong addr, target_ulong size) { return 0; }
+int lpt_search_page(CPUArchState *env, target_ulong addr,
+ target_ulong *addrp, target_ulong *sizep) { return 0; }
+int lpt_flush_page(CPUArchState *env, target_ulong addr,
+ target_ulong *addrp, target_ulong *sizep) { return 0; }
+#endif
+
+/* Initialize the optimization schemes. */
+int optimization_init(CPUArchState *env)
+{
+ CPUState *cpu = ENV_GET_CPU(env);
+ if (cpu->cpu_index == 0) {
+ tbs = tcg_ctx.tb_ctx->tbs;
+ if (!tbs) {
+ std::cerr << __func__ << ": fatal error.\n";
+ exit(0);
+ }
+ if (get_cpu_size() != sizeof(CPUArchState)) {
+ std::cerr << "Inconsistent CPUArchState size in C and C++.\n"
+ "This may be because sizeof empty struct in C is "
+ "different with C++. Please fix this.\n";
+ exit(0);
+ }
+ }
+
+ /* Create a processor tracer for each env. */
+ BaseTracer *Tracer = BaseTracer::CreateTracer(env);
+
+ /* Create optimization facilities. */
+ CPUOptimization *Opt = new CPUOptimization(cpu, Tracer);
+
+ /* Make an uplink to the optimizaiton facility object. */
+ env->opt_link = Opt;
+ return 1;
+}
+
+/* Finalize the optimization schemes. */
+int optimization_finalize(CPUArchState *env)
+{
+ if (env->opt_link == nullptr)
+ return 0;
+
+ PROFILE( cpu_get_ibtc(env).dump() );
+#if defined(CONFIG_SOFTMMU)
+ PROFILE( cpu_get_cpbl(env).dump() );
+ PROFILE( cpu_get_lpt(env).dump() );
+#endif
+
+ BaseTracer::DeleteTracer(env);
+ delete (CPUOptimization *)env->opt_link;
+ return 1;
+}
+
+/* Reset to default values of the optimizatiion schemes. */
+int optimization_reset(CPUArchState *env, int force_flush)
+{
+ if (env->opt_link == nullptr)
+ return 0;
+
+ ITLB &itlb = cpu_get_itlb(env);
+ IBTC &ibtc = cpu_get_ibtc(env);
+
+ itlb.reset();
+ if (force_flush)
+ ibtc.reset();
+
+ tracer_reset(env);
+ return 1;
+}
+
+int optimization_remove_entry(CPUArchState *env, TranslationBlock *tb)
+{
+ IBTC &ibtc = cpu_get_ibtc(env);
+ ibtc.remove(tb);
+ return 1;
+}
+
+int optimization_flush_page(CPUArchState *env, target_ulong pc)
+{
+#if defined(CONFIG_SOFTMMU)
+ ITLB &itlb = cpu_get_itlb(env);
+ itlb.flush(pc);
+#else
+ IBTC &ibtc = cpu_get_ibtc(env);
+ ibtc.reset();
+#endif
+ return 1;
+}
+
+int optimization_init_tb(TranslationBlock *tb, int id)
+{
+ tb->id = id;
+ tb->tid = -1;
+ tb->mode = BLOCK_NONE;
+ tb->opt_ptr = nullptr;
+ tb->exec_count = 0;
+ tb->patch_jmp = 0;
+ tb->patch_next = 0;
+ tb->jmp_pc[0] = tb->jmp_pc[1] = (target_ulong)-1;
+ tb->image = nullptr;
+ tb->state = nullptr;
+ tb->chain = nullptr;
+ return 1;
+}
+
+}
+
+/*
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
+
OpenPOWER on IntegriCloud