Skip to content

Commit 793ddc7

Browse files
committed
Update IR
IR commit: 0b557c0e4578cbfdbf8017f4adac335d795156dc
1 parent 7b2c67c commit 793ddc7

File tree

7 files changed

+249
-152
lines changed

7 files changed

+249
-152
lines changed

ext/opcache/jit/ir/ir_aarch64.dasc

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -700,7 +700,7 @@ static uint32_t ir_match_insn(ir_ctx *ctx, ir_ref ref)
700700
} else if (IR_IS_CONST_REF(insn->op1)) {
701701
// const
702702
} else if (op2_insn->val.i64 == 0) {
703-
return IR_COPY_INT;
703+
// return IR_COPY_INT;
704704
}
705705
}
706706
binop_int:
@@ -721,7 +721,7 @@ binop_fp:
721721
} else if (op2_insn->val.u64 == 0) {
722722
// 0
723723
} else if (op2_insn->val.u64 == 1) {
724-
return IR_COPY_INT;
724+
// return IR_COPY_INT;
725725
} else if (IR_IS_POWER_OF_TWO(op2_insn->val.u64)) {
726726
return IR_MUL_PWR2;
727727
}
@@ -747,7 +747,7 @@ binop_fp:
747747
} else if (IR_IS_CONST_REF(insn->op1)) {
748748
// const
749749
} else if (op2_insn->val.u64 == 1) {
750-
return IR_COPY_INT;
750+
// return IR_COPY_INT;
751751
} else if (IR_IS_POWER_OF_TWO(op2_insn->val.u64)) {
752752
if (IR_IS_TYPE_UNSIGNED(insn->type)) {
753753
return IR_DIV_PWR2;
@@ -798,7 +798,7 @@ binop_fp:
798798
} else if (IR_IS_CONST_REF(insn->op1)) {
799799
// const
800800
} else if (op2_insn->val.i64 == 0) {
801-
return IR_COPY_INT;
801+
// return IR_COPY_INT;
802802
} else if (op2_insn->val.i64 == -1) {
803803
// -1
804804
}
@@ -814,7 +814,7 @@ binop_fp:
814814
} else if (op2_insn->val.i64 == 0) {
815815
// 0
816816
} else if (op2_insn->val.i64 == -1) {
817-
return IR_COPY_INT;
817+
// return IR_COPY_INT;
818818
}
819819
}
820820
goto binop_int;
@@ -837,7 +837,7 @@ binop_fp:
837837
} else if (IR_IS_CONST_REF(insn->op1)) {
838838
// const
839839
} else if (op2_insn->val.u64 == 0) {
840-
return IR_COPY_INT;
840+
// return IR_COPY_INT;
841841
} else if (ir_type_size[insn->type] >= 4) {
842842
if (op2_insn->val.u64 == 1) {
843843
// lea [op1*2]
@@ -863,7 +863,7 @@ binop_fp:
863863
} else if (IR_IS_CONST_REF(insn->op1)) {
864864
// const
865865
} else if (op2_insn->val.u64 == 0) {
866-
return IR_COPY_INT;
866+
// return IR_COPY_INT;
867867
}
868868
}
869869
return IR_SHIFT_CONST;
@@ -880,11 +880,20 @@ binop_fp:
880880
// case IR_COND:
881881
case IR_COPY:
882882
if (IR_IS_TYPE_INT(insn->type)) {
883-
return IR_COPY_INT;
883+
return IR_COPY_INT | IR_MAY_REUSE;
884884
} else {
885-
return IR_COPY_FP;
885+
return IR_COPY_FP | IR_MAY_REUSE;
886886
}
887887
break;
888+
case IR_TRUNC:
889+
case IR_PROTO:
890+
return insn->op | IR_MAY_REUSE;
891+
case IR_BITCAST:
892+
if (IR_IS_TYPE_INT(insn->type) && IR_IS_TYPE_INT(ctx->ir_base[insn->op1].type)) {
893+
return insn->op | IR_MAY_REUSE;
894+
} else {
895+
return insn->op;
896+
}
888897
case IR_CALL:
889898
ctx->flags2 |= IR_HAS_CALLS;
890899
return IR_CALL;

ext/opcache/jit/ir/ir_cfg.c

Lines changed: 90 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,13 @@ static ir_ref ir_try_remove_empty_diamond(ir_ctx *ctx, ir_ref ref, ir_insn *insn
210210
}
211211
}
212212

213+
static bool ir_is_zero(ir_ctx *ctx, ir_ref ref)
214+
{
215+
return IR_IS_CONST_REF(ref)
216+
&& !IR_IS_SYM_CONST(ctx->ir_base[ref].op)
217+
&& ctx->ir_base[ref].val.u32 == 0;
218+
}
219+
213220
static ir_ref ir_optimize_phi(ir_ctx *ctx, ir_ref merge_ref, ir_insn *merge, ir_ref ref, ir_insn *insn)
214221
{
215222
IR_ASSERT(insn->inputs_count == 3);
@@ -237,11 +244,15 @@ static ir_ref ir_optimize_phi(ir_ctx *ctx, ir_ref merge_ref, ir_insn *merge, ir_
237244
if (IR_IS_TYPE_FP(type)) {
238245
is_cmp = (cond->op == IR_LT || cond->op == IR_LE || cond->op == IR_GT || cond->op == IR_GE ||
239246
cond->op == IR_ULT || cond->op == IR_ULE || cond->op == IR_UGT || cond->op == IR_UGE);
247+
is_less = (cond->op == IR_LT || cond->op == IR_LE ||
248+
cond->op == IR_ULT || cond->op == IR_ULE);
240249
} else if (IR_IS_TYPE_SIGNED(type)) {
241250
is_cmp = (cond->op == IR_LT || cond->op == IR_LE || cond->op == IR_GT || cond->op == IR_GE);
251+
is_less = (cond->op == IR_LT || cond->op == IR_LE);
242252
} else {
243253
IR_ASSERT(IR_IS_TYPE_UNSIGNED(type));
244254
is_cmp = (cond->op == IR_ULT || cond->op == IR_ULE || cond->op == IR_UGT || cond->op == IR_UGE);
255+
is_less = (cond->op == IR_ULT || cond->op == IR_ULE);
245256
}
246257

247258
if (is_cmp
@@ -277,15 +288,6 @@ static ir_ref ir_optimize_phi(ir_ctx *ctx, ir_ref merge_ref, ir_insn *merge, ir_
277288
IR_ASSERT(ctx->use_lists[start1_ref].count == 1);
278289
IR_ASSERT(ctx->use_lists[start2_ref].count == 1);
279290

280-
if (IR_IS_TYPE_FP(type)) {
281-
is_less = (cond->op == IR_LT || cond->op == IR_LE ||
282-
cond->op == IR_ULT || cond->op == IR_ULE);
283-
} else if (IR_IS_TYPE_SIGNED(type)) {
284-
is_less = (cond->op == IR_LT || cond->op == IR_LE);
285-
} else {
286-
IR_ASSERT(IR_IS_TYPE_UNSIGNED(type));
287-
is_less = (cond->op == IR_ULT || cond->op == IR_ULE);
288-
}
289291
insn->op = (
290292
(is_less ? cond->op1 : cond->op2)
291293
==
@@ -318,6 +320,85 @@ static ir_ref ir_optimize_phi(ir_ctx *ctx, ir_ref merge_ref, ir_insn *merge, ir_
318320
MAKE_NOP(end2); CLEAR_USES(end2_ref);
319321
MAKE_NOP(merge); CLEAR_USES(merge_ref);
320322

323+
return next_ref;
324+
} else if (is_cmp
325+
&& ((ctx->ir_base[insn->op2].op == IR_NEG
326+
&& ctx->use_lists[insn->op2].count == 1
327+
&& ctx->ir_base[insn->op2].op1 == insn->op3
328+
&& ((cond->op1 == insn->op3
329+
&& ir_is_zero(ctx, cond->op2)
330+
&& is_less == (start1->op == IR_IF_TRUE))
331+
|| (cond->op2 == insn->op3
332+
&& ir_is_zero(ctx, cond->op1)
333+
&& is_less != (start1->op == IR_IF_TRUE))))
334+
|| (ctx->ir_base[insn->op3].op == IR_NEG
335+
&& ctx->use_lists[insn->op3].count == 1
336+
&& ctx->ir_base[insn->op3].op1 == insn->op2
337+
&& ((cond->op1 == insn->op2
338+
&& ir_is_zero(ctx, cond->op2)
339+
&& is_less != (start1->op == IR_IF_TRUE))
340+
|| (cond->op2 == insn->op2
341+
&& ir_is_zero(ctx, cond->op1)
342+
&& is_less == (start1->op == IR_IF_TRUE)))))) {
343+
/* ABS
344+
*
345+
* prev prev
346+
* | LT(A, 0) |
347+
* | / |
348+
* IF |
349+
* | \ |
350+
* | +-----+ |
351+
* | IF_FALSE |
352+
* IF_TRUE | => |
353+
* | END |
354+
* END / |
355+
* | +---+ |
356+
* | / |
357+
* MERGE |
358+
* | \ |
359+
* | PHI(A, NEG(A)) | ABS(A)
360+
* next next
361+
*/
362+
ir_ref neg_ref;
363+
ir_ref next_ref = ctx->use_edges[ctx->use_lists[merge_ref].refs];
364+
ir_insn *next;
365+
366+
if (next_ref == ref) {
367+
next_ref = ctx->use_edges[ctx->use_lists[merge_ref].refs + 1];
368+
}
369+
next = &ctx->ir_base[next_ref];
370+
371+
IR_ASSERT(ctx->use_lists[start1_ref].count == 1);
372+
IR_ASSERT(ctx->use_lists[start2_ref].count == 1);
373+
374+
insn->op = IR_ABS;
375+
insn->inputs_count = 1;
376+
if (ctx->ir_base[insn->op2].op == IR_NEG) {
377+
neg_ref = insn->op2;
378+
insn->op1 = insn->op3;
379+
} else {
380+
neg_ref = insn->op3;
381+
insn->op1 = insn->op2;
382+
}
383+
insn->op2 = IR_UNUSED;
384+
insn->op3 = IR_UNUSED;
385+
386+
next->op1 = root->op1;
387+
ir_use_list_replace(ctx, root->op1, root_ref, next_ref);
388+
ir_use_list_remove_all(ctx, root->op2, root_ref);
389+
if (!IR_IS_CONST_REF(insn->op1)) {
390+
ir_use_list_remove_all(ctx, insn->op1, cond_ref);
391+
}
392+
393+
MAKE_NOP(cond); CLEAR_USES(cond_ref);
394+
MAKE_NOP(root); CLEAR_USES(root_ref);
395+
MAKE_NOP(start1); CLEAR_USES(start1_ref);
396+
MAKE_NOP(start2); CLEAR_USES(start2_ref);
397+
MAKE_NOP(end1); CLEAR_USES(end1_ref);
398+
MAKE_NOP(end2); CLEAR_USES(end2_ref);
399+
MAKE_NOP(merge); CLEAR_USES(merge_ref);
400+
MAKE_NOP(&ctx->ir_base[neg_ref]); CLEAR_USES(neg_ref);
401+
321402
return next_ref;
322403
#if 0
323404
} else {

ext/opcache/jit/ir/ir_fold.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2257,6 +2257,26 @@ IR_FOLD(TRUNC(SEXT))
22572257
IR_FOLD_NEXT;
22582258
}
22592259

2260+
IR_FOLD(TRUNC(BITCAST))
2261+
IR_FOLD(ZEXT(BITCAST))
2262+
IR_FOLD(SEXT(BITCAST))
2263+
IR_FOLD(BITCAST(BITCAST))
2264+
{
2265+
if (IR_IS_TYPE_INT(op1_insn->type)) {
2266+
op1 = op1_insn->op1;
2267+
IR_FOLD_RESTART;
2268+
}
2269+
IR_FOLD_NEXT;
2270+
}
2271+
2272+
//IR_FOLD(TRUNC(TRUNC))
2273+
IR_FOLD(ZEXT(ZEXT))
2274+
IR_FOLD(SEXT(SEXT))
2275+
{
2276+
op1 = op1_insn->op1;
2277+
IR_FOLD_RESTART;
2278+
}
2279+
22602280
IR_FOLD(TRUNC(AND))
22612281
{
22622282
if (IR_IS_CONST_REF(op1_insn->op2)) {

ext/opcache/jit/ir/ir_private.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1219,6 +1219,7 @@ IR_ALWAYS_INLINE int8_t ir_get_alocated_reg(const ir_ctx *ctx, ir_ref ref, int o
12191219
#define IR_SIMPLE (1U<<29) /* Insn doesn't have any target constraints */
12201220
#define IR_FUSED_REG (1U<<28) /* Register assignemnt may be stored in ctx->fused_regs instead of ctx->regs */
12211221
#define IR_MAY_SWAP (1U<<27) /* Allow swapping operands for better register allocation */
1222+
#define IR_MAY_REUSE (1U<<26) /* Result may reuse register of the source */
12221223

12231224
#define IR_RULE_MASK 0xff
12241225

ext/opcache/jit/ir/ir_ra.c

Lines changed: 57 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1535,6 +1535,33 @@ static ir_live_pos ir_vregs_overlap(ir_ctx *ctx, uint32_t r1, uint32_t r2)
15351535
return ir_ivals_overlap(&ival1->range, &ival2->range);
15361536
}
15371537

1538+
static bool ir_ivals_inside(ir_live_range *parent, ir_live_range *child)
1539+
{
1540+
do {
1541+
while (parent && parent->end < child->start) {
1542+
parent = parent->next;
1543+
}
1544+
if (!parent || parent->start > child->start || parent->end < child->end) {
1545+
return 0;
1546+
}
1547+
child = child->next;
1548+
} while (child);
1549+
return 1;
1550+
}
1551+
1552+
static bool ir_vregs_inside(ir_ctx *ctx, uint32_t parent, uint32_t child)
1553+
{
1554+
ir_live_interval *child_ival = ctx->live_intervals[child];
1555+
ir_live_interval *parent_ival = ctx->live_intervals[parent];
1556+
1557+
#if 0
1558+
if (child_ival->end >= parent_ival->end) {
1559+
return 0;
1560+
}
1561+
#endif
1562+
return ir_ivals_inside(&parent_ival->range, &child_ival->range);
1563+
}
1564+
15381565
static void ir_vregs_join(ir_ctx *ctx, uint32_t r1, uint32_t r2)
15391566
{
15401567
ir_live_interval *ival = ctx->live_intervals[r2];
@@ -1922,29 +1949,33 @@ int ir_coalesce(ir_ctx *ctx)
19221949

19231950
if (ctx->rules) {
19241951
/* try to swap operands of commutative instructions for better register allocation */
1925-
for (b = 1, bb = &ctx->cfg_blocks[1]; b <= ctx->cfg_blocks_count; b++, bb++) {
1926-
ir_ref i;
1927-
1928-
IR_ASSERT(!(bb->flags & IR_BB_UNREACHABLE));
1929-
i = bb->end;
1930-
1931-
/* skip last instruction */
1932-
i = ctx->prev_ref[i];
1933-
1934-
while (i != bb->start) {
1935-
if (ctx->rules[i] & IR_MAY_SWAP) {
1936-
insn = &ctx->ir_base[i];
1952+
uint32_t *rule = ctx->rules + 1;
1953+
ir_ref i;
1954+
1955+
for (i = 1; i < ctx->insns_count; rule++, i++) {
1956+
if ((*rule) & (IR_MAY_SWAP|IR_MAY_REUSE)) {
1957+
insn = &ctx->ir_base[i];
1958+
IR_ASSERT(ctx->vregs[i]);
1959+
if ((*rule) & IR_MAY_SWAP) {
19371960
IR_ASSERT(ir_op_flags[insn->op] & IR_OP_FLAG_COMMUTATIVE);
1938-
if (ctx->vregs[i]
1939-
&& ctx->live_intervals[ctx->vregs[i]]->use_pos
1961+
if (ctx->live_intervals[ctx->vregs[i]]->use_pos
19401962
&& (ctx->live_intervals[ctx->vregs[i]]->use_pos->flags & IR_DEF_REUSES_OP1_REG)
19411963
&& insn->op2 > 0
19421964
&& insn->op1 > 0
19431965
&& insn->op1 != insn->op2) {
19441966
ir_try_swap_operands(ctx, i, insn);
19451967
}
1968+
} else {
1969+
IR_ASSERT((*rule) & IR_MAY_REUSE);
1970+
if (insn->op1 > 0
1971+
&& ctx->vregs[insn->op1]
1972+
&& ctx->vregs[i] != ctx->vregs[insn->op1]) {
1973+
if (ir_vregs_inside(ctx, ctx->vregs[insn->op1], ctx->vregs[i])) {
1974+
ir_vregs_coalesce(ctx, ctx->vregs[i], ctx->vregs[insn->op1], i, insn->op1);
1975+
compact = 1;
1976+
}
1977+
}
19461978
}
1947-
i = ctx->prev_ref[i];
19481979
}
19491980
}
19501981
}
@@ -3807,6 +3838,17 @@ static void assign_regs(ir_ctx *ctx)
38073838
ref = IR_LIVE_POS_TO_REF(use_pos->pos);
38083839
// TODO: Insert spill loads and stores in optimal positions (resolution)
38093840
if (use_pos->op_num == 0) {
3841+
if ((ctx->ir_base[ref].op == IR_COPY
3842+
|| ctx->ir_base[ref].op == IR_BITCAST
3843+
|| ctx->ir_base[ref].op == IR_TRUNC)
3844+
&& !IR_IS_CONST_REF(ctx->ir_base[ref].op1)
3845+
&& ctx->vregs[ctx->ir_base[ref].op1] == (uint32_t)i) {
3846+
/* register reuse */
3847+
ir_set_alocated_reg(ctx, ref, use_pos->op_num, reg);
3848+
prev_use_ref = ref;
3849+
use_pos = use_pos->next;
3850+
continue;
3851+
}
38103852
ir_bitset_clear(available, ir_bitset_len(ctx->cfg_blocks_count + 1));
38113853
if (ctx->ir_base[ref].op == IR_PHI) {
38123854
/* Spilled PHI var is passed through memory */

0 commit comments

Comments
 (0)