Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions ir_aarch64.dasc
Original file line number Diff line number Diff line change
Expand Up @@ -3490,14 +3490,14 @@ static void ir_emit_cond(ir_ctx *ctx, ir_ref def, ir_insn *insn)
op3_reg = op2_reg;
}
}
if (op3 != op2 && IR_REG_SPILLED(op3_reg)) {
if (IR_REG_SPILLED(op3_reg)) {
op3_reg = IR_REG_NUM(op3_reg);
ir_emit_load(ctx, type, op3_reg, op3);
if (op1 == op2) {
if (op1 == op3) {
op1_reg = op3_reg;
}
}
if (op1 != op2 && op1 != op3 && IR_REG_SPILLED(op1_reg)) {
if (IR_REG_SPILLED(op1_reg)) {
op1_reg = IR_REG_NUM(op1_reg);
ir_emit_load(ctx, op1_type, op1_reg, op1);
}
Expand Down
79 changes: 79 additions & 0 deletions ir_fold.h
Original file line number Diff line number Diff line change
Expand Up @@ -3439,5 +3439,84 @@ IR_FOLD(COND(_, _)) // TODO: COND(_, _, _)
if (op2 == op3) {
IR_FOLD_COPY(op2);
}

if (op1_insn->type == IR_BOOL) {
if (op2 == IR_TRUE) {
if (op3 == IR_FALSE) {
/* a ? true : false => a */
IR_FOLD_COPY(op1);
} else {
/* a ? true : b => a | b */
opt = IR_OPT(IR_OR, IR_BOOL);
op2 = op3;
op3 = IR_UNUSED;
IR_FOLD_RESTART;
}
} else if (op3 == IR_FALSE) {
/* a ? b : false => a & b */
opt = IR_OPT(IR_AND, IR_BOOL);
op3 = IR_UNUSED;
IR_FOLD_RESTART;
} else if (op2 == IR_FALSE) {
if (op3 == IR_TRUE) {
/* a ? flase : true => !a */
opt = IR_OPT(IR_NOT, IR_BOOL);
op2 = IR_UNUSED;
op3 = IR_UNUSED;
IR_FOLD_RESTART;
}
} else if (IR_IS_TYPE_INT(IR_OPT_TYPE(opt))
&& IR_IS_CONST_REF(op2)
&& IR_IS_CONST_REF(op3)
&& op2_insn->val.u64 == 1
&& op3_insn->val.u64 == 0) {
if (ir_type_size[IR_OPT_TYPE(opt)] > 1) {
/* a ? 1 : 0 => ZEXT(a) */
opt = IR_OPT(IR_ZEXT, IR_OPT_TYPE(opt));
} else {
/* a ? 1 : 0 => BITCAST(a) */
opt = IR_OPT(IR_BITCAST, IR_OPT_TYPE(opt));
}
op2 = IR_UNUSED;
op3 = IR_UNUSED;
IR_FOLD_RESTART;
}
} else if (IR_IS_TYPE_INT(op1_insn->type)) {
if (op2 == IR_TRUE) {
if (op3 == IR_FALSE) {
opt = IR_OPT(IR_NE, IR_BOOL);
val.u64 = 0;
op2 = ir_const(ctx, val, op1_insn->type);
op3 = IR_UNUSED;
IR_FOLD_RESTART;
}
} else if (op2 == IR_FALSE) {
if (op3 == IR_TRUE) {
opt = IR_OPT(IR_EQ, IR_BOOL);
val.u64 = 0;
op2 = ir_const(ctx, val, op1_insn->type);
op3 = IR_UNUSED;
IR_FOLD_RESTART;
}
}
}

if (op1_insn->op == IR_NE) {
if (IR_IS_CONST_REF(op1_insn->op2)
&& IR_IS_TYPE_INT(ctx->ir_base[op1_insn->op2].type)
&& ctx->ir_base[op1_insn->op2].val.u64 == 0) {
op1 = op1_insn->op1;
IR_FOLD_RESTART;
}
} else if (op1_insn->op == IR_EQ) {
if (IR_IS_CONST_REF(op1_insn->op2)
&& IR_IS_TYPE_INT(ctx->ir_base[op1_insn->op2].type)
&& ctx->ir_base[op1_insn->op2].val.u64 == 0) {
op1 = op1_insn->op1;
SWAP_REFS(op2, op3);
IR_FOLD_RESTART;
}
}

IR_FOLD_NEXT;
}
19 changes: 13 additions & 6 deletions ir_sccp.c
Original file line number Diff line number Diff line change
Expand Up @@ -2470,7 +2470,7 @@ static bool ir_optimize_phi(ir_ctx *ctx, ir_ref merge_ref, ir_insn *merge, ir_re
ir_ref root_ref = start1->op1;
ir_insn *root = &ctx->ir_base[root_ref];

if (root->op == IR_IF && !IR_IS_CONST_REF(root->op2) && ctx->use_lists[root->op2].count == 1) {
if (root->op == IR_IF && !IR_IS_CONST_REF(root->op2)) {
ir_ref cond_ref = root->op2;
ir_insn *cond = &ctx->ir_base[cond_ref];
ir_type type = insn->type;
Expand Down Expand Up @@ -2550,7 +2550,11 @@ static bool ir_optimize_phi(ir_ctx *ctx, ir_ref merge_ref, ir_insn *merge, ir_re
ir_use_list_remove_all(ctx, insn->op2, cond_ref);
}

MAKE_NOP(cond); CLEAR_USES(cond_ref);
if (ctx->use_lists[cond_ref].count == 1) {
MAKE_NOP(cond); CLEAR_USES(cond_ref);
} else {
ir_use_list_remove_one(ctx, cond_ref, root_ref);
}
MAKE_NOP(root); CLEAR_USES(root_ref);
MAKE_NOP(start1); CLEAR_USES(start1_ref);
MAKE_NOP(start2); CLEAR_USES(start2_ref);
Expand Down Expand Up @@ -2636,7 +2640,11 @@ static bool ir_optimize_phi(ir_ctx *ctx, ir_ref merge_ref, ir_insn *merge, ir_re
ir_use_list_remove_all(ctx, insn->op1, cond_ref);
}

MAKE_NOP(cond); CLEAR_USES(cond_ref);
if (ctx->use_lists[cond_ref].count == 1) {
MAKE_NOP(cond); CLEAR_USES(cond_ref);
} else {
ir_use_list_remove_one(ctx, cond_ref, root_ref);
}
MAKE_NOP(root); CLEAR_USES(root_ref);
MAKE_NOP(start1); CLEAR_USES(start1_ref);
MAKE_NOP(start2); CLEAR_USES(start2_ref);
Expand All @@ -2650,8 +2658,7 @@ static bool ir_optimize_phi(ir_ctx *ctx, ir_ref merge_ref, ir_insn *merge, ir_re
}

return 1;
#if 0
} else {
} else if (cond->op != IR_OVERFLOW && insn->op2 <= cond_ref && insn->op3 <= cond_ref) {
/* COND
*
* prev prev
Expand Down Expand Up @@ -2705,12 +2712,12 @@ static bool ir_optimize_phi(ir_ctx *ctx, ir_ref merge_ref, ir_insn *merge, ir_re
MAKE_NOP(end2); CLEAR_USES(end2_ref);
MAKE_NOP(merge); CLEAR_USES(merge_ref);

ir_bitqueue_add(worklist, ref);
if (ctx->ir_base[next->op1].op == IR_BEGIN || ctx->ir_base[next->op1].op == IR_MERGE) {
ir_bitqueue_add(worklist, next->op1);
}

return 1;
#endif
}
}
}
Expand Down
159 changes: 137 additions & 22 deletions ir_x86.dasc
Original file line number Diff line number Diff line change
Expand Up @@ -1167,6 +1167,7 @@ const ir_call_conv_dsc ir_call_conv_x86_fastcall = {
_(CMP_AND_BRANCH_FP) \
_(TEST_AND_BRANCH_INT) \
_(JCC_INT) \
_(COND_TEST_INT) \
_(COND_CMP_INT) \
_(COND_CMP_FP) \
_(GUARD_CMP_INT) \
Expand Down Expand Up @@ -1405,6 +1406,7 @@ op2_const:
}
IR_FALLTHROUGH;
case IR_COND_CMP_INT:
case IR_COND_TEST_INT:
insn = &ctx->ir_base[ref];
if (IR_IS_TYPE_INT(insn->type)) {
if (IR_IS_CONST_REF(insn->op3) || ir_rule(ctx, insn->op3) == IR_STATIC_ALLOCA) {
Expand Down Expand Up @@ -3060,8 +3062,16 @@ store_int:
ctx->rules[insn->op1] = IR_FUSED | IR_CMP_FP;
return IR_COND_CMP_FP;
}
} else if (op1_insn->op == IR_AND) {
/* c = AND(_, _) ... IF(c) => SKIP_TEST ... TEST_AND_BRANCH */
ir_match_fuse_load_test_int(ctx, op1_insn, ref);
ctx->rules[insn->op1] = IR_FUSED | IR_TEST_INT;
return IR_COND_TEST_INT;
}
}
if (IR_IS_TYPE_INT(ctx->ir_base[insn->op1].type)) {
ir_match_fuse_load(ctx, insn->op1, ref);
}
return IR_COND;
case IR_GUARD:
case IR_GUARD_NOT:
Expand Down Expand Up @@ -6812,37 +6822,24 @@ static void ir_emit_cond(ir_ctx *ctx, ir_ref def, ir_insn *insn)

IR_ASSERT(def_reg != IR_REG_NONE);

if (op2 != op3) {
if (op2_reg != IR_REG_NONE && IR_REG_SPILLED(op2_reg)) {
op2_reg = IR_REG_NUM(op2_reg);
ir_emit_load(ctx, type, op2_reg, op2);
if (op1 == op2) {
op1_reg = op2_reg;
}
}
if (op3_reg != IR_REG_NONE && IR_REG_SPILLED(op3_reg)) {
op3_reg = IR_REG_NUM(op3_reg);
ir_emit_load(ctx, type, op3_reg, op3);
if (op1 == op2) {
op1_reg = op3_reg;
}
}
} else if (op2_reg != IR_REG_NONE && IR_REG_SPILLED(op2_reg)) {
if (op2_reg != IR_REG_NONE && IR_REG_SPILLED(op2_reg)) {
op2_reg = IR_REG_NUM(op2_reg);
ir_emit_load(ctx, type, op2_reg, op2);
op3_reg = op2_reg;
if (op1 == op2) {
op1_reg = op2_reg;
}
} else if (op3_reg != IR_REG_NONE && IR_REG_SPILLED(op3_reg)) {
if (op3 == op2) {
op3_reg = op2_reg;
}
}
if (op3_reg != IR_REG_NONE && IR_REG_SPILLED(op3_reg)) {
op3_reg = IR_REG_NUM(op3_reg);
ir_emit_load(ctx, type, op3_reg, op3);
op2_reg = op3_reg;
if (op1 == op3) {
op1_reg = op3_reg;
op1_reg = op2_reg;
}
}
if (op1_reg != IR_REG_NONE && op1 != op2 && op1 != op3 && IR_REG_SPILLED(op1_reg)) {
if (op1_reg != IR_REG_NONE && IR_REG_SPILLED(op1_reg)) {
op1_reg = IR_REG_NUM(op1_reg);
ir_emit_load(ctx, op1_type, op1_reg, op1);
}
Expand All @@ -6851,7 +6848,13 @@ static void ir_emit_cond(ir_ctx *ctx, ir_ref def, ir_insn *insn)
if (op1_reg != IR_REG_NONE) {
| ASM_REG_REG_OP test, op1_type, op1_reg, op1_reg
} else {
ir_mem mem = ir_ref_spill_slot(ctx, op1);
ir_mem mem;

if (ir_rule(ctx, insn->op1) & IR_FUSED) {
mem = ir_fuse_load(ctx, def, insn->op1);
} else {
mem = ir_ref_spill_slot(ctx, insn->op1);
}

| ASM_MEM_IMM_OP cmp, op1_type, mem, 0
}
Expand Down Expand Up @@ -6941,6 +6944,115 @@ static void ir_emit_cond(ir_ctx *ctx, ir_ref def, ir_insn *insn)
}
}

static void ir_emit_cond_test_int(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 op2 = insn->op2;
ir_ref op3 = insn->op3;
ir_reg def_reg = IR_REG_NUM(ctx->regs[def][0]);
ir_reg op2_reg = ctx->regs[def][2];
ir_reg op3_reg = ctx->regs[def][3];

if (op2 != op3) {
if (op2_reg != IR_REG_NONE && IR_REG_SPILLED(op2_reg)) {
op2_reg = IR_REG_NUM(op2_reg);
ir_emit_load(ctx, type, op2_reg, op2);
}
if (op3_reg != IR_REG_NONE && IR_REG_SPILLED(op3_reg)) {
op3_reg = IR_REG_NUM(op3_reg);
ir_emit_load(ctx, type, op3_reg, op3);
}
} else if (op2_reg != IR_REG_NONE && IR_REG_SPILLED(op2_reg)) {
op2_reg = IR_REG_NUM(op2_reg);
ir_emit_load(ctx, type, op2_reg, op2);
op3_reg = op2_reg;
} else if (op3_reg != IR_REG_NONE && IR_REG_SPILLED(op3_reg)) {
op3_reg = IR_REG_NUM(op3_reg);
ir_emit_load(ctx, type, op3_reg, op3);
op2_reg = op3_reg;
}

ir_emit_test_int_common(ctx, def, insn->op1, IR_NE);

if (IR_IS_TYPE_INT(type)) {
bool eq = 0;

if (op3_reg != IR_REG_NONE) {
if (op3_reg == def_reg) {
IR_ASSERT(op2_reg != IR_REG_NONE);
op3_reg = op2_reg;
eq = 1; // reverse
} else {
if (op2_reg != IR_REG_NONE) {
if (def_reg != op2_reg) {
// if (IR_IS_TYPE_INT(type)) {
ir_emit_mov(ctx, type, def_reg, op2_reg);
// } else {
// ir_emit_fp_mov(ctx, type, def_reg, op2_reg);
// }
}
} else if (IR_IS_CONST_REF(op2) && !IR_IS_SYM_CONST(ctx->ir_base[op2].op)) {
/* prevent "xor" and flags clobbering */
ir_emit_mov_imm_int(ctx, type, def_reg, ctx->ir_base[op2].val.i64);
} else {
ir_emit_load_ex(ctx, type, def_reg, op2, def);
}
}
} else {
IR_ASSERT(op2_reg != IR_REG_NONE && op2_reg != def_reg);
if (IR_IS_CONST_REF(op3) && !IR_IS_SYM_CONST(ctx->ir_base[op3].op)) {
/* prevent "xor" and flags clobbering */
ir_emit_mov_imm_int(ctx, type, def_reg, ctx->ir_base[op3].val.i64);
} else {
ir_emit_load_ex(ctx, type, def_reg, op3, def);
}
op3_reg = op2_reg;
eq = 1; // reverse
}

if (eq) {
| ASM_REG_REG_OP2 cmovne, type, def_reg, op3_reg
} else {
| ASM_REG_REG_OP2 cmove, type, def_reg, op3_reg
}
} else {
| jne >2
|1:

if (op2_reg != IR_REG_NONE) {
if (def_reg != op2_reg) {
if (IR_IS_TYPE_INT(type)) {
ir_emit_mov(ctx, type, def_reg, op2_reg);
} else {
ir_emit_fp_mov(ctx, type, def_reg, op2_reg);
}
}
} else {
ir_emit_load_ex(ctx, type, def_reg, op2, def);
}
| jmp >3
|2:
if (op3_reg != IR_REG_NONE) {
if (def_reg != op3_reg) {
if (IR_IS_TYPE_INT(type)) {
ir_emit_mov(ctx, type, def_reg, op3_reg);
} else {
ir_emit_fp_mov(ctx, type, def_reg, op3_reg);
}
}
} else {
ir_emit_load_ex(ctx, type, def_reg, op3, def);
}
|3:
}

if (IR_REG_SPILLED(ctx->regs[def][0])) {
ir_emit_store(ctx, type, def, def_reg);
}
}

static void ir_emit_cond_cmp_int(ir_ctx *ctx, ir_ref def, ir_insn *insn)
{
ir_backend_data *data = ctx->data;
Expand Down Expand Up @@ -11798,6 +11910,9 @@ void *ir_emit_code(ir_ctx *ctx, size_t *size_ptr)
case IR_COND:
ir_emit_cond(ctx, i, insn);
break;
case IR_COND_TEST_INT:
ir_emit_cond_test_int(ctx, i, insn);
break;
case IR_COND_CMP_INT:
ir_emit_cond_cmp_int(ctx, i, insn);
break;
Expand Down
2 changes: 1 addition & 1 deletion tests/020.irt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
--TEST--
020: Translation out of SSA (Figure 1 from "Translating Out of Static Single Assignment Form" by Sreedhar)
--ARGS--
--save --dump-live-ranges --dump-cfg
-O1 --save --dump-live-ranges --dump-cfg
--CODE--
{
uintptr_t c_1 = 0;
Expand Down
2 changes: 1 addition & 1 deletion tests/Windows-x86_64/if_001.irt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
--TARGET--
Windows-x86_64
--ARGS--
-S
-O1 -S
--CODE--
{
int32_t c_1 = 0;
Expand Down
Loading