Allow printing IR annotated with register-allocation, spill-code-placement, de-SSA and code-generation information

This commit is contained in:
Dmitry Stogov 2023-06-21 13:28:15 +03:00
parent 25656607ba
commit 4124ef5150
7 changed files with 250 additions and 101 deletions

1
ir.h
View File

@ -505,6 +505,7 @@ void ir_strtab_free(ir_strtab *strtab);
# define IR_DEBUG_GCM (1<<28)
# define IR_DEBUG_SCHEDULE (1<<29)
# define IR_DEBUG_RA (1<<30)
# define IR_DEBUG_CODEGEN (1<<31)
#endif
typedef struct _ir_ctx ir_ctx;

View File

@ -217,38 +217,54 @@ const char *ir_reg_name(int8_t reg, ir_type type)
}
}
#define IR_RULES(_) \
_(CMP_INT) \
_(CMP_FP) \
_(MUL_PWR2) \
_(DIV_PWR2) \
_(MOD_PWR2) \
_(OP_INT) \
_(OP_FP) \
_(BINOP_INT) \
_(BINOP_FP) \
_(SHIFT) \
_(SHIFT_CONST) \
_(COPY_INT) \
_(COPY_FP) \
_(CMP_AND_BRANCH_INT) \
_(CMP_AND_BRANCH_FP) \
_(GUARD_CMP_INT) \
_(GUARD_CMP_FP) \
_(GUARD_OVERFLOW) \
_(OVERFLOW_AND_BRANCH) \
_(MIN_MAX_INT) \
_(REG_BINOP_INT) \
_(LOAD_INT) \
_(LOAD_FP) \
_(STORE_INT) \
_(STORE_FP) \
_(IF_INT) \
_(RETURN_VOID) \
_(RETURN_INT) \
_(RETURN_FP) \
#define IR_RULE_ENUM(name) IR_ ## name,
enum _ir_rule {
IR_CMP_INT = IR_LAST_OP,
IR_CMP_FP,
IR_MUL_PWR2,
IR_DIV_PWR2,
IR_MOD_PWR2,
IR_OP_INT,
IR_OP_FP,
IR_BINOP_INT,
IR_BINOP_FP,
IR_SHIFT,
IR_SHIFT_CONST,
IR_COPY_INT,
IR_COPY_FP,
IR_CMP_AND_BRANCH_INT,
IR_CMP_AND_BRANCH_FP,
IR_GUARD_CMP_INT,
IR_GUARD_CMP_FP,
IR_GUARD_OVERFLOW,
IR_OVERFLOW_AND_BRANCH,
IR_MIN_MAX_INT,
IR_REG_BINOP_INT,
IR_LOAD_INT,
IR_LOAD_FP,
IR_STORE_INT,
IR_STORE_FP,
IR_IF_INT,
IR_RETURN_VOID,
IR_RETURN_INT,
IR_RETURN_FP,
IR_FIRST_RULE = IR_LAST_OP,
IR_RULES(IR_RULE_ENUM)
IR_LAST_RULE
};
#ifdef IR_DEBUG
#define IR_RULE_NAME(name) #name,
const char *ir_rule_name[IR_LAST_OP] = {
NULL,
IR_RULES(IR_RULE_NAME)
NULL
};
#endif
/* register allocation */
int ir_get_target_constraints(const ir_ctx *ctx, ir_ref ref, ir_target_constraints *constraints)
{

View File

@ -332,6 +332,8 @@ int main(int argc, char **argv)
flags |= IR_DEBUG_SCHEDULE;
} else if (strcmp(argv[i], "--debug-ra") == 0) {
flags |= IR_DEBUG_RA;
} else if (strcmp(argv[i], "--debug-codegen") == 0) {
flags |= IR_DEBUG_CODEGEN;
#endif
} else if (strcmp(argv[i], "--debug-regset") == 0) {
if (i + 1 == argc || argv[i + 1][0] == '-') {

View File

@ -1123,6 +1123,8 @@ IR_ALWAYS_INLINE ir_reg ir_regset_pop_first(ir_regset *set)
} \
} while (0)
#endif /* defined(IR_REGSET_64BIT) */
/*** IR Register Allocation ***/
/* Flags for ctx->regs[][] (low bits are used for register number itself) */
typedef struct _ir_reg_alloc_data {
@ -1162,6 +1164,10 @@ IR_ALWAYS_INLINE int8_t ir_get_alocated_reg(const ir_ctx *ctx, ir_ref ref, int o
#define IR_RULE_MASK 0xff
#ifdef IR_DEBUG
extern const char *ir_rule_name[];
#endif
typedef struct _ir_target_constraints ir_target_constraints;
#define IR_TMP_REG(_num, _type, _start, _end) \
@ -1171,8 +1177,6 @@ typedef struct _ir_target_constraints ir_target_constraints;
int ir_get_target_constraints(const ir_ctx *ctx, ir_ref ref, ir_target_constraints *constraints);
#endif /* defined(IR_REGSET_64BIT) */
//#define IR_BITSET_LIVENESS
#endif /* IR_PRIVATE_H */

110
ir_save.c
View File

@ -14,6 +14,9 @@ void ir_save(const ir_ctx *ctx, FILE *f)
ir_insn *insn;
uint32_t flags;
bool first;
#ifdef IR_DEBUG
bool verbose = (ctx->flags & IR_DEBUG_CODEGEN);
#endif
fprintf(f, "{\n");
for (i = IR_UNUSED + 1, insn = ctx->ir_base - i; i < ctx->consts_count; i++, insn--) {
@ -40,6 +43,11 @@ 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 (flags & IR_OP_FLAG_CONTROL) {
#ifdef IR_DEBUG
if (verbose && ctx->cfg_map && (flags & IR_OP_FLAG_BB_START)) {
fprintf(f, "#BB%d:\n", ctx->cfg_map[i]);
}
#endif
if (!(flags & IR_OP_FLAG_MEM) || insn->type == IR_VOID) {
fprintf(f, "\tl_%d = ", i);
} else {
@ -48,7 +56,20 @@ void ir_save(const ir_ctx *ctx, FILE *f)
} 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);
#ifdef IR_DEBUG
if (verbose && ctx->vregs && ctx->vregs[i]) {
fprintf(f, " {R%d}", ctx->vregs[i]);
}
if (verbose && 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), ctx->ir_base[ref].type),
(reg & (IR_REG_SPILL_STORE|IR_REG_SPILL_SPECIAL)) ? ":store" : "");
}
}
#endif
fprintf(f, " = ");
}
}
fprintf(f, "%s", ir_op_name[insn->op]);
@ -75,6 +96,18 @@ void ir_save(const ir_ctx *ctx, FILE *f)
} else {
fprintf(f, "%sd_%d", first ? "(" : ", ", ref);
}
#ifdef IR_DEBUG
if (verbose && ctx->vregs && ref > 0 && ctx->vregs[ref]) {
fprintf(f, " {R%d}", ctx->vregs[ref]);
}
if (verbose && ctx->regs) {
int8_t reg = ctx->regs[i][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" : "");
}
}
#endif
first = 0;
break;
case IR_OPND_CONTROL:
@ -117,7 +150,82 @@ void ir_save(const ir_ctx *ctx, FILE *f)
fprintf(f, " # BIND(0x%x);", -var);
}
}
#ifdef IR_DEBUG
if (verbose && ctx->rules) {
uint32_t rule = ctx->rules[i];
uint32_t id = rule & ~(IR_FUSED|IR_SKIPPED|IR_SIMPLE);
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, ")");
}
#endif
fprintf(f, "\n");
#ifdef IR_DEBUG
if (verbose && ctx->cfg_map && (flags & IR_OP_FLAG_BB_END)) {
uint32_t b = ctx->cfg_map[i];
ir_block *bb = &ctx->cfg_blocks[b];
if (bb->flags & IR_BB_DESSA_MOVES) {
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 reg = ctx->regs[use_ref][k];
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" : "");
}
}
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[ref].type),
(reg & (IR_REG_SPILL_STORE|IR_REG_SPILL_SPECIAL)) ? ":store" : "");
}
}
fprintf(f, "\n");
}
}
}
}
#endif
n = ir_insn_inputs_to_len(n);
i += n;
insn += n;

View File

@ -127,6 +127,8 @@ int main(int argc, char **argv)
flags |= IR_DEBUG_SCHEDULE;
} else if (strcmp(argv[i], "--debug-ra") == 0) {
flags |= IR_DEBUG_RA;
} else if (strcmp(argv[i], "--debug-codegen") == 0) {
flags |= IR_DEBUG_CODEGEN;
#endif
} else if (strcmp(argv[i], "--debug-regset") == 0) {
if (i + 1 == argc || argv[i + 1][0] == '-') {

View File

@ -441,78 +441,94 @@ const char *ir_reg_name(int8_t reg, ir_type type)
return NULL;
}
#define IR_RULES(_) \
_(CMP_INT) \
_(CMP_FP) \
_(MUL_INT) \
_(DIV_INT) \
_(MOD_INT) \
_(TEST_INT) \
_(SETCC_INT) \
_(TESTCC_INT) \
_(LEA_OB) \
_(LEA_SI) \
_(LEA_SIB) \
_(LEA_IB) \
_(LEA_SI_O) \
_(LEA_SIB_O) \
_(LEA_IB_O) \
_(LEA_I_OB) \
_(LEA_OB_I) \
_(LEA_OB_SI) \
_(LEA_SI_OB) \
_(LEA_B_SI) \
_(LEA_SI_B) \
_(INC) \
_(DEC) \
_(MUL_PWR2) \
_(DIV_PWR2) \
_(MOD_PWR2) \
_(BOOL_NOT_INT) \
_(ABS_INT) \
_(OP_INT) \
_(OP_FP) \
_(IMUL3) \
_(BINOP_INT) \
_(BINOP_SSE2) \
_(BINOP_AVX) \
_(SHIFT) \
_(SHIFT_CONST) \
_(COPY_INT) \
_(COPY_FP) \
_(CMP_AND_BRANCH_INT) \
_(CMP_AND_BRANCH_FP) \
_(TEST_AND_BRANCH_INT) \
_(JCC_INT) \
_(GUARD_CMP_INT) \
_(GUARD_CMP_FP) \
_(GUARD_TEST_INT) \
_(GUARD_JCC_INT) \
_(GUARD_OVERFLOW) \
_(OVERFLOW_AND_BRANCH) \
_(MIN_MAX_INT) \
_(MEM_OP_INT) \
_(MEM_INC) \
_(MEM_DEC) \
_(MEM_MUL_PWR2) \
_(MEM_DIV_PWR2) \
_(MEM_MOD_PWR2) \
_(MEM_BINOP_INT) \
_(MEM_SHIFT) \
_(MEM_SHIFT_CONST) \
_(REG_BINOP_INT) \
_(VSTORE_INT) \
_(VSTORE_FP) \
_(LOAD_INT) \
_(LOAD_FP) \
_(STORE_INT) \
_(STORE_FP) \
_(IF_INT) \
_(RETURN_VOID) \
_(RETURN_INT) \
_(RETURN_FP) \
#define IR_RULE_ENUM(name) IR_ ## name,
enum _ir_rule {
IR_CMP_INT = IR_LAST_OP,
IR_CMP_FP,
IR_MUL_INT,
IR_DIV_INT,
IR_MOD_INT,
IR_TEST_INT,
IR_SETCC_INT,
IR_TESTCC_INT,
IR_LEA_OB,
IR_LEA_SI,
IR_LEA_SIB,
IR_LEA_IB,
IR_LEA_SI_O,
IR_LEA_SIB_O,
IR_LEA_IB_O,
IR_LEA_I_OB,
IR_LEA_OB_I,
IR_LEA_OB_SI,
IR_LEA_SI_OB,
IR_LEA_B_SI,
IR_LEA_SI_B,
IR_INC,
IR_DEC,
IR_MUL_PWR2,
IR_DIV_PWR2,
IR_MOD_PWR2,
IR_BOOL_NOT_INT,
IR_ABS_INT,
IR_OP_INT,
IR_OP_FP,
IR_IMUL3,
IR_BINOP_INT,
IR_BINOP_SSE2,
IR_BINOP_AVX,
IR_SHIFT,
IR_SHIFT_CONST,
IR_COPY_INT,
IR_COPY_FP,
IR_CMP_AND_BRANCH_INT,
IR_CMP_AND_BRANCH_FP,
IR_TEST_AND_BRANCH_INT,
IR_JCC_INT,
IR_GUARD_CMP_INT,
IR_GUARD_CMP_FP,
IR_GUARD_TEST_INT,
IR_GUARD_JCC_INT,
IR_GUARD_OVERFLOW,
IR_OVERFLOW_AND_BRANCH,
IR_MIN_MAX_INT,
IR_MEM_OP_INT,
IR_MEM_INC,
IR_MEM_DEC,
IR_MEM_MUL_PWR2,
IR_MEM_DIV_PWR2,
IR_MEM_MOD_PWR2,
IR_MEM_BINOP_INT,
IR_MEM_SHIFT,
IR_MEM_SHIFT_CONST,
IR_REG_BINOP_INT,
IR_VSTORE_INT,
IR_VSTORE_FP,
IR_LOAD_INT,
IR_LOAD_FP,
IR_STORE_INT,
IR_STORE_FP,
IR_IF_INT,
IR_RETURN_VOID,
IR_RETURN_INT,
IR_RETURN_FP,
IR_FIRST_RULE = IR_LAST_OP,
IR_RULES(IR_RULE_ENUM)
IR_LAST_RULE
};
#ifdef IR_DEBUG
#define IR_RULE_NAME(name) #name,
const char *ir_rule_name[IR_LAST_OP] = {
NULL,
IR_RULES(IR_RULE_NAME)
NULL
};
#endif
/* register allocation */
int ir_get_target_constraints(const ir_ctx *ctx, ir_ref ref, ir_target_constraints *constraints)
{