Skip to content

Commit 36ff451

Browse files
bpo-30501: Make the compiler producing optimized code for condition expressions. (#1851)
1 parent 1efbf92 commit 36ff451

File tree

5 files changed

+2537
-2448
lines changed

5 files changed

+2537
-2448
lines changed

Misc/NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ What's New in Python 3.7.0 alpha 1?
1010
Core and Builtins
1111
-----------------
1212

13+
- bpo-30501: The compiler now produces more optimal code for complex condition
14+
expressions in the "if", "while" and "assert" statement, the "if" expression,
15+
and generator expressions and comprehensions.
16+
1317
- bpo-28180: Implement PEP 538 (legacy C locale coercion). This means that when
1418
a suitable coercion target locale is available, both the core interpreter and
1519
locale-aware C extensions will assume the use of UTF-8 as the default text

Python/compile.c

Lines changed: 137 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1999,6 +1999,131 @@ compiler_class(struct compiler *c, stmt_ty s)
19991999
return 1;
20002000
}
20012001

2002+
static int
2003+
cmpop(cmpop_ty op)
2004+
{
2005+
switch (op) {
2006+
case Eq:
2007+
return PyCmp_EQ;
2008+
case NotEq:
2009+
return PyCmp_NE;
2010+
case Lt:
2011+
return PyCmp_LT;
2012+
case LtE:
2013+
return PyCmp_LE;
2014+
case Gt:
2015+
return PyCmp_GT;
2016+
case GtE:
2017+
return PyCmp_GE;
2018+
case Is:
2019+
return PyCmp_IS;
2020+
case IsNot:
2021+
return PyCmp_IS_NOT;
2022+
case In:
2023+
return PyCmp_IN;
2024+
case NotIn:
2025+
return PyCmp_NOT_IN;
2026+
default:
2027+
return PyCmp_BAD;
2028+
}
2029+
}
2030+
2031+
static int
2032+
compiler_jump_if(struct compiler *c, expr_ty e, basicblock *next, int cond)
2033+
{
2034+
switch (e->kind) {
2035+
case UnaryOp_kind:
2036+
if (e->v.UnaryOp.op == Not)
2037+
return compiler_jump_if(c, e->v.UnaryOp.operand, next, !cond);
2038+
/* fallback to general implementation */
2039+
break;
2040+
case BoolOp_kind: {
2041+
asdl_seq *s = e->v.BoolOp.values;
2042+
Py_ssize_t i, n = asdl_seq_LEN(s) - 1;
2043+
assert(n >= 0);
2044+
int cond2 = e->v.BoolOp.op == Or;
2045+
basicblock *next2 = next;
2046+
if (!cond2 != !cond) {
2047+
next2 = compiler_new_block(c);
2048+
if (next2 == NULL)
2049+
return 0;
2050+
}
2051+
for (i = 0; i < n; ++i) {
2052+
if (!compiler_jump_if(c, (expr_ty)asdl_seq_GET(s, i), next2, cond2))
2053+
return 0;
2054+
}
2055+
if (!compiler_jump_if(c, (expr_ty)asdl_seq_GET(s, n), next, cond))
2056+
return 0;
2057+
if (next2 != next)
2058+
compiler_use_next_block(c, next2);
2059+
return 1;
2060+
}
2061+
case IfExp_kind: {
2062+
basicblock *end, *next2;
2063+
end = compiler_new_block(c);
2064+
if (end == NULL)
2065+
return 0;
2066+
next2 = compiler_new_block(c);
2067+
if (next2 == NULL)
2068+
return 0;
2069+
if (!compiler_jump_if(c, e->v.IfExp.test, next2, 0))
2070+
return 0;
2071+
if (!compiler_jump_if(c, e->v.IfExp.body, next, cond))
2072+
return 0;
2073+
ADDOP_JREL(c, JUMP_FORWARD, end);
2074+
compiler_use_next_block(c, next2);
2075+
if (!compiler_jump_if(c, e->v.IfExp.orelse, next, cond))
2076+
return 0;
2077+
compiler_use_next_block(c, end);
2078+
return 1;
2079+
}
2080+
case Compare_kind: {
2081+
Py_ssize_t i, n = asdl_seq_LEN(e->v.Compare.ops) - 1;
2082+
if (n > 0) {
2083+
basicblock *cleanup = compiler_new_block(c);
2084+
if (cleanup == NULL)
2085+
return 0;
2086+
VISIT(c, expr, e->v.Compare.left);
2087+
for (i = 0; i < n; i++) {
2088+
VISIT(c, expr,
2089+
(expr_ty)asdl_seq_GET(e->v.Compare.comparators, i));
2090+
ADDOP(c, DUP_TOP);
2091+
ADDOP(c, ROT_THREE);
2092+
ADDOP_I(c, COMPARE_OP,
2093+
cmpop((cmpop_ty)(asdl_seq_GET(e->v.Compare.ops, i))));
2094+
ADDOP_JABS(c, POP_JUMP_IF_FALSE, cleanup);
2095+
NEXT_BLOCK(c);
2096+
}
2097+
VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Compare.comparators, n));
2098+
ADDOP_I(c, COMPARE_OP,
2099+
cmpop((cmpop_ty)(asdl_seq_GET(e->v.Compare.ops, n))));
2100+
ADDOP_JABS(c, cond ? POP_JUMP_IF_TRUE : POP_JUMP_IF_FALSE, next);
2101+
basicblock *end = compiler_new_block(c);
2102+
if (end == NULL)
2103+
return 0;
2104+
ADDOP_JREL(c, JUMP_FORWARD, end);
2105+
compiler_use_next_block(c, cleanup);
2106+
ADDOP(c, POP_TOP);
2107+
if (!cond) {
2108+
ADDOP_JREL(c, JUMP_FORWARD, next);
2109+
}
2110+
compiler_use_next_block(c, end);
2111+
return 1;
2112+
}
2113+
/* fallback to general implementation */
2114+
break;
2115+
}
2116+
default:
2117+
/* fallback to general implementation */
2118+
break;
2119+
}
2120+
2121+
/* general implementation */
2122+
VISIT(c, expr, e);
2123+
ADDOP_JABS(c, cond ? POP_JUMP_IF_TRUE : POP_JUMP_IF_FALSE, next);
2124+
return 1;
2125+
}
2126+
20022127
static int
20032128
compiler_ifexp(struct compiler *c, expr_ty e)
20042129
{
@@ -2011,8 +2136,8 @@ compiler_ifexp(struct compiler *c, expr_ty e)
20112136
next = compiler_new_block(c);
20122137
if (next == NULL)
20132138
return 0;
2014-
VISIT(c, expr, e->v.IfExp.test);
2015-
ADDOP_JABS(c, POP_JUMP_IF_FALSE, next);
2139+
if (!compiler_jump_if(c, e->v.IfExp.test, next, 0))
2140+
return 0;
20162141
VISIT(c, expr, e->v.IfExp.body);
20172142
ADDOP_JREL(c, JUMP_FORWARD, end);
20182143
compiler_use_next_block(c, next);
@@ -2101,8 +2226,8 @@ compiler_if(struct compiler *c, stmt_ty s)
21012226
}
21022227
else
21032228
next = end;
2104-
VISIT(c, expr, s->v.If.test);
2105-
ADDOP_JABS(c, POP_JUMP_IF_FALSE, next);
2229+
if (!compiler_jump_if(c, s->v.If.test, next, 0))
2230+
return 0;
21062231
VISIT_SEQ(c, stmt, s->v.If.body);
21072232
if (asdl_seq_LEN(s->v.If.orelse)) {
21082233
ADDOP_JREL(c, JUMP_FORWARD, end);
@@ -2261,8 +2386,8 @@ compiler_while(struct compiler *c, stmt_ty s)
22612386
if (!compiler_push_fblock(c, LOOP, loop))
22622387
return 0;
22632388
if (constant == -1) {
2264-
VISIT(c, expr, s->v.While.test);
2265-
ADDOP_JABS(c, POP_JUMP_IF_FALSE, anchor);
2389+
if (!compiler_jump_if(c, s->v.While.test, anchor, 0))
2390+
return 0;
22662391
}
22672392
VISIT_SEQ(c, stmt, s->v.While.body);
22682393
ADDOP_JABS(c, JUMP_ABSOLUTE, loop);
@@ -2721,11 +2846,11 @@ compiler_assert(struct compiler *c, stmt_ty s)
27212846
}
27222847
Py_DECREF(msg);
27232848
}
2724-
VISIT(c, expr, s->v.Assert.test);
27252849
end = compiler_new_block(c);
27262850
if (end == NULL)
27272851
return 0;
2728-
ADDOP_JABS(c, POP_JUMP_IF_TRUE, end);
2852+
if (!compiler_jump_if(c, s->v.Assert.test, end, 1))
2853+
return 0;
27292854
ADDOP_O(c, LOAD_GLOBAL, assertion_error, names);
27302855
if (s->v.Assert.msg) {
27312856
VISIT(c, expr, s->v.Assert.msg);
@@ -2909,35 +3034,6 @@ binop(struct compiler *c, operator_ty op)
29093034
}
29103035
}
29113036

2912-
static int
2913-
cmpop(cmpop_ty op)
2914-
{
2915-
switch (op) {
2916-
case Eq:
2917-
return PyCmp_EQ;
2918-
case NotEq:
2919-
return PyCmp_NE;
2920-
case Lt:
2921-
return PyCmp_LT;
2922-
case LtE:
2923-
return PyCmp_LE;
2924-
case Gt:
2925-
return PyCmp_GT;
2926-
case GtE:
2927-
return PyCmp_GE;
2928-
case Is:
2929-
return PyCmp_IS;
2930-
case IsNot:
2931-
return PyCmp_IS_NOT;
2932-
case In:
2933-
return PyCmp_IN;
2934-
case NotIn:
2935-
return PyCmp_NOT_IN;
2936-
default:
2937-
return PyCmp_BAD;
2938-
}
2939-
}
2940-
29413037
static int
29423038
inplace_binop(struct compiler *c, operator_ty op)
29433039
{
@@ -3676,8 +3772,8 @@ compiler_sync_comprehension_generator(struct compiler *c,
36763772
n = asdl_seq_LEN(gen->ifs);
36773773
for (i = 0; i < n; i++) {
36783774
expr_ty e = (expr_ty)asdl_seq_GET(gen->ifs, i);
3679-
VISIT(c, expr, e);
3680-
ADDOP_JABS(c, POP_JUMP_IF_FALSE, if_cleanup);
3775+
if (!compiler_jump_if(c, e, if_cleanup, 0))
3776+
return 0;
36813777
NEXT_BLOCK(c);
36823778
}
36833779

@@ -3807,8 +3903,8 @@ compiler_async_comprehension_generator(struct compiler *c,
38073903
n = asdl_seq_LEN(gen->ifs);
38083904
for (i = 0; i < n; i++) {
38093905
expr_ty e = (expr_ty)asdl_seq_GET(gen->ifs, i);
3810-
VISIT(c, expr, e);
3811-
ADDOP_JABS(c, POP_JUMP_IF_FALSE, if_cleanup);
3906+
if (!compiler_jump_if(c, e, if_cleanup, 0))
3907+
return 0;
38123908
NEXT_BLOCK(c);
38133909
}
38143910

0 commit comments

Comments
 (0)