mirror of
https://github.com/danog/ir.git
synced 2024-12-02 09:38:29 +01:00
Allow printing IR annotated with register-allocation, spill-code-placement, de-SSA and code-generation information
This commit is contained in:
parent
25656607ba
commit
4124ef5150
1
ir.h
1
ir.h
@ -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;
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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] == '-') {
|
||||
|
@ -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
110
ir_save.c
@ -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;
|
||||
|
@ -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] == '-') {
|
||||
|
154
ir_x86.dasc
154
ir_x86.dasc
@ -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)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user