mirror of
https://github.com/php/php-src.git
synced 2025-08-16 05:58:45 +02:00
Update IR
IR commit: d2ab283e3c3bb4b5ba21701a4d18f14fd9b3d798
This commit is contained in:
parent
71cccc0bcc
commit
a3620cd6e7
4 changed files with 291 additions and 29 deletions
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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))
|
||||||
|
|
|
@ -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 */
|
||||||
return IR_MOD_PWR2;
|
if (IR_IS_TYPE_UNSIGNED(insn->type)) {
|
||||||
|
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
|
||||||
| ASM_REG_IMM_OP and, type, def_reg, mask
|
|| 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
|
||||||
}
|
}
|
||||||
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;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue