Update IR

IR commit: d2ab283e3c3bb4b5ba21701a4d18f14fd9b3d798
This commit is contained in:
Dmitry Stogov 2024-02-12 09:36:33 +03:00
parent 71cccc0bcc
commit a3620cd6e7
4 changed files with 291 additions and 29 deletions

View file

@ -878,6 +878,7 @@ static ir_ref _ir_fold_cse(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2, ir
#define IR_FOLD_CONST_F(_val) do { \ #define IR_FOLD_CONST_F(_val) do { \
val.f = (_val); \ val.f = (_val); \
val.u32_hi = 0; \
goto ir_fold_const; \ goto ir_fold_const; \
} while (0) } while (0)
@ -1756,7 +1757,7 @@ static ir_ref ir_find_aliasing_load(ir_ctx *ctx, ir_ref ref, ir_type type, ir_re
} }
} else if (insn->op == IR_RSTORE) { } else if (insn->op == IR_RSTORE) {
modified_regset |= (1 << insn->op3); modified_regset |= (1 << insn->op3);
} else if (insn->op >= IR_START || insn->op == IR_CALL || insn->op == IR_VSTORE) { } else if (insn->op == IR_MERGE || insn->op == IR_LOOP_BEGIN || insn->op == IR_CALL || insn->op == IR_VSTORE) {
return IR_UNUSED; return IR_UNUSED;
} }
ref = insn->op1; ref = insn->op1;
@ -2322,7 +2323,7 @@ void _ir_GUARD(ir_ctx *ctx, ir_ref condition, ir_ref addr)
condition = IR_FALSE; condition = IR_FALSE;
break; break;
} }
} else if (insn->op >= IR_START) { } else if (insn->op == IR_START || insn->op == IR_MERGE || insn->op == IR_LOOP_BEGIN) {
break; break;
} }
ref = insn->op1; ref = insn->op1;
@ -2354,7 +2355,7 @@ void _ir_GUARD_NOT(ir_ctx *ctx, ir_ref condition, ir_ref addr)
condition = IR_TRUE; condition = IR_TRUE;
break; break;
} }
} else if (insn->op >= IR_START) { } else if (insn->op == IR_START || insn->op == IR_MERGE || insn->op == IR_LOOP_BEGIN) {
break; break;
} }
ref = insn->op1; ref = insn->op1;

View file

@ -160,6 +160,14 @@ static bool aarch64_may_encode_addr_offset(int64_t offset, uint32_t type_size)
|| } || }
|.endmacro |.endmacro
|.macro ASM_REG_REG_REG_TXT_OP, op, type, dst, src1, src2, txt
|| if (ir_type_size[type] == 8) {
| op Rx(dst), Rx(src1), Rx(src2), txt
|| } else {
| op Rw(dst), Rw(src1), Rw(src2), txt
|| }
|.endmacro
|.macro ASM_REG_REG_REG_REG_OP, op, type, dst, src1, src2, src3 |.macro ASM_REG_REG_REG_REG_OP, op, type, dst, src1, src2, src3
|| if (ir_type_size[type] == 8) { || if (ir_type_size[type] == 8) {
| op Rx(dst), Rx(src1), Rx(src2), Rx(src3) | op Rx(dst), Rx(src1), Rx(src2), Rx(src3)
@ -280,6 +288,7 @@ const char *ir_reg_name(int8_t reg, ir_type type)
_(DIV_PWR2) \ _(DIV_PWR2) \
_(MOD_PWR2) \ _(MOD_PWR2) \
_(SDIV_PWR2) \ _(SDIV_PWR2) \
_(SMOD_PWR2) \
_(OP_INT) \ _(OP_INT) \
_(OP_FP) \ _(OP_FP) \
_(BINOP_INT) \ _(BINOP_INT) \
@ -378,10 +387,6 @@ int ir_get_target_constraints(ir_ctx *ctx, ir_ref ref, ir_target_constraints *co
n++; n++;
} }
break; break;
case IR_SEXT:
case IR_ZEXT:
flags = IR_USE_MUST_BE_IN_REG | IR_OP1_SHOULD_BE_IN_REG;
IR_FALLTHROUGH;
case IR_MUL_PWR2: case IR_MUL_PWR2:
case IR_DIV_PWR2: case IR_DIV_PWR2:
case IR_MOD_PWR2: case IR_MOD_PWR2:
@ -432,6 +437,17 @@ int ir_get_target_constraints(ir_ctx *ctx, ir_ref ref, ir_target_constraints *co
} }
} }
break; break;
case IR_SMOD_PWR2:
flags = IR_USE_MUST_BE_IN_REG | IR_OP1_SHOULD_BE_IN_REG;
insn = &ctx->ir_base[ref];
n = 0;
if (IR_IS_CONST_REF(insn->op1)) {
constraints->tmp_regs[n] = IR_TMP_REG(1, insn->type, IR_LOAD_SUB_REF, IR_DEF_SUB_REF);
n++;
}
constraints->tmp_regs[n] = IR_TMP_REG(3, insn->type, IR_USE_SUB_REF, IR_SAVE_SUB_REF);
n++;
break;
case IR_CTPOP: case IR_CTPOP:
flags = IR_USE_MUST_BE_IN_REG | IR_OP1_MUST_BE_IN_REG; flags = IR_USE_MUST_BE_IN_REG | IR_OP1_MUST_BE_IN_REG;
insn = &ctx->ir_base[ref]; insn = &ctx->ir_base[ref];
@ -565,6 +581,13 @@ int ir_get_target_constraints(ir_ctx *ctx, ir_ref ref, ir_target_constraints *co
break; break;
case IR_COPY_INT: case IR_COPY_INT:
case IR_COPY_FP: case IR_COPY_FP:
case IR_TRUNC:
case IR_BITCAST:
case IR_PROTO:
flags = IR_USE_MUST_BE_IN_REG | IR_OP1_SHOULD_BE_IN_REG;
break;
case IR_ZEXT:
case IR_SEXT:
flags = IR_DEF_REUSES_OP1_REG | IR_USE_MUST_BE_IN_REG; flags = IR_DEF_REUSES_OP1_REG | IR_USE_MUST_BE_IN_REG;
break; break;
case IR_PARAM: case IR_PARAM:
@ -582,11 +605,6 @@ int ir_get_target_constraints(ir_ctx *ctx, ir_ref ref, ir_target_constraints *co
case IR_EXITCALL: case IR_EXITCALL:
constraints->def_reg = IR_REG_INT_RET1; constraints->def_reg = IR_REG_INT_RET1;
break; break;
case IR_TRUNC:
case IR_BITCAST:
case IR_PROTO:
flags = IR_USE_MUST_BE_IN_REG | IR_OP1_SHOULD_BE_IN_REG;
break;
case IR_RSTORE: case IR_RSTORE:
flags = IR_OP3_SHOULD_BE_IN_REG; flags = IR_OP3_SHOULD_BE_IN_REG;
break; break;
@ -750,9 +768,12 @@ binop_fp:
/* pass */ /* pass */
} else if (IR_IS_CONST_REF(insn->op1)) { } else if (IR_IS_CONST_REF(insn->op1)) {
// const // const
} else if (IR_IS_TYPE_UNSIGNED(insn->type) && IR_IS_POWER_OF_TWO(op2_insn->val.u64)) { } else if (IR_IS_POWER_OF_TWO(op2_insn->val.u64)) {
// TODO: signed division by power of two ??? if (IR_IS_TYPE_UNSIGNED(insn->type)) {
return IR_MOD_PWR2; return IR_MOD_PWR2;
} else {
return IR_SMOD_PWR2;
}
} }
} }
return IR_BINOP_INT; return IR_BINOP_INT;
@ -2073,11 +2094,9 @@ static void ir_emit_mul_div_mod_pwr2(ir_ctx *ctx, ir_ref def, ir_insn *insn)
} }
} else if (insn->op == IR_DIV) { } else if (insn->op == IR_DIV) {
uint32_t shift = IR_LOG2(ctx->ir_base[insn->op2].val.u64); uint32_t shift = IR_LOG2(ctx->ir_base[insn->op2].val.u64);
IR_ASSERT(IR_IS_TYPE_UNSIGNED(type));
| ASM_REG_REG_IMM_OP lsr, type, def_reg, op1_reg, shift | ASM_REG_REG_IMM_OP lsr, type, def_reg, op1_reg, shift
} else { } else {
IR_ASSERT(insn->op == IR_MOD); IR_ASSERT(insn->op == IR_MOD);
IR_ASSERT(IR_IS_TYPE_UNSIGNED(type));
uint64_t mask = ctx->ir_base[insn->op2].val.u64 - 1; uint64_t mask = ctx->ir_base[insn->op2].val.u64 - 1;
| ASM_REG_REG_IMM_OP and, type, def_reg, op1_reg, mask | ASM_REG_REG_IMM_OP and, type, def_reg, op1_reg, mask
} }
@ -2142,6 +2161,50 @@ static void ir_emit_sdiv_pwr2(ir_ctx *ctx, ir_ref def, ir_insn *insn)
} }
} }
static void ir_emit_smod_pwr2(ir_ctx *ctx, ir_ref def, ir_insn *insn)
{
ir_backend_data *data = ctx->data;
dasm_State **Dst = &data->dasm_state;
ir_type type = insn->type;
ir_ref op1 = insn->op1;
ir_reg def_reg = IR_REG_NUM(ctx->regs[def][0]);
ir_reg op1_reg = ctx->regs[def][1];
ir_reg tmp_reg = ctx->regs[def][3];
// uint32_t shift = IR_LOG2(ctx->ir_base[insn->op2].val.u64);
uint64_t mask = ctx->ir_base[insn->op2].val.u64 - 1;
IR_ASSERT(IR_IS_CONST_REF(insn->op2));
IR_ASSERT(!IR_IS_SYM_CONST(ctx->ir_base[insn->op2].op));
IR_ASSERT(def_reg != IR_REG_NONE && tmp_reg != IR_REG_NONE && def_reg != tmp_reg);
if (op1_reg != IR_REG_NONE && IR_REG_SPILLED(op1_reg)) {
op1_reg = IR_REG_NUM(op1_reg);
ir_emit_load(ctx, type, op1_reg, op1);
}
if (def_reg != op1_reg) {
if (op1_reg != IR_REG_NONE) {
ir_emit_mov(ctx, type, def_reg, op1_reg);
} else {
ir_emit_load(ctx, type, def_reg, op1);
}
}
// | ASM_REG_REG_IMM_OP asr, type, tmp_reg, def_reg, (ir_type_size[type]*8-1)
// | ASM_REG_REG_IMM_OP lsr, type, tmp_reg, tmp_reg, (ir_type_size[type]*8-shift)
// | ASM_REG_REG_REG_OP add, type, def_reg, def_reg, tmp_reg
// | ASM_REG_REG_IMM_OP and, type, def_reg, def_reg, mask
// | ASM_REG_REG_REG_OP sub, type, def_reg, def_reg, tmp_reg
| ASM_REG_REG_OP negs, type, tmp_reg, def_reg
| ASM_REG_REG_IMM_OP and, type, def_reg, def_reg, mask
| ASM_REG_REG_IMM_OP and, type, tmp_reg, tmp_reg, mask
| ASM_REG_REG_REG_TXT_OP csneg, type, def_reg, def_reg, tmp_reg, mi
if (IR_REG_SPILLED(ctx->regs[def][0])) {
ir_emit_store(ctx, type, def, def_reg);
}
}
static void ir_emit_shift(ir_ctx *ctx, ir_ref def, ir_insn *insn) static void ir_emit_shift(ir_ctx *ctx, ir_ref def, ir_insn *insn)
{ {
ir_backend_data *data = ctx->data; ir_backend_data *data = ctx->data;
@ -5625,6 +5688,9 @@ void *ir_emit_code(ir_ctx *ctx, size_t *size_ptr)
case IR_SDIV_PWR2: case IR_SDIV_PWR2:
ir_emit_sdiv_pwr2(ctx, i, insn); ir_emit_sdiv_pwr2(ctx, i, insn);
break; break;
case IR_SMOD_PWR2:
ir_emit_smod_pwr2(ctx, i, insn);
break;
case IR_SHIFT: case IR_SHIFT:
ir_emit_shift(ctx, i, insn); ir_emit_shift(ctx, i, insn);
break; break;

View file

@ -1992,6 +1992,104 @@ IR_FOLD(GE(ABS, C_DOUBLE))
} }
// TODO: conversions // TODO: conversions
IR_FOLD(FP2FP(FP2FP))
{
if (IR_OPT_TYPE(opt) == IR_FLOAT) {
/* (float)(double)f => f */
IR_ASSERT(op1_insn->type == IR_DOUBLE);
IR_ASSERT(ctx->ir_base[op1_insn->op1].type == IR_FLOAT);
IR_FOLD_COPY(op1_insn->op1);
}
IR_FOLD_NEXT;
}
IR_FOLD(FP2INT(INT2FP))
{
ir_type dst_type = IR_OPT_TYPE(opt);
ir_type src_type = ctx->ir_base[op1_insn->op1].type;
if (ir_type_size[src_type] >= ir_type_size[op1_insn->type]) {
/* source integer type can not fit into intermediate floating point */
IR_FOLD_NEXT;
}
/* (int)(double)i => i */
if (src_type == dst_type) {
IR_FOLD_COPY(op1_insn->op1);
}
IR_FOLD_NEXT;
}
IR_FOLD(TRUNC(ZEXT))
IR_FOLD(TRUNC(SEXT))
{
ir_type dst_type = IR_OPT_TYPE(opt);
ir_type src_type = ctx->ir_base[op1_insn->op1].type;
/* (int32_t)(int64_t)i => i */
if (src_type == dst_type) {
IR_FOLD_COPY(op1_insn->op1);
} else if (ir_type_size[src_type] == ir_type_size[dst_type]) {
opt = IR_OPT(IR_BITCAST, dst_type);
op1 = op1_insn->op1;
IR_FOLD_RESTART;
} else if (ir_type_size[src_type] > ir_type_size[dst_type]) {
opt = IR_OPT(IR_TRUNC, dst_type);
op1 = op1_insn->op1;
IR_FOLD_RESTART;
} else {
opt = IR_OPT(op1_insn->op, dst_type);
op1 = op1_insn->op1;
IR_FOLD_RESTART;
}
IR_FOLD_NEXT;
}
IR_FOLD(TRUNC(AND))
{
if (IR_IS_CONST_REF(op1_insn->op2)) {
size_t size = ir_type_size[IR_OPT_TYPE(opt)];
uint64_t mask = ctx->ir_base[op1_insn->op2].val.u64;
if (size == 1) {
if (mask == 0xff) {
op1 = op1_insn->op1;
IR_FOLD_RESTART;
}
} else if (size == 2) {
if (mask == 0xffff) {
op1 = op1_insn->op1;
IR_FOLD_RESTART;
}
} else if (size == 4) {
if (mask == 0xffffffff) {
op1 = op1_insn->op1;
IR_FOLD_RESTART;
}
}
}
IR_FOLD_NEXT;
}
IR_FOLD(EQ(FP2FP, C_DOUBLE))
IR_FOLD(NE(FP2FP, C_DOUBLE))
IR_FOLD(LT(FP2FP, C_DOUBLE))
IR_FOLD(GE(FP2FP, C_DOUBLE))
IR_FOLD(LE(FP2FP, C_DOUBLE))
IR_FOLD(GT(FP2FP, C_DOUBLE))
IR_FOLD(ULT(FP2FP, C_DOUBLE))
IR_FOLD(UGE(FP2FP, C_DOUBLE))
IR_FOLD(ULE(FP2FP, C_DOUBLE))
IR_FOLD(UGT(FP2FP, C_DOUBLE))
{
IR_ASSERT(op1_insn->type == IR_DOUBLE);
IR_ASSERT(ctx->ir_base[op1_insn->op1].type == IR_FLOAT);
if (op2_insn->val.d == (double)(float)op2_insn->val.d) {
op1 = op1_insn->op1;
op2 = ir_const_float(ctx, (float)op2_insn->val.d);
IR_FOLD_RESTART;
}
IR_FOLD_NEXT;
}
// TODO: Reassociation // TODO: Reassociation
IR_FOLD(ADD(ADD, C_U8)) IR_FOLD(ADD(ADD, C_U8))

View file

@ -780,7 +780,7 @@ IR_ALWAYS_INLINE ir_mem IR_MEM(ir_reg base, int32_t offset, ir_reg index, int32_
| op..d xmm(op1-IR_REG_FP_FIRST), xmm(op2-IR_REG_FP_FIRST), qword op3 | op..d xmm(op1-IR_REG_FP_FIRST), xmm(op2-IR_REG_FP_FIRST), qword op3
|| } else { || } else {
|| IR_ASSERT(type == IR_FLOAT); || IR_ASSERT(type == IR_FLOAT);
| op..s xmm(op2-IR_REG_FP_FIRST), xmm(op2-IR_REG_FP_FIRST), dword op3 | op..s xmm(op1-IR_REG_FP_FIRST), xmm(op2-IR_REG_FP_FIRST), dword op3
|| } || }
|.endmacro |.endmacro
@ -979,6 +979,7 @@ const char *ir_reg_name(int8_t reg, ir_type type)
_(DIV_PWR2) \ _(DIV_PWR2) \
_(MOD_PWR2) \ _(MOD_PWR2) \
_(SDIV_PWR2) \ _(SDIV_PWR2) \
_(SMOD_PWR2) \
_(BOOL_NOT_INT) \ _(BOOL_NOT_INT) \
_(ABS_INT) \ _(ABS_INT) \
_(OP_INT) \ _(OP_INT) \
@ -1303,18 +1304,41 @@ op2_const:
case IR_DEC: case IR_DEC:
case IR_MUL_PWR2: case IR_MUL_PWR2:
case IR_DIV_PWR2: case IR_DIV_PWR2:
case IR_MOD_PWR2:
case IR_OP_INT: case IR_OP_INT:
case IR_OP_FP: case IR_OP_FP:
flags = IR_DEF_REUSES_OP1_REG | IR_USE_MUST_BE_IN_REG | IR_OP1_SHOULD_BE_IN_REG; flags = IR_DEF_REUSES_OP1_REG | IR_USE_MUST_BE_IN_REG | IR_OP1_SHOULD_BE_IN_REG;
break; break;
case IR_MOD_PWR2:
flags = IR_DEF_REUSES_OP1_REG | IR_USE_MUST_BE_IN_REG | IR_OP1_SHOULD_BE_IN_REG;
insn = &ctx->ir_base[ref];
if (ir_type_size[insn->type] == 8) {
int64_t offset = ctx->ir_base[insn->op2].val.u64 - 1;
if (!IR_IS_SIGNED_32BIT(offset)) {
constraints->tmp_regs[n] = IR_TMP_REG(2, insn->type, IR_LOAD_SUB_REF, IR_DEF_SUB_REF);
n++;
}
}
break;
case IR_SMOD_PWR2:
flags = IR_DEF_REUSES_OP1_REG | IR_USE_MUST_BE_IN_REG | IR_OP1_SHOULD_BE_IN_REG;
insn = &ctx->ir_base[ref];
if (ir_type_size[insn->type] == 8) {
int64_t offset = ctx->ir_base[insn->op2].val.u64 - 1;
if (!IR_IS_SIGNED_32BIT(offset)) {
constraints->tmp_regs[n] = IR_TMP_REG(2, insn->type, IR_LOAD_SUB_REF, IR_DEF_SUB_REF);
n++;
}
}
constraints->tmp_regs[n] = IR_TMP_REG(3, insn->type, IR_USE_SUB_REF, IR_SAVE_SUB_REF);
n++;
break;
case IR_SDIV_PWR2: case IR_SDIV_PWR2:
flags = IR_DEF_CONFLICTS_WITH_INPUT_REGS | IR_USE_MUST_BE_IN_REG | IR_OP1_MUST_BE_IN_REG; flags = IR_DEF_CONFLICTS_WITH_INPUT_REGS | IR_USE_MUST_BE_IN_REG | IR_OP1_MUST_BE_IN_REG;
insn = &ctx->ir_base[ref]; insn = &ctx->ir_base[ref];
if (ir_type_size[insn->type] == 8) { if (ir_type_size[insn->type] == 8) {
int64_t offset = ctx->ir_base[insn->op2].val.u64 - 1; int64_t offset = ctx->ir_base[insn->op2].val.u64 - 1;
if (!IR_IS_SIGNED_32BIT(offset)) { if (!IR_IS_SIGNED_32BIT(offset)) {
constraints->tmp_regs[n] = IR_TMP_REG(3, insn->type, IR_LOAD_SUB_REF, IR_DEF_SUB_REF); constraints->tmp_regs[n] = IR_TMP_REG(2, insn->type, IR_LOAD_SUB_REF, IR_DEF_SUB_REF);
n++; n++;
} }
} }
@ -1345,6 +1369,9 @@ op2_const:
case IR_COPY_FP: case IR_COPY_FP:
case IR_SEXT: case IR_SEXT:
case IR_ZEXT: case IR_ZEXT:
case IR_TRUNC:
case IR_BITCAST:
case IR_PROTO:
flags = IR_DEF_REUSES_OP1_REG | IR_USE_MUST_BE_IN_REG | IR_OP1_SHOULD_BE_IN_REG; flags = IR_DEF_REUSES_OP1_REG | IR_USE_MUST_BE_IN_REG | IR_OP1_SHOULD_BE_IN_REG;
break; break;
case IR_ABS_INT: case IR_ABS_INT:
@ -1929,12 +1956,13 @@ binop_fp:
/* pass */ /* pass */
} else if (IR_IS_CONST_REF(insn->op1)) { } else if (IR_IS_CONST_REF(insn->op1)) {
// const // const
} else if (IR_IS_TYPE_UNSIGNED(insn->type) } else if (IR_IS_POWER_OF_TWO(op2_insn->val.u64)) {
&& IR_IS_POWER_OF_TWO(op2_insn->val.u64)
&& IR_IS_UNSIGNED_32BIT(op2_insn->val.u64 - 1)) {
// TODO: signed division by power of two ???
/* MOD(X, PWR2) => AND */ /* MOD(X, PWR2) => AND */
if (IR_IS_TYPE_UNSIGNED(insn->type)) {
return IR_MOD_PWR2; return IR_MOD_PWR2;
} else {
return IR_SMOD_PWR2;
}
} }
} }
ir_match_fuse_load(ctx, insn->op2, ref); ir_match_fuse_load(ctx, insn->op2, ref);
@ -3716,6 +3744,7 @@ static void ir_emit_mul_div_mod_pwr2(ir_ctx *ctx, ir_ref def, ir_insn *insn)
} }
if (insn->op == IR_MUL) { if (insn->op == IR_MUL) {
uint32_t shift = IR_LOG2(ctx->ir_base[insn->op2].val.u64); uint32_t shift = IR_LOG2(ctx->ir_base[insn->op2].val.u64);
if (shift == 1) { if (shift == 1) {
| ASM_REG_REG_OP add, type, def_reg, def_reg | ASM_REG_REG_OP add, type, def_reg, def_reg
} else { } else {
@ -3723,14 +3752,24 @@ static void ir_emit_mul_div_mod_pwr2(ir_ctx *ctx, ir_ref def, ir_insn *insn)
} }
} else if (insn->op == IR_DIV) { } else if (insn->op == IR_DIV) {
uint32_t shift = IR_LOG2(ctx->ir_base[insn->op2].val.u64); uint32_t shift = IR_LOG2(ctx->ir_base[insn->op2].val.u64);
IR_ASSERT(IR_IS_TYPE_UNSIGNED(type));
| ASM_REG_IMM_OP shr, type, def_reg, shift | ASM_REG_IMM_OP shr, type, def_reg, shift
} else { } else {
IR_ASSERT(insn->op == IR_MOD); IR_ASSERT(insn->op == IR_MOD);
uint64_t mask = ctx->ir_base[insn->op2].val.u64 - 1; uint64_t mask = ctx->ir_base[insn->op2].val.u64 - 1;
IR_ASSERT(IR_IS_TYPE_UNSIGNED(type));
IR_ASSERT(IR_IS_UNSIGNED_32BIT(mask)); |.if X64
|| if (ir_type_size[type] == 8 && ctx->regs[def][2] != IR_REG_NONE) {
|| ir_reg op2_reg = ctx->regs[def][2];
||
|| ir_emit_load_imm_int(ctx, type, op2_reg, mask);
| ASM_REG_REG_OP and, type, def_reg, op2_reg
|| } else {
|.endif
| ASM_REG_IMM_OP and, type, def_reg, mask | ASM_REG_IMM_OP and, type, def_reg, mask
|.if X64
|| }
|.endif
} }
if (IR_REG_SPILLED(ctx->regs[def][0])) { if (IR_REG_SPILLED(ctx->regs[def][0])) {
ir_emit_store(ctx, type, def, def_reg); ir_emit_store(ctx, type, def, def_reg);
@ -3798,6 +3837,61 @@ static void ir_emit_sdiv_pwr2(ir_ctx *ctx, ir_ref def, ir_insn *insn)
} }
} }
static void ir_emit_smod_pwr2(ir_ctx *ctx, ir_ref def, ir_insn *insn)
{
ir_backend_data *data = ctx->data;
dasm_State **Dst = &data->dasm_state;
ir_type type = insn->type;
ir_ref op1 = insn->op1;
ir_reg def_reg = IR_REG_NUM(ctx->regs[def][0]);
ir_reg op1_reg = ctx->regs[def][1];
ir_reg tmp_reg = ctx->regs[def][3];
uint32_t shift = IR_LOG2(ctx->ir_base[insn->op2].val.u64);
uint64_t mask = ctx->ir_base[insn->op2].val.u64 - 1;
IR_ASSERT(IR_IS_CONST_REF(insn->op2));
IR_ASSERT(!IR_IS_SYM_CONST(ctx->ir_base[insn->op2].op));
IR_ASSERT(def_reg != IR_REG_NONE && tmp_reg != IR_REG_NONE && def_reg != tmp_reg);
if (op1_reg != IR_REG_NONE && IR_REG_SPILLED(op1_reg)) {
op1_reg = IR_REG_NUM(op1_reg);
ir_emit_load(ctx, type, op1_reg, op1);
}
if (def_reg != op1_reg) {
if (op1_reg != IR_REG_NONE) {
ir_emit_mov(ctx, type, def_reg, op1_reg);
} else {
ir_emit_load(ctx, type, def_reg, op1);
}
}
if (tmp_reg != op1_reg) {
ir_emit_mov(ctx, type, tmp_reg, def_reg);
}
| ASM_REG_IMM_OP sar, type, tmp_reg, (ir_type_size[type]*8-1)
| ASM_REG_IMM_OP shr, type, tmp_reg, (ir_type_size[type]*8-shift)
| ASM_REG_REG_OP add, type, def_reg, tmp_reg
|.if X64
|| if (ir_type_size[type] == 8 && ctx->regs[def][2] != IR_REG_NONE) {
|| ir_reg op2_reg = ctx->regs[def][2];
||
|| ir_emit_load_imm_int(ctx, type, op2_reg, mask);
| ASM_REG_REG_OP and, type, def_reg, op2_reg
|| } else {
|.endif
| ASM_REG_IMM_OP and, type, def_reg, mask
|.if X64
|| }
|.endif
| ASM_REG_REG_OP sub, type, def_reg, tmp_reg
if (IR_REG_SPILLED(ctx->regs[def][0])) {
ir_emit_store(ctx, type, def, def_reg);
}
}
static void ir_emit_mem_mul_div_mod_pwr2(ir_ctx *ctx, ir_ref def, ir_insn *insn) static void ir_emit_mem_mul_div_mod_pwr2(ir_ctx *ctx, ir_ref def, ir_insn *insn)
{ {
ir_backend_data *data = ctx->data; ir_backend_data *data = ctx->data;
@ -9237,6 +9331,9 @@ void *ir_emit_code(ir_ctx *ctx, size_t *size_ptr)
case IR_SDIV_PWR2: case IR_SDIV_PWR2:
ir_emit_sdiv_pwr2(ctx, i, insn); ir_emit_sdiv_pwr2(ctx, i, insn);
break; break;
case IR_SMOD_PWR2:
ir_emit_smod_pwr2(ctx, i, insn);
break;
case IR_SHIFT: case IR_SHIFT:
ir_emit_shift(ctx, i, insn); ir_emit_shift(ctx, i, insn);
break; break;