Load fusion for MUL/DIV/MOD

This commit is contained in:
Dmitry Stogov 2022-08-25 21:47:07 +03:00
parent dbb382224d
commit 1f657fd4d7

View File

@ -99,14 +99,6 @@
|| }
|.endmacro
|.macro ASM_MREF_OP, op, type, ref
|| do {
|| int32_t offset = ir_ref_spill_slot(ctx, ref);
|| ir_reg fp = (ctx->flags & IR_USE_FRAME_POINTER) ? IR_REG_FRAME_POINTER : IR_REG_STACK_POINTER;
| ASM_MEM_OP op, type, [Ra(fp)+offset]
|| } while (0);
|.endmacro
|.macro ASM_REG_REG_OP, op, type, dst, src
|| switch (ir_type_size[type]) {
|| case 1:
@ -231,18 +223,6 @@
|| }
|.endmacro
|.macro ASM_REG_MREF_OP, _op, type, dst, src
|| if (IR_IS_CONST_REF(src)) {
|| ir_insn *_insn = &ctx->ir_base[src];
|| IR_ASSERT(IR_IS_32BIT(_insn->type, _insn->val));
| ASM_REG_IMM_OP _op, type, dst, _insn->val.i32
|| } else {
|| int32_t offset = ir_ref_spill_slot(ctx, src);
|| ir_reg fp = (ctx->flags & IR_USE_FRAME_POINTER) ? IR_REG_FRAME_POINTER : IR_REG_STACK_POINTER;
| ASM_REG_MEM_OP _op, type, dst, [Ra(fp)+offset]
|| }
|.endmacro
|.macro ASM_MREF_REG_OP, op, type, dst, src
|| do {
|| int32_t offset = ir_ref_spill_slot(ctx, dst);
@ -1399,7 +1379,11 @@ binop_fp:
return IR_MUL_PWR2; // shl op1, IR_LOG2(op2_insn->val.u64)
}
}
return (IR_IS_TYPE_SIGNED(insn->type) && ir_type_size[insn->type] != 1) ? IR_BINOP_INT : IR_MUL_INT;
if (IR_IS_TYPE_SIGNED(insn->type) && ir_type_size[insn->type] != 1) {
goto binop_int;
}
ir_match_fuse_load(ctx, insn->op2, bb);
return IR_MUL_INT;
} else {
goto binop_fp;
}
@ -1412,9 +1396,9 @@ binop_fp:
IR_ASSERT(IR_IS_TYPE_INT(insn->type));
if (IR_IS_TYPE_SIGNED(insn->type) && ir_type_size[insn->type] != 1) {
goto binop_int;
} else {
return IR_MUL_INT;
}
ir_match_fuse_load(ctx, insn->op2, bb);
return IR_MUL_INT;
case IR_DIV:
if (IR_IS_TYPE_INT(insn->type)) {
if ((ctx->flags & IR_OPT_CODEGEN) && IR_IS_CONST_REF(insn->op2)) {
@ -1427,6 +1411,7 @@ binop_fp:
return IR_DIV_PWR2; // shr op1, IR_LOG2(op2_insn->val.u64)
}
}
ir_match_fuse_load(ctx, insn->op2, bb);
return IR_DIV_INT;
} else {
goto binop_fp;
@ -1443,6 +1428,7 @@ binop_fp:
return IR_MOD_PWR2; // and op1, op2_insn->val.u64-1
}
}
ir_match_fuse_load(ctx, insn->op2, bb);
return IR_MOD_INT;
case IR_BSWAP:
case IR_NOT:
@ -3043,6 +3029,8 @@ static void ir_emit_mul_div_mod(ir_ctx *ctx, ir_ref def, ir_insn *insn)
ir_reg def_reg = IR_REG_NUM(ctx->regs[def][0]);
ir_reg op1_reg = ctx->regs[def][1];
ir_reg op2_reg = ctx->regs[def][2];
ir_reg base_reg = IR_REG_NONE;
int32_t offset = 0;
IR_ASSERT(def_reg != IR_REG_NONE);
@ -3071,12 +3059,21 @@ static void ir_emit_mul_div_mod(ir_ctx *ctx, ir_ref def, ir_insn *insn)
}
ir_emit_load(ctx, type, op2_reg, op2);
}
if (op2_reg == IR_REG_NONE) {
if (ctx->rules[op2] == IR_SKIP_MEM) {
base_reg = ir_fuse_load(ctx, op2, &offset);
IR_ASSERT(base_reg != IR_REG_NONE);
} else {
base_reg = (ctx->flags & IR_USE_FRAME_POINTER) ? IR_REG_FRAME_POINTER : IR_REG_STACK_POINTER;
offset = ir_ref_spill_slot(ctx, op2);
}
}
if (insn->op == IR_MUL || insn->op == IR_MUL_OV) {
IR_ASSERT(!IR_IS_TYPE_SIGNED(insn->type));
if (op2_reg != IR_REG_NONE) {
| ASM_REG_OP mul, type, op2_reg
} else {
| ASM_MREF_OP mul, type, op2
| ASM_MEM_OP mul, type, [Ra(base_reg)+offset]
}
} else {
if (IR_IS_TYPE_SIGNED(type)) {
@ -3090,14 +3087,14 @@ static void ir_emit_mul_div_mod(ir_ctx *ctx, ir_ref def, ir_insn *insn)
if (op2_reg != IR_REG_NONE) {
| ASM_REG_OP idiv, type, op2_reg
} else {
| ASM_MREF_OP idiv, type, op2
| ASM_MEM_OP idiv, type, [Ra(base_reg)+offset]
}
} else {
| ASM_REG_REG_OP xor, type, IR_REG_RDX, IR_REG_RDX
if (op2_reg != IR_REG_NONE) {
| ASM_REG_OP div, type, op2_reg
} else {
| ASM_MREF_OP div, type, op2
| ASM_MEM_OP div, type, [Ra(base_reg)+offset]
}
}
}