Actually this barely even rises to the level of an RFC, but
since I'm not entirely sure how or if it might be possible to
turn this into upstreamable code I thought I might as well
send it out as-is in case anybody else finds it useful.

The basic idea is that you build the linux-user binary and
run it on something (anything). Instead of actually running
code we instead just loop round feeding every possible
instruction pattern to the decoder. This lets us catch:
 * "can't happen" assertions in the wrong place
 * TCG temp leaks
 * insns which generate too many TCG ops

Obvious deficiencies here:
 * no UI for specifying that you want to test a smaller
   part of the instruction space
 * an assumption that instructions are fixed-length 32 bits
 * cheesily hardwired in

You can do a complete sweep of an entire 32-bit instruction
encoding space within a couple of hours.

thanks
-- PMM

---
 translate-all.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 51 insertions(+)

diff --git a/translate-all.c b/translate-all.c
index 543e1ff..716f501 100644
--- a/translate-all.c
+++ b/translate-all.c
@@ -195,6 +195,53 @@ int cpu_gen_code(CPUArchState *env, TranslationBlock *tb, 
int *gen_code_size_ptr
     return 0;
 }
 
+#if 1
+static void cpu_exercise_decoder(CPUArchState *env, TranslationBlock *tb)
+{
+    fprintf(stderr, "Test mode, exercising decoder\n");
+    uint32_t insn = 0;
+    int maxops = 0, numops;
+    uint32_t insnbuf[1];
+
+    /* Force the decoder to do just one instruction at a time */
+    singlestep = 1;
+
+    for (;;) {
+        /* ARM A64 specific hack: just skip all the unallocateds */
+        if (insn && !(insn & (3 << 27))) {
+            insn++;
+            continue;
+        }
+
+        if (!(insn & 0xffff)) {
+            fprintf(stderr, "%x", insn >> 28);
+        }
+
+        tb->pc = h2g_nocheck(&insnbuf);
+        insnbuf[0] = insn;
+
+        tcg_func_start(&tcg_ctx);
+        gen_intermediate_code(env, tb);
+
+        numops = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf;
+        if (numops > maxops) {
+            maxops = numops;
+            fprintf(stderr, "\nNew worst case TCG ops: %d (insn %08x)\n",
+                             numops, insn);
+        }
+
+        insn++;
+        if (insn == 0) {
+            break;
+        }
+    }
+
+    fprintf(stderr, "\nExercising complete. Worst case TCG ops: %d\n", maxops);
+
+    exit(0);
+}
+#endif
+
 /* The cpu state corresponding to 'searched_pc' is restored.
  */
 static int cpu_restore_state_from_tb(TranslationBlock *tb, CPUArchState *env,
@@ -966,6 +1013,10 @@ TranslationBlock *tb_gen_code(CPUArchState *env,
     tb->cs_base = cs_base;
     tb->flags = flags;
     tb->cflags = cflags;
+#if 1
+    cpu_exercise_decoder(env, tb);
+    exit(0);
+#endif
     cpu_gen_code(env, tb, &code_gen_size);
     tcg_ctx.code_gen_ptr = (void *)(((uintptr_t)tcg_ctx.code_gen_ptr +
             code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
-- 
1.8.5


Reply via email to