Skip to content

Commit db0cd64

Browse files
committed
Improved SCDF<->SCCP interface
- "get_feasible_successors" callback is changed into "mark_feasible_successors" and should mark necessary edges through scdf_mark_edge_feasible() - SCDF takes care about OP_DATA instruction - SCDF code is re-arranged to avoid repeatable checks
1 parent e0ad5dd commit db0cd64

File tree

3 files changed

+81
-95
lines changed

3 files changed

+81
-95
lines changed

ext/opcache/Optimizer/sccp.c

Lines changed: 37 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -601,15 +601,10 @@ static inline int ct_eval_func_call(
601601

602602
#define SKIP_IF_TOP(op) if (IS_TOP(op)) break;
603603

604-
static void sccp_visit_instr(scdf_ctx *scdf, void *void_ctx, zend_op *opline, zend_ssa_op *ssa_op) {
605-
sccp_ctx *ctx = (sccp_ctx *) void_ctx;
604+
static void sccp_visit_instr(scdf_ctx *scdf, zend_op *opline, zend_ssa_op *ssa_op) {
605+
sccp_ctx *ctx = (sccp_ctx *) scdf->ctx;
606606
zval *op1, *op2, zv; /* zv is a temporary to hold result values */
607607

608-
if (opline->opcode == ZEND_OP_DATA) {
609-
opline--;
610-
ssa_op--;
611-
}
612-
613608
op1 = get_op1_value(ctx, opline, ssa_op);
614609
op2 = get_op2_value(ctx, opline, ssa_op);
615610

@@ -1032,11 +1027,13 @@ static void sccp_visit_instr(scdf_ctx *scdf, void *void_ctx, zend_op *opline, ze
10321027
}
10331028

10341029
/* Returns whether there is a successor */
1035-
static zend_bool sccp_get_feasible_successors(
1036-
scdf_ctx *scdf, void *void_ctx, zend_basic_block *block,
1037-
zend_op *opline, zend_ssa_op *ssa_op, zend_bool *suc) {
1038-
sccp_ctx *ctx = (sccp_ctx *) void_ctx;
1030+
static void sccp_mark_feasible_successors(
1031+
scdf_ctx *scdf,
1032+
int block_num, zend_basic_block *block,
1033+
zend_op *opline, zend_ssa_op *ssa_op) {
1034+
sccp_ctx *ctx = (sccp_ctx *) scdf->ctx;
10391035
zval *op1;
1036+
int s;
10401037

10411038
/* We can't determine the branch target at compile-time for these */
10421039
switch (opline->opcode) {
@@ -1046,51 +1043,56 @@ static zend_bool sccp_get_feasible_successors(
10461043
case ZEND_DECLARE_ANON_INHERITED_CLASS:
10471044
case ZEND_FE_FETCH_R:
10481045
case ZEND_FE_FETCH_RW:
1049-
suc[0] = 1;
1050-
suc[1] = 1;
1051-
return 1;
1046+
scdf_mark_edge_feasible(scdf, block_num, block->successors[0]);
1047+
scdf_mark_edge_feasible(scdf, block_num, block->successors[1]);
1048+
return;
10521049
}
10531050

10541051
op1 = get_op1_value(ctx, opline, ssa_op);
10551052

1056-
/* Branch target not yet known */
1057-
if (IS_TOP(op1)) {
1058-
return 0;
1053+
/* Branch target can be either one */
1054+
if (!op1 || IS_BOT(op1)) {
1055+
for (s = 0; s < block->successors_count; s++) {
1056+
scdf_mark_edge_feasible(scdf, block_num, block->successors[s]);
1057+
}
1058+
return;
10591059
}
10601060

1061-
/* Branch target can be either one */
1062-
if (IS_BOT(op1)) {
1063-
suc[0] = 1;
1064-
suc[1] = 1;
1065-
return 1;
1061+
/* Branch target not yet known */
1062+
if (IS_TOP(op1)) {
1063+
return;
10661064
}
10671065

10681066
switch (opline->opcode) {
10691067
case ZEND_JMPZ:
10701068
case ZEND_JMPZNZ:
10711069
case ZEND_JMPZ_EX:
1072-
suc[zend_is_true(op1)] = 1;
1070+
s = zend_is_true(op1);
10731071
break;
10741072
case ZEND_JMPNZ:
10751073
case ZEND_JMPNZ_EX:
10761074
case ZEND_JMP_SET:
1077-
suc[!zend_is_true(op1)] = 1;
1075+
s = !zend_is_true(op1);
10781076
break;
10791077
case ZEND_COALESCE:
1080-
suc[Z_TYPE_P(op1) == IS_NULL] = 1;
1078+
s = (Z_TYPE_P(op1) == IS_NULL);
10811079
break;
10821080
case ZEND_FE_RESET_R:
10831081
case ZEND_FE_RESET_RW:
1084-
if (Z_TYPE_P(op1) == IS_ARRAY) {
1085-
suc[zend_hash_num_elements(Z_ARR_P(op1)) != 0] = 1;
1086-
} else {
1087-
suc[0] = 1;
1088-
suc[1] = 1;
1082+
if (Z_TYPE_P(op1) != IS_ARRAY) {
1083+
scdf_mark_edge_feasible(scdf, block_num, block->successors[0]);
1084+
scdf_mark_edge_feasible(scdf, block_num, block->successors[1]);
1085+
return;
10891086
}
1087+
s = zend_hash_num_elements(Z_ARR_P(op1)) != 0;
10901088
break;
1091-
EMPTY_SWITCH_DEFAULT_CASE()
1089+
default:
1090+
for (s = 0; s < block->successors_count; s++) {
1091+
scdf_mark_edge_feasible(scdf, block_num, block->successors[s]);
1092+
}
1093+
return;
10921094
}
1093-
return 1;
1095+
scdf_mark_edge_feasible(scdf, block_num, block->successors[s]);
10941096
}
10951097

10961098
static void join_phi_values(zval *a, zval *b) {
@@ -1108,8 +1110,8 @@ static void join_phi_values(zval *a, zval *b) {
11081110
}
11091111
}
11101112

1111-
static void sccp_visit_phi(scdf_ctx *scdf, void *void_ctx, zend_ssa_phi *phi) {
1112-
sccp_ctx *ctx = (sccp_ctx *) void_ctx;
1113+
static void sccp_visit_phi(scdf_ctx *scdf, zend_ssa_phi *phi) {
1114+
sccp_ctx *ctx = (sccp_ctx *) scdf->ctx;
11131115
zend_ssa *ssa = ctx->ssa;
11141116
ZEND_ASSERT(phi->ssa_var >= 0);
11151117
if (!IS_BOT(&ctx->values[phi->ssa_var])) {
@@ -1372,7 +1374,7 @@ void sccp_optimize_op_array(zend_op_array *op_array, zend_ssa *ssa, zend_call_in
13721374

13731375
scdf.handlers.visit_instr = sccp_visit_instr;
13741376
scdf.handlers.visit_phi = sccp_visit_phi;
1375-
scdf.handlers.get_feasible_successors = sccp_get_feasible_successors;
1377+
scdf.handlers.mark_feasible_successors = sccp_mark_feasible_successors;
13761378

13771379
scdf_init(&scdf, op_array, ssa, &ctx);
13781380
scdf_solve(&scdf, "SCCP");

ext/opcache/Optimizer/scdf.c

Lines changed: 37 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@
5252
#define DEBUG_PRINT(...)
5353
#endif
5454

55-
static void mark_edge_feasible(scdf_ctx *ctx, int from, int to) {
55+
void scdf_mark_edge_feasible(scdf_ctx *ctx, int from, int to) {
5656
uint32_t edge = scdf_edge(&ctx->ssa->cfg, from, to);
5757

5858
if (zend_bitset_in(ctx->feasible_edges, edge)) {
@@ -75,50 +75,7 @@ static void mark_edge_feasible(scdf_ctx *ctx, int from, int to) {
7575
zend_ssa_phi *phi;
7676
for (phi = ssa_block->phis; phi; phi = phi->next) {
7777
zend_bitset_excl(ctx->phi_var_worklist, phi->ssa_var);
78-
ctx->handlers.visit_phi(ctx, ctx->ctx, phi);
79-
}
80-
}
81-
}
82-
83-
/* Returns whether there is a successor */
84-
static inline zend_bool get_feasible_successors(
85-
scdf_ctx *ctx, zend_basic_block *block,
86-
zend_op *opline, zend_ssa_op *ssa_op, zend_bool *suc) {
87-
/* Terminal block without successors */
88-
if (block->successors_count == 0) {
89-
return 0;
90-
}
91-
92-
/* Unconditional jump */
93-
if (block->successors_count == 1) {
94-
suc[0] = 1;
95-
return 1;
96-
}
97-
98-
return ctx->handlers.get_feasible_successors(ctx, ctx->ctx, block, opline, ssa_op, suc);
99-
}
100-
101-
static void handle_instr(scdf_ctx *ctx, int block_num, zend_op *opline, zend_ssa_op *ssa_op) {
102-
zend_basic_block *block = &ctx->ssa->cfg.blocks[block_num];
103-
ctx->handlers.visit_instr(ctx, ctx->ctx, opline, ssa_op);
104-
105-
if (opline - ctx->op_array->opcodes == block->start + block->len - 1) {
106-
if (opline->opcode == ZEND_SWITCH_LONG || opline->opcode == ZEND_SWITCH_STRING) {
107-
// TODO For now consider all edges feasible
108-
int s;
109-
for (s = 0; s < block->successors_count; s++) {
110-
mark_edge_feasible(ctx, block_num, block->successors[s]);
111-
}
112-
} else {
113-
zend_bool suc[2] = {0};
114-
if (get_feasible_successors(ctx, block, opline, ssa_op, suc)) {
115-
if (suc[0]) {
116-
mark_edge_feasible(ctx, block_num, block->successors[0]);
117-
}
118-
if (suc[1]) {
119-
mark_edge_feasible(ctx, block_num, block->successors[1]);
120-
}
121-
}
78+
ctx->handlers.visit_phi(ctx, phi);
12279
}
12380
}
12481
}
@@ -168,14 +125,28 @@ void scdf_solve(scdf_ctx *ctx, const char *name) {
168125
zend_ssa_phi *phi = ssa->vars[i].definition_phi;
169126
ZEND_ASSERT(phi);
170127
if (zend_bitset_in(ctx->executable_blocks, phi->block)) {
171-
ctx->handlers.visit_phi(ctx, ctx->ctx, phi);
128+
ctx->handlers.visit_phi(ctx, phi);
172129
}
173130
}
174131

175132
while ((i = zend_bitset_pop_first(ctx->instr_worklist, ctx->instr_worklist_len)) >= 0) {
176133
int block_num = ssa->cfg.map[i];
177134
if (zend_bitset_in(ctx->executable_blocks, block_num)) {
178-
handle_instr(ctx, block_num, &ctx->op_array->opcodes[i], &ssa->ops[i]);
135+
zend_basic_block *block = &ssa->cfg.blocks[block_num];
136+
zend_op *opline = &ctx->op_array->opcodes[i];
137+
zend_ssa_op *ssa_op = &ssa->ops[i];
138+
if (opline->opcode == ZEND_OP_DATA) {
139+
opline--;
140+
ssa_op--;
141+
}
142+
ctx->handlers.visit_instr(ctx, opline, ssa_op);
143+
if (i == block->start + block->len - 1) {
144+
if (block->successors_count == 1) {
145+
scdf_mark_edge_feasible(ctx, block_num, block->successors[0]);
146+
} else if (block->successors_count > 1) {
147+
ctx->handlers.mark_feasible_successors(ctx, block_num, block, opline, ssa_op);
148+
}
149+
}
179150
}
180151
}
181152

@@ -191,21 +162,32 @@ void scdf_solve(scdf_ctx *ctx, const char *name) {
191162
zend_ssa_phi *phi;
192163
for (phi = ssa_block->phis; phi; phi = phi->next) {
193164
zend_bitset_excl(ctx->phi_var_worklist, phi->ssa_var);
194-
ctx->handlers.visit_phi(ctx, ctx->ctx, phi);
165+
ctx->handlers.visit_phi(ctx, phi);
195166
}
196167
}
197168

198-
{
169+
if (block->len == 0) {
170+
/* Zero length blocks don't have a last instruction that would normally do this */
171+
scdf_mark_edge_feasible(ctx, i, block->successors[0]);
172+
} else {
173+
zend_op *opline;
199174
int j, end = block->start + block->len;
200175
for (j = block->start; j < end; j++) {
176+
opline = &ctx->op_array->opcodes[j];
201177
zend_bitset_excl(ctx->instr_worklist, j);
202-
handle_instr(ctx, i, &ctx->op_array->opcodes[j], &ssa->ops[j]);
178+
if (opline->opcode != ZEND_OP_DATA) {
179+
ctx->handlers.visit_instr(ctx, opline, &ssa->ops[j]);
180+
}
181+
}
182+
if (block->successors_count == 1) {
183+
scdf_mark_edge_feasible(ctx, i, block->successors[0]);
184+
} else if (block->successors_count > 1) {
185+
if (opline->opcode == ZEND_OP_DATA) {
186+
opline--;
187+
j--;
188+
}
189+
ctx->handlers.mark_feasible_successors(ctx, i, block, opline, &ssa->ops[j-1]);
203190
}
204-
}
205-
206-
if (block->len == 0) {
207-
/* Zero length blocks don't have a last instruction that would normally do this */
208-
mark_edge_feasible(ctx, i, block->successors[0]);
209191
}
210192
}
211193
}

ext/opcache/Optimizer/scdf.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,12 @@ typedef struct _scdf_ctx {
3838

3939
struct {
4040
void (*visit_instr)(
41-
struct _scdf_ctx *scdf, void *ctx, zend_op *opline, zend_ssa_op *ssa_op);
41+
struct _scdf_ctx *scdf, zend_op *opline, zend_ssa_op *ssa_op);
4242
void (*visit_phi)(
43-
struct _scdf_ctx *scdf, void *ctx, zend_ssa_phi *phi);
44-
zend_bool (*get_feasible_successors)(
45-
struct _scdf_ctx *scdf, void *ctx, zend_basic_block *block,
46-
zend_op *opline, zend_ssa_op *ssa_op, zend_bool *suc);
43+
struct _scdf_ctx *scdf, zend_ssa_phi *phi);
44+
void (*mark_feasible_successors)(
45+
struct _scdf_ctx *scdf, int block_num, zend_basic_block *block,
46+
zend_op *opline, zend_ssa_op *ssa_op);
4747
} handlers;
4848
} scdf_ctx;
4949

@@ -96,4 +96,6 @@ static inline zend_bool scdf_is_edge_feasible(scdf_ctx *scdf, int from, int to)
9696
return zend_bitset_in(scdf->feasible_edges, edge);
9797
}
9898

99+
void scdf_mark_edge_feasible(scdf_ctx *ctx, int from, int to);
100+
99101
#endif

0 commit comments

Comments
 (0)