Merge ir_uses_fixed_reg() into ir_get_def_flags() and ir_get_use_flags()

This commit is contained in:
Dmitry Stogov 2022-08-12 21:17:19 +03:00
parent b607a28b2a
commit b0cba142a9
4 changed files with 89 additions and 120 deletions

View File

@ -381,38 +381,6 @@ static ir_reg ir_get_arg_reg(ir_ctx *ctx, ir_insn *insn, int op_num)
return IR_REG_NONE;
}
ir_reg ir_uses_fixed_reg(ir_ctx *ctx, ir_ref ref, int op_num)
{
ir_ref rule;
rule = ctx->rules[ref];
if (rule == IR_RETURN_INT) {
if (op_num == 2) {
return IR_REG_INT_RET1;
}
} else if (rule == IR_RETURN_FP) {
if (op_num == 2) {
return IR_REG_FP_RET1;
}
} else if (rule == IR_SKIP_REG) {
if (ctx->ir_base[ref].op == IR_PARAM && op_num == 0) {
return ir_get_param_reg(ctx, ref);
}
} else if (rule == IR_CALL || (rule == IR_TAILCALL && op_num > 0)) {
ir_insn *insn = &ctx->ir_base[ref];
if (op_num == 0) {
if (IR_IS_TYPE_INT(insn->type)) {
return IR_REG_INT_RET1;
} else {
return IR_REG_FP_RET1;
}
} else {
return ir_get_arg_reg(ctx, insn, op_num);
}
}
return IR_REG_NONE;
}
static bool ir_call_needs_tmp_int_reg(ir_ctx *ctx, ir_ref ref)
{
ir_insn *insn = &ctx->ir_base[ref];
@ -442,34 +410,42 @@ static bool ir_call_needs_tmp_int_reg(ir_ctx *ctx, ir_ref ref)
return 0;
}
uint8_t ir_get_def_flags(ir_ctx *ctx, ir_ref ref)
uint8_t ir_get_def_flags(ir_ctx *ctx, ir_ref ref, ir_reg *reg)
{
ir_ref rule = ctx->rules[ref];
ir_insn *insn;
*reg = IR_REG_NONE;
switch (rule) {
case IR_SKIP_REG: /* PARAM PHI PI */
insn = &ctx->ir_base[ref];
if (insn->op == IR_PARAM) {
if (ir_get_param_reg(ctx, ref) == IR_REG_NONE) {
*reg = ir_get_param_reg(ctx, ref);
if (*reg == IR_REG_NONE) {
return IR_USE_MUST_BE_IN_REG;
}
}
return IR_USE_SHOULD_BE_IN_REG;
case IR_CALL:
insn = &ctx->ir_base[ref];
*reg = (IR_IS_TYPE_INT(insn->type)) ? IR_REG_INT_RET1 : IR_REG_FP_RET1;
break;
}
return IR_USE_MUST_BE_IN_REG;
}
uint8_t ir_get_use_flags(ir_ctx *ctx, ir_ref ref, int op_num)
uint8_t ir_get_use_flags(ir_ctx *ctx, ir_ref ref, int op_num, ir_reg *reg)
{
ir_ref rule = ctx->rules[ref];
IR_ASSERT(op_num > 0);
*reg = IR_REG_NONE;
switch (rule) {
case IR_CALL:
case IR_TAILCALL:
if (op_num > 2) {
*reg = ir_get_arg_reg(ctx, &ctx->ir_base[ref], op_num);
return IR_USE_SHOULD_BE_IN_REG;
}
return IR_USE_MUST_BE_IN_REG;
@ -477,11 +453,17 @@ uint8_t ir_get_use_flags(ir_ctx *ctx, ir_ref ref, int op_num)
case IR_ZEXT:
case IR_TRUNC:
case IR_BITCAST:
case IR_RETURN_INT:
case IR_RETURN_FP:
case IR_RSTORE:
case IR_SKIP_REG: /* PARAM PHI PI */
return IR_USE_SHOULD_BE_IN_REG;
case IR_RETURN_INT:
IR_ASSERT(op_num == 2);
*reg = IR_REG_INT_RET1;
return IR_USE_SHOULD_BE_IN_REG;
case IR_RETURN_FP:
IR_ASSERT(op_num == 2);
*reg = IR_REG_FP_RET1;
return IR_USE_SHOULD_BE_IN_REG;
}
return IR_USE_MUST_BE_IN_REG;
@ -4529,6 +4511,7 @@ static void ir_allocate_unique_spill_slots(ir_ctx *ctx)
ir_regset available = 0;
ir_tmp_reg tmp_regs[4];
uint8_t def_flags;
ir_reg reg;
ctx->regs = ir_mem_malloc(sizeof(ir_regs) * ctx->insns_count);
memset(ctx->regs, IR_REG_NONE, sizeof(ir_regs) * ctx->insns_count);
@ -4564,7 +4547,7 @@ static void ir_allocate_unique_spill_slots(ir_ctx *ctx)
case IR_SKIP:
case IR_SKIP_REG: /* PARAM PHI PI */
/* skip */
def_flags = ir_get_def_flags(ctx, i);
def_flags = ir_get_def_flags(ctx, i, &reg);
if (ctx->rules
&& *rule != IR_CMP_AND_BRANCH_INT
&& *rule != IR_CMP_AND_BRANCH_FP
@ -4573,8 +4556,6 @@ static void ir_allocate_unique_spill_slots(ir_ctx *ctx)
available = IR_REGSET_SCRATCH;
}
if (ctx->vregs[i]) {
ir_reg reg = ir_uses_fixed_reg(ctx, i, 0);
if (reg != IR_REG_NONE && IR_REGSET_IN(available, reg)) {
IR_REGSET_EXCL(available, reg);
ctx->regs[i][0] = reg | IR_REG_SPILL_STORE;
@ -4661,14 +4642,15 @@ static void ir_allocate_unique_spill_slots(ir_ctx *ctx)
ir_reg reg = ctx->regs[i][0] & ~IR_REG_SPILL_STORE;
ctx->regs[i][1] = reg | IR_REG_SPILL_LOAD;
} else {
ir_reg reg = ir_uses_fixed_reg(ctx, i, j);
ir_reg reg;
uint8_t use_flags = ir_get_use_flags(ctx, i, j, &reg);
if (reg != IR_REG_NONE && IR_REGSET_IN(available, reg)) {
IR_REGSET_EXCL(available, reg);
ctx->regs[i][j] = reg | IR_REG_SPILL_LOAD;
} else if (j > 1 && input == insn->op1 && ctx->regs[i][1] != IR_REG_NONE) {
ctx->regs[i][j] = ctx->regs[i][1];
} else if (ir_get_use_flags(ctx, i, j) & IR_USE_MUST_BE_IN_REG) {
} else if (use_flags & IR_USE_MUST_BE_IN_REG) {
reg = ir_get_free_reg(ctx->ir_base[input].type, available);
IR_REGSET_EXCL(available, reg);
ctx->regs[i][j] = reg | IR_REG_SPILL_LOAD;

View File

@ -209,7 +209,7 @@ IR_ALWAYS_INLINE int ir_nlzl(uint64_t num)
# define IR_BITSET_BITS 32
# define IR_BITSET_ONE 1U
# define ir_bitset_base_t uint32_t
# define IR_bitset_ntz ir_ntz
# define ir_bitset_ntz ir_ntz
#else
# define IR_BITSET_BITS 64
# define IR_BITSET_ONE 1UL
@ -927,9 +927,8 @@ bool ir_needs_vreg(ir_ctx *ctx, ir_ref ref);
/* Registers modified by the given instruction */
ir_regset ir_get_scratch_regset(ir_ctx *ctx, ir_ref ref, ir_live_pos *start, ir_live_pos *end);
ir_reg ir_uses_fixed_reg(ir_ctx *ctx, ir_ref ref, int op_num);
uint8_t ir_get_def_flags(ir_ctx *ctx, ir_ref ref);
uint8_t ir_get_use_flags(ir_ctx *ctx, ir_ref ref, int op_num);
uint8_t ir_get_def_flags(ir_ctx *ctx, ir_ref ref, ir_reg *reg);
uint8_t ir_get_use_flags(ir_ctx *ctx, ir_ref ref, int op_num, ir_reg *reg);
int ir_get_temporary_regs(ir_ctx *ctx, ir_ref ref, ir_tmp_reg *tmp_regs);
#endif /* defined(IR_REGSET_64BIT) */

View File

@ -434,8 +434,7 @@ int ir_compute_live_ranges(ir_ctx *ctx)
ir_ref hint_ref = 0;
if (ctx->rules) {
def_flags = ir_get_def_flags(ctx, i);
reg = ir_uses_fixed_reg(ctx, i, 0);
def_flags = ir_get_def_flags(ctx, i, &reg);
} else {
reg = IR_REG_NONE;
}
@ -490,8 +489,7 @@ int ir_compute_live_ranges(ir_ctx *ctx)
uint8_t use_flags;
if (ctx->rules) {
use_flags = ir_get_use_flags(ctx, i, j);
reg = ir_uses_fixed_reg(ctx, i, j);
use_flags = ir_get_use_flags(ctx, i, j, &reg);
} else {
use_flags = 0;
reg = IR_REG_NONE;
@ -929,6 +927,7 @@ int ir_coalesce(ir_ctx *ctx)
ir_worklist blocks;
bool compact = 0;
ir_live_range *unused = NULL;
ir_reg reg;
/* Collect a list of blocks which are predecossors to block with phi finctions */
ir_worklist_init(&blocks, ctx->cfg_blocks_count + 1);
@ -999,7 +998,7 @@ int ir_coalesce(ir_ctx *ctx)
/* try to swap operands of commutative instructions for better register allocation */
for (b = 1, bb = &ctx->cfg_blocks[1]; b <= ctx->cfg_blocks_count; b++, bb++) {
for (i = bb->start, insn = ctx->ir_base + i; i <= bb->end;) {
if (ir_get_def_flags(ctx, i) & IR_DEF_REUSES_OP1_REG) {
if (ir_get_def_flags(ctx, i, &reg) & IR_DEF_REUSES_OP1_REG) {
if (insn->op2 > 0 && insn->op1 != insn->op2
&& (ir_op_flags[insn->op] & IR_OP_FLAG_COMMUTATIVE)) {
ir_try_swap_operands(ctx, i, insn);

View File

@ -769,56 +769,6 @@ static ir_reg ir_get_arg_reg(ir_ctx *ctx, ir_insn *insn, int op_num)
return IR_REG_NONE;
}
ir_reg ir_uses_fixed_reg(ir_ctx *ctx, ir_ref ref, int op_num)
{
ir_ref rule;
rule = ctx->rules[ref];
if (rule == IR_SHIFT || rule == IR_SKIP_SHIFT) {
if (op_num == 2) {
return IR_REG_RCX;
}
} else if (rule == IR_MUL_INT || rule == IR_DIV_INT) {
if (op_num == 0 || op_num == 1) {
return IR_REG_RAX;
}
} else if (rule == IR_MOD_INT) {
if (op_num == 0) {
return IR_REG_RDX;
} else if (op_num == 1) {
return IR_REG_RAX;
}
} else if (rule == IR_RETURN_INT) {
if (op_num == 2) {
return IR_REG_INT_RET1;
}
#ifdef IR_REG_FP_RET1
} else if (rule == IR_RETURN_FP) {
if (op_num == 2) {
return IR_REG_FP_RET1;
}
#endif
} else if (rule == IR_SKIP_REG) {
if (ctx->ir_base[ref].op == IR_PARAM && op_num == 0) {
return ir_get_param_reg(ctx, ref);
}
} else if (rule == IR_CALL || (rule == IR_TAILCALL && op_num > 0)) {
ir_insn *insn = &ctx->ir_base[ref];
if (op_num == 0) {
if (IR_IS_TYPE_INT(insn->type)) {
return IR_REG_INT_RET1;
#ifdef IR_REG_FP_RET1
} else {
return IR_REG_FP_RET1;
#endif
}
} else {
return ir_get_arg_reg(ctx, insn, op_num);
}
}
return IR_REG_NONE;
}
static bool ir_call_needs_tmp_int_reg(ir_ctx *ctx, ir_ref ref)
{
ir_insn *insn = &ctx->ir_base[ref];
@ -862,18 +812,17 @@ static bool ir_call_needs_tmp_int_reg(ir_ctx *ctx, ir_ref ref)
return 0;
}
uint8_t ir_get_def_flags(ir_ctx *ctx, ir_ref ref)
uint8_t ir_get_def_flags(ir_ctx *ctx, ir_ref ref, ir_reg *reg)
{
ir_ref rule = ctx->rules[ref];
ir_insn *insn;
*reg = IR_REG_NONE;
switch (rule) {
case IR_BINOP_INT:
case IR_BINOP_SSE2:
case IR_SHIFT:
case IR_SHIFT_CONST:
case IR_MUL_INT:
case IR_DIV_INT:
case IR_COPY_INT:
case IR_COPY_FP:
case IR_INC:
@ -890,29 +839,42 @@ uint8_t ir_get_def_flags(ir_ctx *ctx, ir_ref ref)
case IR_SKIP_REG: /* PARAM PHI PI */
insn = &ctx->ir_base[ref];
if (insn->op == IR_PARAM) {
if (ir_get_param_reg(ctx, ref) == IR_REG_NONE) {
*reg = ir_get_param_reg(ctx, ref);
if (*reg == IR_REG_NONE) {
return IR_USE_MUST_BE_IN_REG;
}
}
return IR_USE_SHOULD_BE_IN_REG;
case IR_MUL_INT:
case IR_DIV_INT:
*reg = IR_REG_RAX;
return IR_DEF_REUSES_OP1_REG | IR_USE_MUST_BE_IN_REG;
case IR_MOD_INT :
*reg = IR_REG_RDX;
break;
case IR_CALL:
insn = &ctx->ir_base[ref];
if (IR_IS_TYPE_INT(insn->type)) {
*reg = IR_REG_INT_RET1;
#ifdef IR_REG_FP_RET1
} else {
*reg = IR_REG_FP_RET1;
#endif
}
break;
}
return IR_USE_MUST_BE_IN_REG;
}
uint8_t ir_get_use_flags(ir_ctx *ctx, ir_ref ref, int op_num)
uint8_t ir_get_use_flags(ir_ctx *ctx, ir_ref ref, int op_num, ir_reg *reg)
{
ir_ref rule = ctx->rules[ref];
ir_insn *insn;
IR_ASSERT(op_num > 0);
*reg = IR_REG_NONE;
switch (rule) {
case IR_MUL_INT:
case IR_DIV_INT:
case IR_MOD_INT:
if (op_num == 1) {
return IR_USE_SHOULD_BE_IN_REG;
}
case IR_BINOP_INT:
case IR_SKIP_BINOP_INT:
case IR_BINOP_SSE2:
@ -941,11 +903,11 @@ uint8_t ir_get_use_flags(ir_ctx *ctx, ir_ref ref, int op_num)
case IR_CALL:
case IR_TAILCALL:
if (op_num > 2) {
insn = &ctx->ir_base[ref];
*reg = ir_get_arg_reg(ctx, insn, op_num);
return IR_USE_SHOULD_BE_IN_REG;
}
return IR_USE_SHOULD_BE_IN_REG;
case IR_RETURN_INT:
case IR_RETURN_FP:
case IR_IJMP:
case IR_RSTORE:
case IR_SKIP_REG: /* PARAM PHI PI */
@ -981,8 +943,35 @@ uint8_t ir_get_use_flags(ir_ctx *ctx, ir_ref ref, int op_num)
break;
}
break;
}
case IR_SHIFT:
case IR_SKIP_SHIFT:
if (op_num == 2) {
*reg = IR_REG_RCX;
}
break;
case IR_MUL_INT:
case IR_DIV_INT:
if (op_num == 1) {
*reg = IR_REG_RAX;
}
return IR_USE_SHOULD_BE_IN_REG;
case IR_MOD_INT:
if (op_num == 1) {
*reg = IR_REG_RAX;
}
return IR_USE_SHOULD_BE_IN_REG;
case IR_RETURN_INT:
IR_ASSERT(op_num == 2);
*reg = IR_REG_INT_RET1;
return IR_USE_SHOULD_BE_IN_REG;
case IR_RETURN_FP:
#ifdef IR_REG_FP_RET1
IR_ASSERT(op_num == 2);
*reg = IR_REG_FP_RET1;
#endif
return IR_USE_SHOULD_BE_IN_REG;
}
return IR_USE_MUST_BE_IN_REG;
}
@ -6502,6 +6491,7 @@ static void ir_allocate_unique_spill_slots(ir_ctx *ctx)
ir_regset available = 0;
ir_tmp_reg tmp_regs[4];
uint8_t def_flags;
ir_reg reg;
#ifndef IR_REG_FP_RET1
ir_type ret_type = ir_get_return_type(ctx);
@ -6551,7 +6541,7 @@ static void ir_allocate_unique_spill_slots(ir_ctx *ctx)
case IR_SKIP_MEM:
case IR_SKIP_REG: /* PARAM PHI PI */
/* skip */
def_flags = ir_get_def_flags(ctx, i);
def_flags = ir_get_def_flags(ctx, i, &reg);
if (ctx->rules
&& *rule != IR_CMP_AND_BRANCH_INT
&& *rule != IR_CMP_AND_BRANCH_FP
@ -6560,8 +6550,6 @@ static void ir_allocate_unique_spill_slots(ir_ctx *ctx)
available = IR_REGSET_SCRATCH;
}
if (ctx->vregs[i]) {
ir_reg reg = ir_uses_fixed_reg(ctx, i, 0);
if (reg != IR_REG_NONE && IR_REGSET_IN(available, reg)) {
IR_REGSET_EXCL(available, reg);
ctx->regs[i][0] = reg | IR_REG_SPILL_STORE;
@ -6648,14 +6636,15 @@ static void ir_allocate_unique_spill_slots(ir_ctx *ctx)
ir_reg reg = ctx->regs[i][0] & ~IR_REG_SPILL_STORE;
ctx->regs[i][1] = reg | IR_REG_SPILL_LOAD;
} else {
ir_reg reg = ir_uses_fixed_reg(ctx, i, j);
ir_reg reg;
uint8_t use_flags = ir_get_use_flags(ctx, i, j, &reg);
if (reg != IR_REG_NONE && IR_REGSET_IN(available, reg)) {
IR_REGSET_EXCL(available, reg);
ctx->regs[i][j] = reg | IR_REG_SPILL_LOAD;
} else if (j > 1 && input == insn->op1 && ctx->regs[i][1] != IR_REG_NONE) {
ctx->regs[i][j] = ctx->regs[i][1];
} else if (ir_get_use_flags(ctx, i, j) & IR_USE_MUST_BE_IN_REG) {
} else if (use_flags & IR_USE_MUST_BE_IN_REG) {
reg = ir_get_free_reg(ctx->ir_base[input].type, available);
IR_REGSET_EXCL(available, reg);
ctx->regs[i][j] = reg | IR_REG_SPILL_LOAD;