diff --git a/examples/mandelbrot.c b/examples/mandelbrot.c index 2c010696..4ef8dc2e 100644 --- a/examples/mandelbrot.c +++ b/examples/mandelbrot.c @@ -160,7 +160,7 @@ int main(int argc, char **argv) ctx.fixed_regset = ~debug_regset; ctx.ret_type = IR_I32; gen_mandelbrot(&ctx); -// ir_save(&ctx, stderr); +// ir_save(&ctx, 0, stderr); ir_build_def_use_lists(&ctx); if (opt_level > 1) { @@ -186,7 +186,7 @@ int main(int argc, char **argv) ir_truncate(&ctx); // ir_dump(&ctx, stderr); - ir_save(&ctx, stderr); + ir_save(&ctx, 0, stderr); ir_dump_live_ranges(&ctx, stderr); f = fopen("mandelbrot.dot", "w+"); ir_dump_dot(&ctx, "mandelbrot", f); diff --git a/ir.h b/ir.h index 3fb57cf2..16551b3b 100644 --- a/ir.h +++ b/ir.h @@ -843,8 +843,14 @@ int ir_load_llvm_bitcode(ir_loader *loader, const char *filename); int ir_load_llvm_asm(ir_loader *loader, const char *filename); /* IR save API (implementation in ir_save.c) */ +#define IR_SAVE_CFG (1<<0) /* add info about CFG */ +#define IR_SAVE_CFG_MAP (1<<1) /* add info about CFG block assignment */ +#define IR_SAVE_USE_LISTS (1<<2) /* add info about def->use lists */ +#define IR_SAVE_RULES (1<<3) /* add info about selected code-generation rules */ +#define IR_SAVE_REGS (1<<4) /* add info about selected registers */ + void ir_print_proto(const ir_ctx *ctx, ir_ref proto, FILE *f); -void ir_save(const ir_ctx *ctx, FILE *f); +void ir_save(const ir_ctx *ctx, uint32_t save_flags, FILE *f); /* IR debug dump API (implementation in ir_dump.c) */ void ir_dump(const ir_ctx *ctx, FILE *f); diff --git a/ir_dump.c b/ir_dump.c index 34002a60..c3a86e25 100644 --- a/ir_dump.c +++ b/ir_dump.c @@ -511,7 +511,46 @@ void ir_dump_codegen(const ir_ctx *ctx, FILE *f) if ((bb->flags & (IR_BB_START|IR_BB_ENTRY|IR_BB_EMPTY)) == IR_BB_EMPTY) { continue; } - fprintf(f, "#BB%d:\n", b); + + fprintf(f, "#BB%d: end=l_%d", b, bb->end); + if (bb->flags && IR_BB_UNREACHABLE) { + fprintf(f, ", U"); + } + if (bb->dom_parent > 0) { + fprintf(f, ", idom=BB%d(%d)", bb->dom_parent, bb->dom_depth); + } + if (bb->loop_depth != 0) { + if (bb->flags & IR_BB_LOOP_HEADER) { + if (bb->loop_header > 0) { + fprintf(f, ", loop=HDR,BB%d(%d)", bb->loop_header, bb->loop_depth); + } else { + IR_ASSERT(bb->loop_depth == 1); + fprintf(f, ", loop=HDR(%d)", bb->loop_depth); + } + } else { + IR_ASSERT(bb->loop_header > 0); + fprintf(f, ", loop=BB%d(%d)", bb->loop_header, bb->loop_depth); + } + } + if (bb->predecessors_count) { + uint32_t i; + + fprintf(f, ", pred(%d)=[BB%d", bb->predecessors_count, ctx->cfg_edges[bb->predecessors]); + for (i = 1; i < bb->predecessors_count; i++) { + fprintf(f, ", BB%d", ctx->cfg_edges[bb->predecessors + i]); + } + fprintf(f, "]"); + } + if (bb->successors_count) { + uint32_t i; + + fprintf(f, ", succ(%d)=[BB%d", bb->successors_count, ctx->cfg_edges[bb->successors]); + for (i = 1; i < bb->successors_count; i++) { + fprintf(f, ", BB%d", ctx->cfg_edges[bb->successors + i]); + } + fprintf(f, "]"); + } + fprintf(f, "\n"); for (i = bb->start, insn = ctx->ir_base + i; i <= bb->end;) { flags = ir_op_flags[insn->op]; diff --git a/ir_main.c b/ir_main.c index 4ab136f2..900aa5a2 100644 --- a/ir_main.c +++ b/ir_main.c @@ -58,14 +58,23 @@ static void help(const char *cmd) " --emit-c [file-name] - convert to C source\n" " --emit-llvm [file-name] - convert to LLVM\n" " --save [file-name] - save IR\n" + " --save-cfg - save IR\n" + " --save-cfg-map - save IR\n" + " --save-rules - save IR\n" + " --save-regs - save IR\n" + " --save-use_lists - save IR\n" " --dot [file-name] - dump IR graph\n" " --dump [file-name] - dump IR table\n" " --dump-after-load - dump IR after load and local optimization\n" " --dump-after-sccp - dump IR after SCCP optimization pass\n" + " --dump-after-cfg - dump IR after CFG construction\n" + " --dump-after-dom - dump IR after Dominators tree construction\n" + " --dump-after-loop - dump IR after Loop detection\n" " --dump-after-gcm - dump IR after GCM optimization pass\n" " --dump-after-schedule - dump IR after SCHEDULE pass\n" " --dump-after-live-ranges - dump IR after live ranges identification\n" " --dump-after-coalescing - dump IR after live ranges coalescing\n" + " --dump-after-regalloc - dump IR after register allocation\n" " --dump-after-all - dump IR after each pass\n" " --dump-final - dump IR after all pass\n" " --dump-size - dump generated code size\n" @@ -99,15 +108,19 @@ static void help(const char *cmd) #define IR_DUMP_AFTER_LOAD (1<<16) #define IR_DUMP_AFTER_SCCP (1<<17) -#define IR_DUMP_AFTER_GCM (1<<18) -#define IR_DUMP_AFTER_SCHEDULE (1<<19) -#define IR_DUMP_AFTER_LIVE_RANGES (1<<20) -#define IR_DUMP_AFTER_COALESCING (1<<21) +#define IR_DUMP_AFTER_CFG (1<<18) +#define IR_DUMP_AFTER_DOM (1<<19) +#define IR_DUMP_AFTER_LOOP (1<<20) +#define IR_DUMP_AFTER_GCM (1<<21) +#define IR_DUMP_AFTER_SCHEDULE (1<<22) +#define IR_DUMP_AFTER_LIVE_RANGES (1<<23) +#define IR_DUMP_AFTER_COALESCING (1<<24) +#define IR_DUMP_AFTER_REGALLOC (1<<25) #define IR_DUMP_AFTER_ALL (1<<29) #define IR_DUMP_FINAL (1<<30) -static int _save(ir_ctx *ctx, uint32_t dump, uint32_t pass, FILE *f, const char *func_name) +static int _save(ir_ctx *ctx, uint32_t save_flags, uint32_t dump, uint32_t pass, FILE *f, const char *func_name) { char fn[4096]; bool close = 0; @@ -118,19 +131,27 @@ static int _save(ir_ctx *ctx, uint32_t dump, uint32_t pass, FILE *f, const char snprintf(fn, sizeof(fn)-1, "01-load-%s.ir", func_name); } else if (pass == IR_DUMP_AFTER_SCCP) { snprintf(fn, sizeof(fn)-1, "02-sccp-%s.ir", func_name); + } else if (pass == IR_DUMP_AFTER_CFG) { + snprintf(fn, sizeof(fn)-1, "03-cfg-%s.ir", func_name); + } else if (pass == IR_DUMP_AFTER_DOM) { + snprintf(fn, sizeof(fn)-1, "04-dom-%s.ir", func_name); + } else if (pass == IR_DUMP_AFTER_LOOP) { + snprintf(fn, sizeof(fn)-1, "05-loop-%s.ir", func_name); } else if (pass == IR_DUMP_AFTER_GCM) { - snprintf(fn, sizeof(fn)-1, "03-gcm-%s.ir", func_name); + snprintf(fn, sizeof(fn)-1, "06-gcm-%s.ir", func_name); } else if (pass == IR_DUMP_AFTER_SCHEDULE) { - snprintf(fn, sizeof(fn)-1, "04-schedule-%s.ir", func_name); + snprintf(fn, sizeof(fn)-1, "07-schedule-%s.ir", func_name); } else if (pass == IR_DUMP_AFTER_LIVE_RANGES) { - snprintf(fn, sizeof(fn)-1, "05-live-ranges-%s.ir", func_name); + snprintf(fn, sizeof(fn)-1, "08-live-ranges-%s.ir", func_name); } else if (pass == IR_DUMP_AFTER_COALESCING) { - snprintf(fn, sizeof(fn)-1, "06-coalescing-%s.ir", func_name); + snprintf(fn, sizeof(fn)-1, "09-coalescing-%s.ir", func_name); + } else if (pass == IR_DUMP_AFTER_REGALLOC) { + snprintf(fn, sizeof(fn)-1, "10-regalloc-%s.ir", func_name); } else if (pass == IR_DUMP_FINAL) { if (dump & IR_DUMP_CODEGEN) { - snprintf(fn, sizeof(fn)-1, "07-codegen-%s.ir", func_name); + snprintf(fn, sizeof(fn)-1, "11-codegen-%s.ir", func_name); } else { - snprintf(fn, sizeof(fn)-1, "07-final-%s.ir", func_name); + snprintf(fn, sizeof(fn)-1, "11-final-%s.ir", func_name); } } else { f = stderr; // TODO: @@ -148,7 +169,7 @@ static int _save(ir_ctx *ctx, uint32_t dump, uint32_t pass, FILE *f, const char if (pass == IR_DUMP_FINAL && (dump & IR_DUMP_CODEGEN)) { ir_dump_codegen(ctx, f); } else if (dump & IR_DUMP_SAVE) { - ir_save(ctx, f); + ir_save(ctx, save_flags, f); } if (dump & IR_DUMP_DUMP) { ir_dump(ctx, f); @@ -174,10 +195,10 @@ static int _save(ir_ctx *ctx, uint32_t dump, uint32_t pass, FILE *f, const char return 1; } -int ir_compile_func(ir_ctx *ctx, int opt_level, uint32_t dump, FILE *dump_file, const char *func_name) +int ir_compile_func(ir_ctx *ctx, int opt_level, uint32_t save_flags, uint32_t dump, FILE *dump_file, const char *func_name) { if ((dump & (IR_DUMP_AFTER_LOAD|IR_DUMP_AFTER_ALL)) - && !_save(ctx, dump, IR_DUMP_AFTER_LOAD, dump_file, func_name)) { + && !_save(ctx, save_flags, dump, IR_DUMP_AFTER_LOAD, dump_file, func_name)) { return 0; } @@ -193,7 +214,7 @@ int ir_compile_func(ir_ctx *ctx, int opt_level, uint32_t dump, FILE *dump_file, if (opt_level > 1) { ir_sccp(ctx); if ((dump & (IR_DUMP_AFTER_SCCP|IR_DUMP_AFTER_ALL)) - && !_save(ctx, dump, IR_DUMP_AFTER_SCCP, dump_file, func_name)) { + && !_save(ctx, save_flags, dump, IR_DUMP_AFTER_SCCP, dump_file, func_name)) { return 0; } #ifdef IR_DEBUG @@ -203,6 +224,10 @@ int ir_compile_func(ir_ctx *ctx, int opt_level, uint32_t dump, FILE *dump_file, if (opt_level > 0 || (ctx->flags & (IR_GEN_NATIVE|IR_GEN_CODE))) { ir_build_cfg(ctx); + if ((dump & (IR_DUMP_AFTER_CFG|IR_DUMP_AFTER_ALL)) + && !_save(ctx, save_flags, dump, IR_DUMP_AFTER_CFG, dump_file, func_name)) { + return 0; + } #ifdef IR_DEBUG ir_check(ctx); #endif @@ -211,10 +236,20 @@ int ir_compile_func(ir_ctx *ctx, int opt_level, uint32_t dump, FILE *dump_file, /* Schedule */ if (opt_level > 0) { ir_build_dominators_tree(ctx); + if ((dump & (IR_DUMP_AFTER_DOM|IR_DUMP_AFTER_ALL)) + && !_save(ctx, save_flags, dump, IR_DUMP_AFTER_DOM, dump_file, func_name)) { + return 0; + } + ir_find_loops(ctx); + if ((dump & (IR_DUMP_AFTER_LOOP|IR_DUMP_AFTER_ALL)) + && !_save(ctx, save_flags, dump, IR_DUMP_AFTER_LOOP, dump_file, func_name)) { + return 0; + } + ir_gcm(ctx); if ((dump & (IR_DUMP_AFTER_GCM|IR_DUMP_AFTER_ALL)) - && !_save(ctx, dump, IR_DUMP_AFTER_GCM, dump_file, func_name)) { + && !_save(ctx, save_flags, dump, IR_DUMP_AFTER_GCM, dump_file, func_name)) { return 0; } #ifdef IR_DEBUG @@ -223,7 +258,7 @@ int ir_compile_func(ir_ctx *ctx, int opt_level, uint32_t dump, FILE *dump_file, ir_schedule(ctx); if ((dump & (IR_DUMP_AFTER_SCHEDULE|IR_DUMP_AFTER_ALL)) - && !_save(ctx, dump, IR_DUMP_AFTER_SCHEDULE, dump_file, func_name)) { + && !_save(ctx, save_flags, dump, IR_DUMP_AFTER_SCHEDULE, dump_file, func_name)) { return 0; } #ifdef IR_DEBUG @@ -240,19 +275,23 @@ int ir_compile_func(ir_ctx *ctx, int opt_level, uint32_t dump, FILE *dump_file, ir_compute_live_ranges(ctx); if ((dump & (IR_DUMP_AFTER_LIVE_RANGES|IR_DUMP_AFTER_ALL)) - && !_save(ctx, dump, IR_DUMP_AFTER_LIVE_RANGES, dump_file, func_name)) { + && !_save(ctx, save_flags, dump, IR_DUMP_AFTER_LIVE_RANGES, dump_file, func_name)) { return 0; } ir_coalesce(ctx); if ((dump & (IR_DUMP_AFTER_COALESCING|IR_DUMP_AFTER_ALL)) - && !_save(ctx, dump, IR_DUMP_AFTER_COALESCING, dump_file, func_name)) { + && !_save(ctx, save_flags, dump, IR_DUMP_AFTER_COALESCING, dump_file, func_name)) { return 0; } if (ctx->flags & IR_GEN_NATIVE) { ir_reg_alloc(ctx); + if ((dump & (IR_DUMP_AFTER_REGALLOC|IR_DUMP_AFTER_ALL)) + && !_save(ctx, save_flags, dump, IR_DUMP_AFTER_REGALLOC, dump_file, func_name)) { + return 0; + } } ir_schedule_blocks(ctx); @@ -262,7 +301,7 @@ int ir_compile_func(ir_ctx *ctx, int opt_level, uint32_t dump, FILE *dump_file, } if ((dump & (IR_DUMP_FINAL|IR_DUMP_AFTER_ALL|IR_DUMP_CODEGEN)) - && !_save(ctx, dump, IR_DUMP_FINAL, dump_file, func_name)) { + && !_save(ctx, save_flags, dump, IR_DUMP_FINAL, dump_file, func_name)) { return 0; } @@ -288,6 +327,7 @@ typedef struct _ir_main_loader { int opt_level; uint32_t mflags; uint64_t debug_regset; + uint32_t save_flags; uint32_t dump; bool dump_asm; bool dump_size; @@ -837,7 +877,7 @@ static bool ir_loader_func_process(ir_loader *loader, ir_ctx *ctx, const char *n fprintf(l->dump_file, "\n"); } - if (!ir_compile_func(ctx, l->opt_level, l->dump, l->dump_file, name)) { + if (!ir_compile_func(ctx, l->opt_level, l->save_flags, l->dump, l->dump_file, name)) { return 0; } @@ -932,6 +972,7 @@ int main(int argc, char **argv) char *dump_file = NULL, *c_file = NULL, *llvm_file = 0; FILE *f; bool emit_c = 0, emit_llvm = 0, dump_size = 0, dump_time = 0, dump_asm = 0, run = 0, gdb = 1; + uint32_t save_flags = 0; uint32_t dump = 0; int opt_level = 2; uint32_t flags = 0; @@ -994,6 +1035,21 @@ int main(int argc, char **argv) dump_file = argv[i + 1]; i++; } + } else if (strcmp(argv[i], "--save-cfg") == 0) { + dump |= IR_DUMP_SAVE; + save_flags |= IR_SAVE_CFG; + } else if (strcmp(argv[i], "--save-cfg-map") == 0) { + dump |= IR_DUMP_SAVE; + save_flags |= IR_SAVE_CFG_MAP; + } else if (strcmp(argv[i], "--save-rules") == 0) { + dump |= IR_DUMP_SAVE; + save_flags |= IR_SAVE_RULES; + } else if (strcmp(argv[i], "--save-regs") == 0) { + dump |= IR_DUMP_SAVE; + save_flags |= IR_SAVE_REGS; + } else if (strcmp(argv[i], "--save-use-lists") == 0) { + dump |= IR_DUMP_SAVE; + save_flags |= IR_SAVE_USE_LISTS; } else if (strcmp(argv[i], "--dot") == 0) { dump |= IR_DUMP_DOT; if (i + 1 < argc && argv[i + 1][0] != '-') { @@ -1020,6 +1076,12 @@ int main(int argc, char **argv) dump |= IR_DUMP_AFTER_LOAD; } else if (strcmp(argv[i], "--dump-after-sccp") == 0) { dump |= IR_DUMP_AFTER_SCCP; + } else if (strcmp(argv[i], "--dump-after-cfg") == 0) { + dump |= IR_DUMP_AFTER_CFG; + } else if (strcmp(argv[i], "--dump-after-dom") == 0) { + dump |= IR_DUMP_AFTER_DOM; + } else if (strcmp(argv[i], "--dump-after-loop") == 0) { + dump |= IR_DUMP_AFTER_LOOP; } else if (strcmp(argv[i], "--dump-after-gcm") == 0) { dump |= IR_DUMP_AFTER_GCM; } else if (strcmp(argv[i], "--dump-after-schedule") == 0) { @@ -1028,6 +1090,8 @@ int main(int argc, char **argv) dump |= IR_DUMP_AFTER_LIVE_RANGES; } else if (strcmp(argv[i], "--dump-after-coalescing") == 0) { dump |= IR_DUMP_AFTER_COALESCING; + } else if (strcmp(argv[i], "--dump-after-regalloc") == 0) { + dump |= IR_DUMP_AFTER_REGALLOC; } else if (strcmp(argv[i], "--dump-after-all") == 0) { dump |= IR_DUMP_AFTER_ALL; } else if (strcmp(argv[i], "--dump-final") == 0) { @@ -1106,8 +1170,10 @@ int main(int argc, char **argv) } if (dump && !(dump & (IR_DUMP_AFTER_LOAD|IR_DUMP_AFTER_SCCP| + IR_DUMP_AFTER_CFG|IR_DUMP_AFTER_DOM|IR_DUMP_AFTER_LOOP| IR_DUMP_AFTER_GCM|IR_DUMP_AFTER_SCHEDULE| - IR_DUMP_AFTER_LIVE_RANGES|IR_DUMP_AFTER_COALESCING|IR_DUMP_FINAL))) { + IR_DUMP_AFTER_LIVE_RANGES|IR_DUMP_AFTER_COALESCING|IR_DUMP_AFTER_REGALLOC| + IR_DUMP_FINAL))) { dump |= IR_DUMP_FINAL; } @@ -1179,6 +1245,7 @@ int main(int argc, char **argv) loader.opt_level = opt_level; loader.mflags = mflags; loader.debug_regset = debug_regset; + loader.save_flags = save_flags; loader.dump = dump; loader.dump_asm = dump_asm; loader.dump_size = dump_size; diff --git a/ir_save.c b/ir_save.c index ab0bfb89..3e5d7559 100644 --- a/ir_save.c +++ b/ir_save.c @@ -38,7 +38,55 @@ void ir_print_proto(const ir_ctx *ctx, ir_ref func_proto, FILE *f) } } -void ir_save(const ir_ctx *ctx, FILE *f) +static void ir_save_dessa_moves(const ir_ctx *ctx, int b, ir_block *bb, FILE *f) +{ + uint32_t succ; + ir_block *succ_bb; + ir_use_list *use_list; + ir_ref k, i, *p, use_ref, input; + ir_insn *use_insn; + + IR_ASSERT(bb->successors_count == 1); + succ = ctx->cfg_edges[bb->successors]; + succ_bb = &ctx->cfg_blocks[succ]; + IR_ASSERT(succ_bb->predecessors_count > 1); + use_list = &ctx->use_lists[succ_bb->start]; + k = ir_phi_input_number(ctx, succ_bb, b); + + for (i = 0, p = &ctx->use_edges[use_list->refs]; i < use_list->count; i++, p++) { + use_ref = *p; + use_insn = &ctx->ir_base[use_ref]; + if (use_insn->op == IR_PHI) { + input = ir_insn_op(use_insn, k); + if (IR_IS_CONST_REF(input)) { + fprintf(f, "\t# DESSA MOV c_%d", -input); + } else if (ctx->vregs[input] != ctx->vregs[use_ref]) { + fprintf(f, "\t# DESSA MOV d_%d {R%d}", input, ctx->vregs[input]); + } else { + continue; + } + if (ctx->regs) { + int8_t *regs = ctx->regs[use_ref]; + int8_t reg = regs[k]; + if (reg != IR_REG_NONE) { + fprintf(f, " {%%%s%s}", ir_reg_name(IR_REG_NUM(reg), ctx->ir_base[input].type), + (reg & (IR_REG_SPILL_LOAD|IR_REG_SPILL_SPECIAL)) ? ":load" : ""); + } + } + fprintf(f, " -> d_%d {R%d}", use_ref, ctx->vregs[use_ref]); + if (ctx->regs) { + int8_t reg = ctx->regs[use_ref][0]; + if (reg != IR_REG_NONE) { + fprintf(f, " {%%%s%s}", ir_reg_name(IR_REG_NUM(reg), ctx->ir_base[use_ref].type), + (reg & (IR_REG_SPILL_STORE|IR_REG_SPILL_SPECIAL)) ? ":store" : ""); + } + } + fprintf(f, "\n"); + } + } +} + +void ir_save(const ir_ctx *ctx, uint32_t save_flags, FILE *f) { ir_ref i, j, n, ref, *p; ir_insn *insn; @@ -65,16 +113,90 @@ void ir_save(const ir_ctx *ctx, FILE *f) for (i = IR_UNUSED + 1, insn = ctx->ir_base + i; i < ctx->insns_count;) { flags = ir_op_flags[insn->op]; + + if ((save_flags & IR_SAVE_CFG) + && ctx->cfg_map + && ctx->cfg_map[i] + && ctx->cfg_blocks[ctx->cfg_map[i]].start == i) { + uint32_t b = ctx->cfg_map[i]; + ir_block *bb = &ctx->cfg_blocks[b]; + fprintf(f, "#BB%d: end=l_%d", b, bb->end); + if (bb->flags && IR_BB_UNREACHABLE) { + fprintf(f, ", U"); + } + if (bb->dom_parent > 0) { + fprintf(f, ", idom=BB%d(%d)", bb->dom_parent, bb->dom_depth); + } + if (bb->loop_depth != 0) { + if (bb->flags & IR_BB_LOOP_HEADER) { + if (bb->loop_header > 0) { + fprintf(f, ", loop=HDR,BB%d(%d)", bb->loop_header, bb->loop_depth); + } else { + IR_ASSERT(bb->loop_depth == 1); + fprintf(f, ", loop=HDR(%d)", bb->loop_depth); + } + } else { + IR_ASSERT(bb->loop_header > 0); + fprintf(f, ", loop=BB%d(%d)", bb->loop_header, bb->loop_depth); + } + } + if (bb->predecessors_count) { + uint32_t i; + + fprintf(f, ", pred(%d)=[BB%d", bb->predecessors_count, ctx->cfg_edges[bb->predecessors]); + for (i = 1; i < bb->predecessors_count; i++) { + fprintf(f, ", BB%d", ctx->cfg_edges[bb->predecessors + i]); + } + fprintf(f, "]"); + } + if (bb->successors_count) { + uint32_t i; + + fprintf(f, ", succ(%d)=[BB%d", bb->successors_count, ctx->cfg_edges[bb->successors]); + for (i = 1; i < bb->successors_count; i++) { + fprintf(f, ", BB%d", ctx->cfg_edges[bb->successors + i]); + } + fprintf(f, "]"); + } + fprintf(f, "\n"); + } + if (flags & IR_OP_FLAG_CONTROL) { if (!(flags & IR_OP_FLAG_MEM) || insn->type == IR_VOID) { fprintf(f, "\tl_%d = ", i); } else { - fprintf(f, "\t%s d_%d, l_%d = ", ir_type_cname[insn->type], i, i); + fprintf(f, "\t%s d_%d", ir_type_cname[insn->type], i); + if (save_flags & IR_SAVE_REGS) { + if (ctx->vregs && ctx->vregs[i]) { + fprintf(f, " {R%d}", ctx->vregs[i]); + } + if (ctx->regs) { + int8_t reg = ctx->regs[i][0]; + if (reg != IR_REG_NONE) { + fprintf(f, " {%%%s%s}", ir_reg_name(IR_REG_NUM(reg), insn->type), + (reg & (IR_REG_SPILL_STORE|IR_REG_SPILL_SPECIAL)) ? ":store" : ""); + } + } + } + fprintf(f, ", l_%d = ", i); } } else { fprintf(f, "\t"); if (flags & IR_OP_FLAG_DATA) { - fprintf(f, "%s d_%d = ", ir_type_cname[insn->type], i); + fprintf(f, "%s d_%d", ir_type_cname[insn->type], i); + if (save_flags & IR_SAVE_REGS) { + if (ctx->vregs && ctx->vregs[i]) { + fprintf(f, " {R%d}", ctx->vregs[i]); + } + if (ctx->regs) { + int8_t reg = ctx->regs[i][0]; + if (reg != IR_REG_NONE) { + fprintf(f, " {%%%s%s}", ir_reg_name(IR_REG_NUM(reg), insn->type), + (reg & (IR_REG_SPILL_STORE|IR_REG_SPILL_SPECIAL)) ? ":store" : ""); + } + } + } + fprintf(f, " = "); } } fprintf(f, "%s", ir_op_name[insn->op]); @@ -101,6 +223,19 @@ void ir_save(const ir_ctx *ctx, FILE *f) } else { fprintf(f, "%sd_%d", first ? "(" : ", ", ref); } + if (save_flags & IR_SAVE_REGS) { + if (ctx->vregs && ref > 0 && ctx->vregs[ref]) { + fprintf(f, " {R%d}", ctx->vregs[ref]); + } + if (ctx->regs) { + int8_t *regs = ctx->regs[i]; + int8_t reg = regs[j]; + if (reg != IR_REG_NONE) { + fprintf(f, " {%%%s%s}", ir_reg_name(IR_REG_NUM(reg), ctx->ir_base[ref].type), + (reg & (IR_REG_SPILL_LOAD|IR_REG_SPILL_SPECIAL)) ? ":load" : ""); + } + } + } first = 0; break; case IR_OPND_CONTROL: @@ -141,14 +276,83 @@ void ir_save(const ir_ctx *ctx, FILE *f) } else { fprintf(f, ");"); } + first = 1; if (((flags & IR_OP_FLAG_DATA) || ((flags & IR_OP_FLAG_MEM) && insn->type != IR_VOID)) && ctx->binding) { ir_ref var = ir_binding_find(ctx, i); if (var) { IR_ASSERT(var < 0); fprintf(f, " # BIND(0x%x);", -var); + first = 0; + } + } + + if ((save_flags & IR_SAVE_CFG_MAP) + && ctx->cfg_map + && ctx->cfg_map[i]) { + if (first) { + fprintf(f, " #"); + first = 0; } + fprintf(f, " BLOCK=BB%d;", ctx->cfg_map[i]); + } + + if ((save_flags & IR_SAVE_RULES) + && ctx->rules) { + uint32_t rule = ctx->rules[i]; + uint32_t id = rule & IR_RULE_MASK; + + if (first) { + fprintf(f, " #"); + first = 0; + } + if (id < IR_LAST_OP) { + fprintf(f, " RULE(%s", ir_op_name[id]); + } else { + IR_ASSERT(id > IR_LAST_OP /*&& id < IR_LAST_RULE*/); + fprintf(f, " RULE(%s", ir_rule_name[id - IR_LAST_OP]); + } + if (rule & IR_FUSED) { + fprintf(f, ":FUSED"); + } + if (rule & IR_SKIPPED) { + fprintf(f, ":SKIPPED"); + } + if (rule & IR_SIMPLE) { + fprintf(f, ":SIMPLE"); + } + fprintf(f, ");"); + } + + if ((save_flags & IR_SAVE_USE_LISTS) + && ctx->use_lists + && ctx->use_lists[i].count) { + ir_use_list *use_list = &ctx->use_lists[i]; + ir_ref n = use_list->count; + ir_ref *p = ctx->use_edges + use_list->refs; + + if (first) { + fprintf(f, " #"); + first = 0; + } + fprintf(f, " USE_LIST(%d)=[%05d", n, *p); + for (p++, n--; n; p++, n--) { + fprintf(f, ", %05d", *p); + } + fprintf(f, "];"); } fprintf(f, "\n"); + + if ((save_flags & (IR_SAVE_CFG|IR_SAVE_REGS)) == (IR_SAVE_CFG|IR_SAVE_REGS) + && ctx->cfg_map + && ctx->cfg_map[i] + && ctx->cfg_blocks[ctx->cfg_map[i]].end == i) { + uint32_t b = ctx->cfg_map[i]; + ir_block *bb = &ctx->cfg_blocks[b]; + if (bb->flags & IR_BB_DESSA_MOVES) { + ir_save_dessa_moves(ctx, b, bb, f); + } + } + n = ir_insn_inputs_to_len(n); i += n; insn += n;