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