1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

Update IR

IR commit: 34aeda97a5febe81fb53a679800f8c6cd802c847
This commit is contained in:
Dmitry Stogov
2024-01-17 13:51:59 +03:00
parent 822769f412
commit 2bacd4e110
8 changed files with 480 additions and 173 deletions

View File

@@ -1730,7 +1730,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) {
modified_regset |= (1 << insn->op3);
} else if (insn->op >= IR_START || insn->op == IR_CALL) {
} else if (insn->op >= IR_START || insn->op == IR_CALL || insn->op == IR_VSTORE) {
return IR_UNUSED;
}
ref = insn->op1;

View File

@@ -94,6 +94,13 @@ static bool aarch64_may_encode_logical_imm(uint64_t value, uint32_t type_size)
return 0;
}
static bool aarch64_may_encode_imm7_addr_offset(const int64_t offset, uint32_t type_size)
{
return (uintptr_t)(offset) % type_size == 0
&& offset < 63 * (int32_t)type_size
&& offset >= -64 * (int32_t)type_size;
}
static bool aarch64_may_encode_addr_offset(int64_t offset, uint32_t type_size)
{
return (uintptr_t)(offset) % type_size == 0 && (uintptr_t)(offset) < 0xfff * type_size;
@@ -352,7 +359,20 @@ int ir_get_target_constraints(const ir_ctx *ctx, ir_ref ref, ir_target_constrain
constraints->tmp_regs[n] = IR_TMP_REG(1, insn->type, IR_LOAD_SUB_REF, IR_DEF_SUB_REF);
n++;
}
if (rule == IR_SHIFT && insn->op == IR_ROL) {
if (rule == IR_SHIFT_CONST
&& (insn->op == IR_ROL || insn->op == IR_ROR)
&& ir_type_size[insn->type] < 4) {
constraints->tmp_regs[n] = IR_TMP_REG(3, insn->type, IR_LOAD_SUB_REF, IR_DEF_SUB_REF);
n++;
} else if (rule == IR_SHIFT
&& (insn->op == IR_ROL || insn->op == IR_ROR)
&& ir_type_size[insn->type] < 4) {
if (insn->op == IR_ROL) {
flags |= IR_DEF_CONFLICTS_WITH_INPUT_REGS;
}
constraints->tmp_regs[n] = IR_TMP_REG(3, insn->type, IR_LOAD_SUB_REF, IR_SAVE_SUB_REF);
n++;
} else if (rule == IR_SHIFT && insn->op == IR_ROL) {
constraints->tmp_regs[n] = IR_TMP_REG(3, insn->type, IR_LOAD_SUB_REF, IR_DEF_SUB_REF);
n++;
}
@@ -1341,9 +1361,16 @@ static void ir_emit_prologue(ir_ctx *ctx)
{
ir_backend_data *data = ctx->data;
dasm_State **Dst = &data->dasm_state;
int offset;
if (ctx->flags & IR_USE_FRAME_POINTER) {
| stp x29, x30, [sp, # (-(ctx->stack_frame_size+16))]!
offset = -(ctx->stack_frame_size+16);
if (aarch64_may_encode_imm7_addr_offset(offset, 8)) {
| stp x29, x30, [sp, #offset]!
} else {
| sub sp, sp, #(ctx->stack_frame_size+16)
| stp x29, x30, [sp]
}
| mov x29, sp
if (ctx->call_stack_size) {
| sub sp, sp, #(ctx->call_stack_size)
@@ -1357,7 +1384,6 @@ static void ir_emit_prologue(ir_ctx *ctx)
}
if (ctx->used_preserved_regs) {
ir_reg fp;
int offset;
uint32_t i;
ir_reg prev = IR_REG_NONE;
ir_regset used_preserved_regs = (ir_regset)ctx->used_preserved_regs;
@@ -1375,7 +1401,13 @@ static void ir_emit_prologue(ir_ctx *ctx)
prev = i;
} else if (i < IR_REG_FP_FIRST) {
offset -= sizeof(void*) * 2;
| stp Rx(prev), Rx(i), [Rx(fp), #offset]
if (aarch64_may_encode_imm7_addr_offset(offset, 8)) {
| stp Rx(prev), Rx(i), [Rx(fp), #offset]
} else {
IR_ASSERT(aarch64_may_encode_addr_offset(offset, 8));
| str Rx(prev), [Rx(fp), #offset]
| str Rx(i), [Rx(fp), #(offset+8)]
}
prev = IR_REG_NONE;
} else {
if (prev < IR_REG_FP_FIRST) {
@@ -1385,7 +1417,13 @@ static void ir_emit_prologue(ir_ctx *ctx)
| str Rd(i-IR_REG_FP_FIRST), [Rx(fp), #offset]
} else {
offset -= sizeof(void*) * 2;
| stp Rd(prev-IR_REG_FP_FIRST), Rd(i-IR_REG_FP_FIRST), [Rx(fp), #offset]
if (aarch64_may_encode_imm7_addr_offset(offset, 8)) {
| stp Rd(prev-IR_REG_FP_FIRST), Rd(i-IR_REG_FP_FIRST), [Rx(fp), #offset]
} else {
IR_ASSERT(aarch64_may_encode_addr_offset(offset, 8));
| str Rd(prev-IR_REG_FP_FIRST), [Rx(fp), #offset]
| str Rd(i-IR_REG_FP_FIRST), [Rx(fp), #(offset+8)]
}
}
prev = IR_REG_NONE;
}
@@ -1425,7 +1463,13 @@ static void ir_emit_prologue(ir_ctx *ctx)
offset += sizeof(void*) * ctx->gp_reg_params;
for (i = ctx->gp_reg_params; i < IR_REG_INT_ARGS; i++) {
if (prev != IR_REG_NONE) {
| stp Rx(prev), Rx(int_reg_params[i]), [Rx(fp), #offset]
if (aarch64_may_encode_imm7_addr_offset(offset, 8)) {
| stp Rx(prev), Rx(int_reg_params[i]), [Rx(fp), #offset]
} else {
IR_ASSERT(aarch64_may_encode_addr_offset(offset, 8));
| str Rx(prev), [Rx(fp), #offset]
| str Rx(int_reg_params[i]), [Rx(fp), #(offset+8)]
}
prev = IR_REG_NONE;
offset += sizeof(void*) * 2;
} else {
@@ -1473,7 +1517,13 @@ static void ir_emit_epilogue(ir_ctx *ctx)
prev = i;
} else if (i < IR_REG_FP_FIRST) {
offset -= sizeof(void*) * 2;
| ldp Rx(prev), Rx(i), [Rx(fp), #offset]
if (aarch64_may_encode_imm7_addr_offset(offset, 8)) {
| ldp Rx(prev), Rx(i), [Rx(fp), #offset]
} else {
IR_ASSERT(aarch64_may_encode_addr_offset(offset, 8));
| ldr Rx(prev), [Rx(fp), #offset]
| ldr Rx(i), [Rx(fp), #(offset+8)]
}
prev = IR_REG_NONE;
} else {
if (prev < IR_REG_FP_FIRST) {
@@ -1483,7 +1533,13 @@ static void ir_emit_epilogue(ir_ctx *ctx)
| ldr Rd(i-IR_REG_FP_FIRST), [Rx(fp), #offset]
} else {
offset -= sizeof(void*) * 2;
| ldp Rd(prev-IR_REG_FP_FIRST), Rd(i-IR_REG_FP_FIRST), [Rx(fp), #offset]
if (aarch64_may_encode_imm7_addr_offset(offset, 8)) {
| ldp Rd(prev-IR_REG_FP_FIRST), Rd(i-IR_REG_FP_FIRST), [Rx(fp), #offset]
} else {
IR_ASSERT(aarch64_may_encode_addr_offset(offset, 8));
| ldr Rd(prev-IR_REG_FP_FIRST), [Rx(fp), #offset]
| ldr Rd(i-IR_REG_FP_FIRST), [Rx(fp), #(offset+8)]
}
}
prev = IR_REG_NONE;
}
@@ -1504,7 +1560,12 @@ static void ir_emit_epilogue(ir_ctx *ctx)
if (ctx->call_stack_size || (ctx->flags2 & IR_HAS_ALLOCA)) {
| mov sp, x29
}
| ldp x29, x30, [sp], # (ctx->stack_frame_size+16)
if (aarch64_may_encode_imm7_addr_offset(ctx->stack_frame_size+16, 8)) {
| ldp x29, x30, [sp], #(ctx->stack_frame_size+16)
} else {
| ldp x29, x30, [sp]
| add sp, sp, #(ctx->stack_frame_size+16)
}
} else if (ctx->stack_frame_size + ctx->call_stack_size) {
if (ctx->fixed_stack_red_zone) {
IR_ASSERT(ctx->stack_frame_size + ctx->call_stack_size <= ctx->fixed_stack_red_zone);
@@ -1922,18 +1983,55 @@ static void ir_emit_shift(ir_ctx *ctx, ir_ref def, ir_insn *insn)
default:
IR_ASSERT(0);
case IR_SHL:
| ASM_REG_REG_REG_OP lsl, type, def_reg, op1_reg, op2_reg
if (ir_type_size[type] == 1) {
| and Rw(def_reg), Rw(op1_reg), #0xff
| lsl Rw(def_reg), Rw(def_reg), Rw(op2_reg)
} else if (ir_type_size[type] == 2) {
| and Rw(def_reg), Rw(op1_reg), #0xffff
| lsl Rw(def_reg), Rw(def_reg), Rw(op2_reg)
} else {
| ASM_REG_REG_REG_OP lsl, type, def_reg, op1_reg, op2_reg
}
break;
case IR_SHR:
| ASM_REG_REG_REG_OP lsr, type, def_reg, op1_reg, op2_reg
if (ir_type_size[type] == 1) {
| and Rw(def_reg), Rw(op1_reg), #0xff
| lsr Rw(def_reg), Rw(def_reg), Rw(op2_reg)
} else if (ir_type_size[type] == 2) {
| and Rw(def_reg), Rw(op1_reg), #0xffff
| lsr Rw(def_reg), Rw(def_reg), Rw(op2_reg)
} else {
| ASM_REG_REG_REG_OP lsr, type, def_reg, op1_reg, op2_reg
}
break;
case IR_SAR:
| ASM_REG_REG_REG_OP asr, type, def_reg, op1_reg, op2_reg
if (ir_type_size[type] == 1) {
| sxtb Rw(def_reg), Rw(op1_reg)
| asr Rw(def_reg), Rw(def_reg), Rw(op2_reg)
} else if (ir_type_size[type] == 2) {
| sxth Rw(def_reg), Rw(op1_reg)
| asr Rw(def_reg), Rw(def_reg), Rw(op2_reg)
} else {
| ASM_REG_REG_REG_OP asr, type, def_reg, op1_reg, op2_reg
}
break;
case IR_ROL:
tmp_reg = ctx->regs[def][3];
IR_ASSERT(tmp_reg != IR_REG_NONE);
if (ir_type_size[type] == 8) {
if (ir_type_size[type] == 1) {
| and Rw(def_reg), Rw(op1_reg), #0xff
| add Rw(def_reg), Rw(def_reg), Rw(def_reg), lsl #8
| add Rw(def_reg), Rw(def_reg), Rw(def_reg), lsl #16
| neg Rw(tmp_reg), Rw(op2_reg)
| ror Rw(def_reg), Rw(def_reg), Rw(tmp_reg)
| and Rw(def_reg), Rw(def_reg), #0xff
} else if (ir_type_size[type] == 2) {
| and Rw(def_reg), Rw(op1_reg), #0xffff
| add Rw(def_reg), Rw(def_reg), Rw(def_reg), lsl #16
| neg Rw(tmp_reg), Rw(op2_reg)
| ror Rw(def_reg), Rw(def_reg), Rw(tmp_reg)
| and Rw(def_reg), Rw(def_reg), #0xffff
} else if (ir_type_size[type] == 8) {
| neg Rx(tmp_reg), Rx(op2_reg)
| ror Rx(def_reg), Rx(op1_reg), Rx(tmp_reg)
} else {
@@ -1942,7 +2040,24 @@ static void ir_emit_shift(ir_ctx *ctx, ir_ref def, ir_insn *insn)
}
break;
case IR_ROR:
| ASM_REG_REG_REG_OP ror, type, def_reg, op1_reg, op2_reg
if (ir_type_size[type] == 1) {
tmp_reg = ctx->regs[def][3];
IR_ASSERT(tmp_reg != IR_REG_NONE);
| and Rw(tmp_reg), Rw(op1_reg), #0xff
| add Rw(tmp_reg), Rw(tmp_reg), Rw(tmp_reg), lsl #8
| add Rw(tmp_reg), Rw(tmp_reg), Rw(tmp_reg), lsl #16
| ror Rw(def_reg), Rw(tmp_reg), Rw(op2_reg)
| and Rw(def_reg), Rw(def_reg), #0xff
} else if (ir_type_size[type] == 2) {
tmp_reg = ctx->regs[def][3];
IR_ASSERT(tmp_reg != IR_REG_NONE);
| and Rw(tmp_reg), Rw(op1_reg), #0xffff
| add Rw(tmp_reg), Rw(tmp_reg), Rw(tmp_reg), lsl #16
| ror Rw(def_reg), Rw(tmp_reg), Rw(op2_reg)
| and Rw(def_reg), Rw(def_reg), #0xffff
} else {
| ASM_REG_REG_REG_OP ror, type, def_reg, op1_reg, op2_reg
}
break;
}
if (IR_REG_SPILLED(ctx->regs[def][0])) {
@@ -1959,6 +2074,7 @@ static void ir_emit_shift_const(ir_ctx *ctx, ir_ref def, ir_insn *insn)
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;
IR_ASSERT(IR_IS_CONST_REF(insn->op2));
IR_ASSERT(!IR_IS_SYM_CONST(ctx->ir_base[insn->op2].op));
@@ -1972,16 +2088,42 @@ static void ir_emit_shift_const(ir_ctx *ctx, ir_ref def, ir_insn *insn)
default:
IR_ASSERT(0);
case IR_SHL:
| ASM_REG_REG_IMM_OP lsl, type, def_reg, op1_reg, shift
if (ir_type_size[type] == 1) {
| ubfiz Rw(def_reg), Rw(op1_reg), #shift, #(8-shift)
} else if (ir_type_size[type] == 2) {
| ubfiz Rw(def_reg), Rw(op1_reg), #shift, #(16-shift)
} else {
| ASM_REG_REG_IMM_OP lsl, type, def_reg, op1_reg, shift
}
break;
case IR_SHR:
| ASM_REG_REG_IMM_OP lsr, type, def_reg, op1_reg, shift
if (ir_type_size[type] == 1) {
| ubfx Rw(def_reg), Rw(op1_reg), #shift, #(8-shift)
} else if (ir_type_size[type] == 2) {
| ubfx Rw(def_reg), Rw(op1_reg), #shift, #(16-shift)
} else {
| ASM_REG_REG_IMM_OP lsr, type, def_reg, op1_reg, shift
}
break;
case IR_SAR:
| ASM_REG_REG_IMM_OP asr, type, def_reg, op1_reg, shift
if (ir_type_size[type] == 1) {
| sbfx Rw(def_reg), Rw(op1_reg), #shift, #(8-shift)
} else if (ir_type_size[type] == 2) {
| sbfx Rw(def_reg), Rw(op1_reg), #shift, #(16-shift)
} else {
| ASM_REG_REG_IMM_OP asr, type, def_reg, op1_reg, shift
}
break;
case IR_ROL:
if (ir_type_size[type] == 8) {
if (ir_type_size[type] == 1) {
tmp_reg = ctx->regs[def][3];
| ubfx Rw(tmp_reg), Rw(op1_reg), #(8-shift), #shift
| orr Rw(def_reg), Rw(tmp_reg), Rw(op1_reg), lsl #shift
} else if (ir_type_size[type] == 2) {
tmp_reg = ctx->regs[def][3];
| ubfx Rw(tmp_reg), Rw(op1_reg), #(16-shift), #shift
| orr Rw(def_reg), Rw(tmp_reg), Rw(op1_reg), lsl #shift
} else if (ir_type_size[type] == 8) {
shift = (64 - shift) % 64;
| ror Rx(def_reg), Rx(op1_reg), #shift
} else {
@@ -1990,7 +2132,17 @@ static void ir_emit_shift_const(ir_ctx *ctx, ir_ref def, ir_insn *insn)
}
break;
case IR_ROR:
| ASM_REG_REG_IMM_OP ror, type, def_reg, op1_reg, shift
if (ir_type_size[type] == 1) {
tmp_reg = ctx->regs[def][3];
| ubfx Rw(tmp_reg), Rw(op1_reg), #shift, #(8-shift)
| orr Rw(def_reg), Rw(tmp_reg), Rw(op1_reg), lsl #(8-shift)
} else if (ir_type_size[type] == 2) {
tmp_reg = ctx->regs[def][3];
| ubfx Rw(tmp_reg), Rw(op1_reg), #shift, #(16-shift)
| orr Rw(def_reg), Rw(tmp_reg), Rw(op1_reg), lsl #(16-shift)
} else {
| ASM_REG_REG_IMM_OP ror, type, def_reg, op1_reg, shift
}
break;
}
if (IR_REG_SPILLED(ctx->regs[def][0])) {
@@ -3653,7 +3805,7 @@ static void ir_emit_alloca(ir_ctx *ctx, ir_ref def, ir_insn *insn)
IR_ASSERT(IR_IS_TYPE_INT(val->type));
IR_ASSERT(!IR_IS_SYM_CONST(val->op));
IR_ASSERT(IR_IS_TYPE_UNSIGNED(val->type) || val->val.i64 > 0);
IR_ASSERT(IR_IS_TYPE_UNSIGNED(val->type) || val->val.i64 >= 0);
if (ctx->flags2 & IR_HAS_CALLS) {
/* Stack must be 16 byte aligned */
@@ -4971,7 +5123,7 @@ static void ir_emit_load_params(ir_ctx *ctx)
if (ctx->flags & IR_USE_FRAME_POINTER) {
stack_offset = sizeof(void*) * 2; /* skip old frame pointer and return address */
} else {
stack_offset = sizeof(void*) + ctx->stack_frame_size + ctx->call_stack_size; /* skip return address */
stack_offset = ctx->stack_frame_size + ctx->call_stack_size;
}
n = use_list->count;
for (i = 0, p = &ctx->use_edges[use_list->refs]; i < n; i++, p++) {
@@ -5079,8 +5231,7 @@ static void ir_fix_param_spills(ir_ctx *ctx)
/* skip old frame pointer and return address */
stack_offset = sizeof(void*) * 2 + (ctx->stack_frame_size - ctx->stack_frame_alignment);
} else {
/* skip return address */
stack_offset = sizeof(void*) + ctx->stack_frame_size;
stack_offset = ctx->stack_frame_size;
}
n = use_list->count;
for (i = 0, p = &ctx->use_edges[use_list->refs]; i < n; i++, p++) {

View File

@@ -586,26 +586,41 @@ IR_FOLD(NOT(C_BOOL))
IR_FOLD(NOT(C_U8))
IR_FOLD(NOT(C_CHAR))
IR_FOLD(NOT(C_I8))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_U(~op1_insn->val.u8);
}
IR_FOLD(NOT(C_I8))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_I(~op1_insn->val.i8);
}
IR_FOLD(NOT(C_U16))
IR_FOLD(NOT(C_I16))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_U(~op1_insn->val.u16);
}
IR_FOLD(NOT(C_I16))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_I(~op1_insn->val.i16);
}
IR_FOLD(NOT(C_U32))
IR_FOLD(NOT(C_I32))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_U(~op1_insn->val.u32);
}
IR_FOLD(NOT(C_I32))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_I(~op1_insn->val.i32);
}
IR_FOLD(NOT(C_U64))
IR_FOLD(NOT(C_I64))
{
@@ -619,70 +634,50 @@ IR_FOLD(OR(C_BOOL, C_BOOL))
IR_FOLD_BOOL(op1_insn->val.b || op2_insn->val.b);
}
IR_FOLD(OR(C_U8, C_U8))
IR_FOLD(OR(C_CHAR, C_CHAR))
IR_FOLD(OR(C_I8, C_I8))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_U(op1_insn->val.u8 | op2_insn->val.u8);
}
IR_FOLD(OR(C_U8, C_U8))
IR_FOLD(OR(C_U16, C_U16))
IR_FOLD(OR(C_I16, C_I16))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_U(op1_insn->val.u16 | op2_insn->val.u16);
}
IR_FOLD(OR(C_U32, C_U32))
IR_FOLD(OR(C_I32, C_I32))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_U(op1_insn->val.u32 | op2_insn->val.u32);
}
IR_FOLD(OR(C_U64, C_U64))
IR_FOLD(OR(C_I64, C_I64))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_U(op1_insn->val.u64 | op2_insn->val.u64);
}
IR_FOLD(OR(C_I8, C_I8))
IR_FOLD(OR(C_I16, C_I16))
IR_FOLD(OR(C_I32, C_I32))
IR_FOLD(OR(C_I64, C_I64))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_I(op1_insn->val.i64 | op2_insn->val.i64);
}
IR_FOLD(AND(C_BOOL, C_BOOL))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_BOOL(op1_insn->val.b && op2_insn->val.b);
}
IR_FOLD(AND(C_U8, C_U8))
IR_FOLD(AND(C_CHAR, C_CHAR))
IR_FOLD(AND(C_I8, C_I8))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_U(op1_insn->val.u8 & op2_insn->val.u8);
}
IR_FOLD(AND(C_U8, C_U8))
IR_FOLD(AND(C_U16, C_U16))
IR_FOLD(AND(C_I16, C_I16))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_U(op1_insn->val.u16 & op2_insn->val.u16);
}
IR_FOLD(AND(C_U32, C_U32))
IR_FOLD(AND(C_I32, C_I32))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_U(op1_insn->val.u32 & op2_insn->val.u32);
}
IR_FOLD(AND(C_U64, C_U64))
IR_FOLD(AND(C_I64, C_I64))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_U(op1_insn->val.u64 & op2_insn->val.u64);
}
IR_FOLD(AND(C_I8, C_I8))
IR_FOLD(AND(C_I16, C_I16))
IR_FOLD(AND(C_I32, C_I32))
IR_FOLD(AND(C_I64, C_I64))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_I(op1_insn->val.i64 & op2_insn->val.i64);
}
IR_FOLD(XOR(C_BOOL, C_BOOL))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
@@ -691,55 +686,90 @@ IR_FOLD(XOR(C_BOOL, C_BOOL))
IR_FOLD(XOR(C_U8, C_U8))
IR_FOLD(XOR(C_CHAR, C_CHAR))
IR_FOLD(XOR(C_I8, C_I8))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_U(op1_insn->val.u8 ^ op2_insn->val.u8);
}
IR_FOLD(XOR(C_I8, C_I8))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_I(op1_insn->val.i8 ^ op2_insn->val.i8);
}
IR_FOLD(XOR(C_U16, C_U16))
IR_FOLD(XOR(C_I16, C_I16))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_U(op1_insn->val.u16 ^ op2_insn->val.u16);
}
IR_FOLD(XOR(C_I16, C_I16))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_I(op1_insn->val.i16 ^ op2_insn->val.i16);
}
IR_FOLD(XOR(C_U32, C_U32))
IR_FOLD(XOR(C_I32, C_I32))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_U(op1_insn->val.u32 ^ op2_insn->val.u32);
}
IR_FOLD(XOR(C_I32, C_I32))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_I(op1_insn->val.i32 ^ op2_insn->val.i32);
}
IR_FOLD(XOR(C_U64, C_U64))
IR_FOLD(XOR(C_I64, C_I64))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_U(op1_insn->val.u64 ^ op2_insn->val.u64);
}
IR_FOLD(XOR(C_I64, C_I64))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_I(op1_insn->val.i64 ^ op2_insn->val.i64);
}
IR_FOLD(SHL(C_U8, C_U8))
IR_FOLD(SHL(C_CHAR, C_CHAR))
IR_FOLD(SHL(C_I8, C_I8))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_U(op1_insn->val.u8 << op2_insn->val.u8);
}
IR_FOLD(SHL(C_I8, C_I8))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_I(op1_insn->val.i8 << op2_insn->val.i8);
}
IR_FOLD(SHL(C_U16, C_U16))
IR_FOLD(SHL(C_I16, C_I16))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_U(op1_insn->val.u16 << op2_insn->val.u16);
}
IR_FOLD(SHL(C_I16, C_I16))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_I(op1_insn->val.i16 << op2_insn->val.i16);
}
IR_FOLD(SHL(C_U32, C_U32))
IR_FOLD(SHL(C_I32, C_I32))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_U(op1_insn->val.u32 << op2_insn->val.u32);
}
IR_FOLD(SHL(C_I32, C_I32))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_I(op1_insn->val.i32 << op2_insn->val.i32);
}
IR_FOLD(SHL(C_U64, C_U64))
IR_FOLD(SHL(C_I64, C_I64))
{
@@ -749,26 +779,41 @@ IR_FOLD(SHL(C_I64, C_I64))
IR_FOLD(SHR(C_U8, C_U8))
IR_FOLD(SHR(C_CHAR, C_CHAR))
IR_FOLD(SHR(C_I8, C_I8))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_U(op1_insn->val.u8 >> op2_insn->val.u8);
}
IR_FOLD(SHR(C_I8, C_I8))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_I((int8_t)(op1_insn->val.u8 >> op2_insn->val.u8));
}
IR_FOLD(SHR(C_U16, C_U16))
IR_FOLD(SHR(C_I16, C_I16))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_U(op1_insn->val.u16 >> op2_insn->val.u16);
}
IR_FOLD(SHR(C_I16, C_I16))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_U((int16_t)(op1_insn->val.u16 >> op2_insn->val.u16));
}
IR_FOLD(SHR(C_U32, C_U32))
IR_FOLD(SHR(C_I32, C_I32))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_U(op1_insn->val.u32 >> op2_insn->val.u32);
}
IR_FOLD(SHR(C_I32, C_I32))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_U((int32_t)(op1_insn->val.u32 >> op2_insn->val.u32));
}
IR_FOLD(SHR(C_U64, C_U64))
IR_FOLD(SHR(C_I64, C_I64))
{
@@ -778,6 +823,11 @@ IR_FOLD(SHR(C_I64, C_I64))
IR_FOLD(SAR(C_U8, C_U8))
IR_FOLD(SAR(C_CHAR, C_CHAR))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_U((uint8_t)(op1_insn->val.i8 >> op2_insn->val.i8));
}
IR_FOLD(SAR(C_I8, C_I8))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
@@ -785,6 +835,11 @@ IR_FOLD(SAR(C_I8, C_I8))
}
IR_FOLD(SAR(C_U16, C_U16))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_U((uint16_t)(op1_insn->val.i16 >> op2_insn->val.i16));
}
IR_FOLD(SAR(C_I16, C_I16))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
@@ -792,6 +847,11 @@ IR_FOLD(SAR(C_I16, C_I16))
}
IR_FOLD(SAR(C_U32, C_U32))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_U((uint32_t)(op1_insn->val.i32 >> op2_insn->val.i32));
}
IR_FOLD(SAR(C_I32, C_I32))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
@@ -807,26 +867,41 @@ IR_FOLD(SAR(C_I64, C_I64))
IR_FOLD(ROL(C_U8, C_U8))
IR_FOLD(ROL(C_CHAR, C_CHAR))
IR_FOLD(ROL(C_I8, C_I8))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_U(ir_rol8(op1_insn->val.u8, op2_insn->val.u8));
}
IR_FOLD(ROL(C_I8, C_I8))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_I((int8_t)ir_rol8(op1_insn->val.u8, op2_insn->val.u8));
}
IR_FOLD(ROL(C_U16, C_U16))
IR_FOLD(ROL(C_I16, C_I16))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_U(ir_rol16(op1_insn->val.u16, op2_insn->val.u16));
}
IR_FOLD(ROL(C_I16, C_I16))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_I((int16_t)ir_rol16(op1_insn->val.u16, op2_insn->val.u16));
}
IR_FOLD(ROL(C_U32, C_U32))
IR_FOLD(ROL(C_I32, C_I32))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_U(ir_rol32(op1_insn->val.u32, op2_insn->val.u32));
}
IR_FOLD(ROL(C_I32, C_I32))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_I((int32_t)ir_rol32(op1_insn->val.u32, op2_insn->val.u32));
}
IR_FOLD(ROL(C_U64, C_U64))
IR_FOLD(ROL(C_I64, C_I64))
{
@@ -836,26 +911,41 @@ IR_FOLD(ROL(C_I64, C_I64))
IR_FOLD(ROR(C_U8, C_U8))
IR_FOLD(ROR(C_CHAR, C_CHAR))
IR_FOLD(ROR(C_I8, C_I8))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_U(ir_ror8(op1_insn->val.u8, op2_insn->val.u8));
}
IR_FOLD(ROR(C_I8, C_I8))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_I((int8_t)ir_ror8(op1_insn->val.u8, op2_insn->val.u8));
}
IR_FOLD(ROR(C_U16, C_U16))
IR_FOLD(ROR(C_I16, C_I16))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_U(ir_ror16(op1_insn->val.u16, op2_insn->val.u16));
}
IR_FOLD(ROR(C_I16, C_I16))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_I((int16_t)ir_ror16(op1_insn->val.u16, op2_insn->val.u16));
}
IR_FOLD(ROR(C_U32, C_U32))
IR_FOLD(ROR(C_I32, C_I32))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_U(ir_ror32(op1_insn->val.u32, op2_insn->val.u32));
}
IR_FOLD(ROR(C_I32, C_I32))
{
IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type);
IR_FOLD_CONST_I((int32_t)ir_ror32(op1_insn->val.u32, op2_insn->val.u32));
}
IR_FOLD(ROR(C_U64, C_U64))
IR_FOLD(ROR(C_I64, C_I64))
{
@@ -1020,6 +1110,8 @@ IR_FOLD(BITCAST(C_ADDR))
switch (IR_OPT_TYPE(opt)) {
default:
IR_ASSERT(0);
case IR_BOOL:
IR_FOLD_BOOL(op1_insn->val.i8 != 0);
case IR_I8:
IR_FOLD_CONST_I(op1_insn->val.i8);
case IR_I16:
@@ -1871,6 +1963,34 @@ IR_FOLD(ROR(C_I64, _))
IR_FOLD_NEXT;
}
IR_FOLD(LT(ABS, C_I8))
IR_FOLD(LT(ABS, C_I16))
IR_FOLD(LT(ABS, C_I32))
IR_FOLD(LT(ABS, C_I64))
IR_FOLD(LT(ABS, C_FLOAT))
IR_FOLD(LT(ABS, C_DOUBLE))
{
if (op2_insn->val.u64 == 0) {
/* abs() < 0 => false */
IR_FOLD_COPY(IR_FALSE);
}
IR_FOLD_NEXT;
}
IR_FOLD(GE(ABS, C_I8))
IR_FOLD(GE(ABS, C_I16))
IR_FOLD(GE(ABS, C_I32))
IR_FOLD(GE(ABS, C_I64))
IR_FOLD(GE(ABS, C_FLOAT))
IR_FOLD(GE(ABS, C_DOUBLE))
{
if (op2_insn->val.u64 == 0) {
/* abs() >= 0 => true */
IR_FOLD_COPY(IR_TRUE);
}
IR_FOLD_NEXT;
}
// TODO: conversions
// TODO: Reassociation

View File

@@ -16,7 +16,6 @@
# include <sys/types.h>
# include <sys/sysctl.h>
# include <sys/user.h>
# include <libutil.h>
#endif
#include "ir.h"
@@ -562,6 +561,22 @@ void ir_gdb_unregister_all(void)
}
}
#if defined(__FreeBSD__)
static bool ir_gdb_info_proc(pid_t pid, struct kinfo_proc *proc)
{
size_t len, plen;
len = plen = sizeof(*proc);
int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid};
if (sysctl(mib, 4, proc, &len, NULL, 0) < 0 || len != plen ||
proc->ki_structsize != (int)plen || proc->ki_pid != pid) {
return false;
}
return true;
}
#endif
bool ir_gdb_present(void)
{
bool ret = 0;
@@ -598,13 +613,13 @@ bool ir_gdb_present(void)
close(fd);
}
#elif defined(__FreeBSD__)
struct kinfo_proc *proc = kinfo_getproc(getpid());
struct kinfo_proc proc, dbg;
if (proc) {
if ((proc->ki_flag & P_TRACED) != 0) {
struct kinfo_proc *dbg = kinfo_getproc(proc->ki_tracer);
ret = (dbg && strstr(dbg->ki_comm, "gdb"));
if (ir_gdb_info_proc(getpid(), &proc)) {
if ((proc.ki_flag & P_TRACED) != 0) {
if (ir_gdb_info_proc(proc.ki_tracer, &dbg)) {
ret = strstr(dbg.ki_comm, "gdb");
}
}
}
#endif

View File

@@ -3174,7 +3174,6 @@ try_next_available_register:
/* split any inactive interval for reg at the end of its lifetime hole */
other = *inactive;
prev = NULL;
while (other) {
/* freeUntilPos[it.reg] = next intersection of it with current */
if (reg == other->reg) {
@@ -3187,17 +3186,12 @@ try_next_available_register:
IR_LOG_LSRA_CONFLICT(" ---- Conflict with inactive", other, overlap);
// TODO: optimal split position (this case is not tested)
child = ir_split_interval_at(ctx, other, overlap);
if (prev) {
prev->list_next = other = other->list_next;
} else {
*inactive = other = other->list_next;
}
/* reset range cache */
other->current_range = &other->range;
ir_add_to_unhandled(unhandled, child);
IR_LOG_LSRA(" ---- Queue", child, "");
continue;
}
}
prev = other;
other = other->list_next;
}
@@ -3277,6 +3271,7 @@ static bool ir_ival_spill_for_fuse_load(ir_ctx *ctx, ir_live_interval *ival, ir_
} else if (ival->flags & IR_LIVE_INTERVAL_MEM_LOAD) {
insn = &ctx->ir_base[IR_LIVE_POS_TO_REF(use_pos->pos)];
IR_ASSERT(insn->op == IR_VLOAD);
IR_ASSERT(ctx->ir_base[insn->op2].op == IR_VAR);
use_pos = use_pos->next;
if (use_pos && (use_pos->next || (use_pos->flags & IR_USE_MUST_BE_IN_REG))) {
return 0;
@@ -3287,9 +3282,21 @@ static bool ir_ival_spill_for_fuse_load(ir_ctx *ctx, ir_live_interval *ival, ir_
if (bb->loop_depth && bb != ir_block_from_live_pos(ctx, ival->use_pos->pos)) {
return 0;
}
/* check if VAR may be clobbered between VLOAD and use */
ir_use_list *use_list = &ctx->use_lists[insn->op2];
ir_ref n = use_list->count;
ir_ref *p = &ctx->use_edges[use_list->refs];
for (; n > 0; p++, n--) {
ir_ref use = *p;
if (ctx->ir_base[use].op == IR_VSTORE) {
if (use > IR_LIVE_POS_TO_REF(ival->use_pos->pos) && use < IR_LIVE_POS_TO_REF(use_pos->pos)) {
return 0;
}
} else if (ctx->ir_base[use].op == IR_VADDR) {
return 0;
}
}
}
IR_ASSERT(ctx->ir_base[insn->op2].op == IR_VAR);
ival->stack_spill_pos = ctx->ir_base[insn->op2].op3;
return 1;

View File

@@ -594,30 +594,40 @@ static void ir_sccp_remove_unfeasible_merge_inputs(ir_ctx *ctx, ir_insn *_values
if (input && IR_IS_FEASIBLE(input)) {
ir_insn *input_insn = &ctx->ir_base[input];
IR_ASSERT(input_insn->op == IR_END || input_insn->op == IR_IJMP || input_insn->op == IR_UNREACHABLE);
if (input_insn->op == IR_END) {
ir_ref prev, next = IR_UNUSED;
ir_insn *next_insn = NULL;
IR_ASSERT(input_insn->op == IR_END || input_insn->op == IR_LOOP_END||
input_insn->op == IR_IJMP || input_insn->op == IR_UNREACHABLE);
if (input_insn->op == IR_END || input_insn->op == IR_LOOP_END) {
if (input < ref) {
ir_ref prev, next = IR_UNUSED;
ir_insn *next_insn = NULL;
prev = input_insn->op1;
use_list = &ctx->use_lists[ref];
for (k = 0, p = &ctx->use_edges[use_list->refs]; k < use_list->count; k++, p++) {
use = *p;
use_insn = &ctx->ir_base[use];
IR_ASSERT((use_insn->op != IR_PHI) && "PHI must be already removed");
if (ir_op_flags[use_insn->op] & IR_OP_FLAG_CONTROL) {
next = use;
next_insn = use_insn;
break;
prev = input_insn->op1;
use_list = &ctx->use_lists[ref];
for (k = 0, p = &ctx->use_edges[use_list->refs]; k < use_list->count; k++, p++) {
use = *p;
use_insn = &ctx->ir_base[use];
IR_ASSERT((use_insn->op != IR_PHI) && "PHI must be already removed");
if (ir_op_flags[use_insn->op] & IR_OP_FLAG_CONTROL) {
next = use;
next_insn = use_insn;
break;
}
}
IR_ASSERT(prev && next);
/* remove MERGE and input END from double linked control list */
next_insn->op1 = prev;
ir_sccp_replace_use(ctx, prev, input, next);
/* remove MERGE and input END instructions */
ir_sccp_make_nop(ctx, ref);
ir_sccp_make_nop(ctx, input);
} else {
for (i = 2; i <= n; i++) {
ir_insn_set_op(insn, i, IR_UNUSED);
}
insn->op = IR_BEGIN;
insn->op1 = input;
input_insn->op = IR_END;
}
IR_ASSERT(prev && next);
/* remove MERGE and input END from double linked control list */
next_insn->op1 = prev;
ir_sccp_replace_use(ctx, prev, input, next);
/* remove MERGE and input END instructions */
ir_sccp_make_nop(ctx, ref);
ir_sccp_make_nop(ctx, input);
break;
} else {
for (i = 2; i <= n; i++) {

View File

@@ -23,6 +23,7 @@ static uint32_t ir_str_hash(const char *str, size_t len)
for (i = 0; i < len; i++) {
h = ((h << 5) + h) + *str;
str++;
}
return h | 0x10000000;
}

View File

@@ -724,7 +724,15 @@ op2_const:
break;
case IR_LOAD_FP:
case IR_LOAD_INT:
case IR_MEM_OP_INT:
case IR_MEM_INC:
case IR_MEM_DEC:
case IR_MEM_MUL_PWR2:
case IR_MEM_DIV_PWR2:
case IR_MEM_MOD_PWR2:
case IR_MEM_BINOP_INT:
case IR_MEM_SHIFT:
case IR_MEM_SHIFT_CONST:
flags = IR_USE_MUST_BE_IN_REG | IR_OP2_MUST_BE_IN_REG;
insn = &ctx->ir_base[ref];
if (IR_IS_CONST_REF(insn->op2)) {
@@ -1072,30 +1080,30 @@ static uint32_t ir_match_insn(ir_ctx *ctx, ir_ref ref)
&& insn->op1 == ref - 1) { /* previous instruction */
ir_insn *op1_insn = &ctx->ir_base[insn->op1];
if (op1_insn->op == IR_ADD ||
op1_insn->op == IR_SUB ||
// op1_insn->op == IR_MUL ||
op1_insn->op == IR_OR ||
op1_insn->op == IR_AND ||
op1_insn->op == IR_XOR) {
if (op1_insn->op == IR_AND && ctx->use_lists[insn->op1].count == 1) {
/* v = AND(_, _); CMP(v, 0) => SKIP_TEST; TEST */
if (ir_op_flags[op1_insn->op] & IR_OP_FLAG_COMMUTATIVE) {
ir_match_fuse_load_commutative_int(ctx, op1_insn, ref);
} else {
ir_match_fuse_load(ctx, op1_insn->op2, ref);
}
if (op1_insn->op == IR_AND && ctx->use_lists[insn->op1].count == 1) {
/* v = AND(_, _); CMP(v, 0) => SKIP_TEST; TEST */
if (IR_IS_CONST_REF(op1_insn->op2)) {
ir_match_fuse_load(ctx, op1_insn->op1, ref);
}
ctx->rules[insn->op1] = IR_FUSED | IR_TEST_INT;
return IR_TESTCC_INT;
} else {
/* v = BINOP(_, _); CMP(v, 0) => BINOP; SETCC */
ctx->rules[insn->op1] = IR_BINOP_INT;
return IR_SETCC_INT;
if (IR_IS_CONST_REF(op1_insn->op2)) {
ir_match_fuse_load(ctx, op1_insn->op1, ref);
}
ctx->rules[insn->op1] = IR_FUSED | IR_TEST_INT;
return IR_TESTCC_INT;
} else if ((op1_insn->op == IR_OR || op1_insn->op == IR_AND || op1_insn->op == IR_XOR) ||
/* GT(ADD(_, _), 0) can't be optimized because ADD may overflow */
((op1_insn->op == IR_ADD || op1_insn->op == IR_SUB) &&
(insn->op == IR_EQ || insn->op == IR_NE))) {
/* v = BINOP(_, _); CMP(v, 0) => BINOP; SETCC */
if (ir_op_flags[op1_insn->op] & IR_OP_FLAG_COMMUTATIVE) {
ir_match_fuse_load_commutative_int(ctx, op1_insn, ref);
} else {
ir_match_fuse_load(ctx, op1_insn->op2, ref);
}
ctx->rules[insn->op1] = IR_BINOP_INT;
return IR_SETCC_INT;
}
}
ir_match_fuse_load_cmp_int(ctx, insn, ref);
@@ -1703,32 +1711,32 @@ store_int:
&& op2_insn->op1 == insn->op2 - 1) { /* previous instruction */
ir_insn *op1_insn = &ctx->ir_base[op2_insn->op1];
if (op1_insn->op == IR_ADD ||
op1_insn->op == IR_SUB ||
// op1_insn->op == IR_MUL ||
op1_insn->op == IR_OR ||
op1_insn->op == IR_AND ||
op1_insn->op == IR_XOR) {
if (op1_insn->op == IR_AND && ctx->use_lists[op2_insn->op1].count == 1) {
/* v = AND(_, _); c = CMP(v, 0) ... IF(c) => SKIP_TEST; SKIP ... TEST_AND_BRANCH */
if (ir_op_flags[op1_insn->op] & IR_OP_FLAG_COMMUTATIVE) {
ir_match_fuse_load_commutative_int(ctx, op1_insn, ref);
} else {
ir_match_fuse_load(ctx, op1_insn->op2, ref);
}
if (op1_insn->op == IR_AND && ctx->use_lists[op2_insn->op1].count == 1) {
/* v = AND(_, _); c = CMP(v, 0) ... IF(c) => SKIP_TEST; SKIP ... TEST_AND_BRANCH */
if (IR_IS_CONST_REF(op1_insn->op2)) {
ir_match_fuse_load(ctx, op1_insn->op1, ref);
}
ctx->rules[op2_insn->op1] = IR_FUSED | IR_TEST_INT;
ctx->rules[insn->op2] = IR_FUSED | IR_SIMPLE | IR_NOP;
return IR_TEST_AND_BRANCH_INT;
} else {
/* v = BINOP(_, _); c = CMP(v, 0) ... IF(c) => BINOP; SKIP_CMP ... JCC */
ctx->rules[op2_insn->op1] = IR_BINOP_INT;
ctx->rules[insn->op2] = IR_FUSED | IR_CMP_INT;
return IR_JCC_INT;
if (IR_IS_CONST_REF(op1_insn->op2)) {
ir_match_fuse_load(ctx, op1_insn->op1, ref);
}
ctx->rules[op2_insn->op1] = IR_FUSED | IR_TEST_INT;
ctx->rules[insn->op2] = IR_FUSED | IR_SIMPLE | IR_NOP;
return IR_TEST_AND_BRANCH_INT;
} else if ((op1_insn->op == IR_OR || op1_insn->op == IR_AND || op1_insn->op == IR_XOR) ||
/* GT(ADD(_, _), 0) can't be optimized because ADD may overflow */
((op1_insn->op == IR_ADD || op1_insn->op == IR_SUB) &&
(op2_insn->op == IR_EQ || op2_insn->op == IR_NE))) {
/* v = BINOP(_, _); c = CMP(v, 0) ... IF(c) => BINOP; SKIP_CMP ... JCC */
if (ir_op_flags[op1_insn->op] & IR_OP_FLAG_COMMUTATIVE) {
ir_match_fuse_load_commutative_int(ctx, op1_insn, ref);
} else {
ir_match_fuse_load(ctx, op1_insn->op2, ref);
}
ctx->rules[op2_insn->op1] = IR_BINOP_INT;
ctx->rules[insn->op2] = IR_FUSED | IR_CMP_INT;
return IR_JCC_INT;
}
}
/* c = CMP(_, _) ... IF(c) => SKIP_CMP ... CMP_AND_BRANCH */
@@ -1844,13 +1852,10 @@ store_int:
if (op2_insn->op1 == insn->op2 - 1) { /* previous instruction */
ir_insn *op1_insn = &ctx->ir_base[op2_insn->op1];
if (op1_insn->op == IR_ADD ||
op1_insn->op == IR_SUB ||
// op1_insn->op == IR_MUL ||
op1_insn->op == IR_OR ||
op1_insn->op == IR_AND ||
op1_insn->op == IR_XOR) {
if ((op1_insn->op == IR_OR || op1_insn->op == IR_AND || op1_insn->op == IR_XOR) ||
/* GT(ADD(_, _), 0) can't be optimized because ADD may overflow */
((op1_insn->op == IR_ADD || op1_insn->op == IR_SUB) &&
(op2_insn->op == IR_EQ || op2_insn->op == IR_NE))) {
if (ir_op_flags[op1_insn->op] & IR_OP_FLAG_COMMUTATIVE) {
ir_match_fuse_load_commutative_int(ctx, op1_insn, ref);
} else {
@@ -1870,12 +1875,10 @@ store_int:
if (store_insn->op == IR_STORE && store_insn->op3 == op2_insn->op1) {
ir_insn *op_insn = &ctx->ir_base[op2_insn->op1];
if (op_insn->op == IR_ADD ||
op_insn->op == IR_SUB ||
// op_insn->op == IR_MUL ||
op_insn->op == IR_OR ||
op_insn->op == IR_AND ||
op_insn->op == IR_XOR) {
if ((op_insn->op == IR_OR || op_insn->op == IR_AND || op_insn->op == IR_XOR) ||
/* GT(ADD(_, _), 0) can't be optimized because ADD may overflow */
((op_insn->op == IR_ADD || op_insn->op == IR_SUB) &&
(op2_insn->op == IR_EQ || op2_insn->op == IR_NE))) {
if (ctx->ir_base[op_insn->op1].op == IR_LOAD
&& ctx->ir_base[op_insn->op1].op2 == store_insn->op2) {
if (ir_in_same_block(ctx, op_insn->op1)
@@ -6428,7 +6431,7 @@ static void ir_emit_alloca(ir_ctx *ctx, ir_ref def, ir_insn *insn)
IR_ASSERT(IR_IS_TYPE_INT(val->type));
IR_ASSERT(!IR_IS_SYM_CONST(val->op));
IR_ASSERT(IR_IS_TYPE_UNSIGNED(val->type) || val->val.i64 > 0);
IR_ASSERT(IR_IS_TYPE_UNSIGNED(val->type) || val->val.i64 >= 0);
IR_ASSERT(IR_IS_SIGNED_32BIT(val->val.i64));
if (ctx->flags2 & IR_HAS_CALLS) {