# HG changeset patch # User Antoine Pitrou # Date 1229891245 -3600 diff -r 56747b9abe2d -r 4276bf56dd72 Include/opcode.h --- a/Include/opcode.h +++ b/Include/opcode.h @@ -99,6 +99,8 @@ extern "C" { #define JUMP_IF_FALSE 111 /* "" */ #define JUMP_IF_TRUE 112 /* "" */ #define JUMP_ABSOLUTE 113 /* Target byte offset from beginning of code */ +#define POP_JUMP_IF_FALSE 114 /* Number of bytes to skip */ +#define POP_JUMP_IF_TRUE 115 /* "" */ #define LOAD_GLOBAL 116 /* Index in name list */ diff -r 56747b9abe2d -r 4276bf56dd72 Lib/opcode.py --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -134,6 +134,8 @@ jrel_op('JUMP_FORWARD', 110) # Number jrel_op('JUMP_IF_FALSE', 111) # "" jrel_op('JUMP_IF_TRUE', 112) # "" jabs_op('JUMP_ABSOLUTE', 113) # Target byte offset from beginning of code +jabs_op('POP_JUMP_IF_FALSE', 114) # "" +jabs_op('POP_JUMP_IF_TRUE', 115) # "" name_op('LOAD_GLOBAL', 116) # Index in name list diff -r 56747b9abe2d -r 4276bf56dd72 Python/ceval.c --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1965,8 +1965,54 @@ PyEval_EvalFrameEx(PyFrameObject *f, int Py_DECREF(w); SET_TOP(x); if (x == NULL) break; - PREDICT(JUMP_IF_FALSE); - PREDICT(JUMP_IF_TRUE); + PREDICT(POP_JUMP_IF_FALSE); + PREDICT(POP_JUMP_IF_TRUE); + continue; + + PREDICTED_WITH_ARG(POP_JUMP_IF_FALSE); + case POP_JUMP_IF_FALSE: + w = POP(); + if (w == Py_True) { + Py_DECREF(w); + goto fast_next_opcode; + } + if (w == Py_False) { + Py_DECREF(w); + JUMPTO(oparg); + goto fast_next_opcode; + } + err = PyObject_IsTrue(w); + Py_DECREF(w); + if (err > 0) + err = 0; + else if (err == 0) + JUMPTO(oparg); + else + break; + continue; + + PREDICTED_WITH_ARG(POP_JUMP_IF_TRUE); + case POP_JUMP_IF_TRUE: + w = POP(); + if (w == Py_False) { + Py_DECREF(w); + goto fast_next_opcode; + } + if (w == Py_True) { + Py_DECREF(w); + JUMPTO(oparg); + goto fast_next_opcode; + } + err = PyObject_IsTrue(w); + Py_DECREF(w); + if (err > 0) { + err = 0; + JUMPTO(oparg); + } + else if (err == 0) + ; + else + break; continue; case IMPORT_NAME: @@ -2043,7 +2089,6 @@ PyEval_EvalFrameEx(PyFrameObject *f, int JUMPBY(oparg); goto fast_next_opcode; - PREDICTED_WITH_ARG(JUMP_IF_FALSE); case JUMP_IF_FALSE: w = TOP(); if (w == Py_True) { @@ -2063,7 +2108,6 @@ PyEval_EvalFrameEx(PyFrameObject *f, int break; continue; - PREDICTED_WITH_ARG(JUMP_IF_TRUE); case JUMP_IF_TRUE: w = TOP(); if (w == Py_False) { diff -r 56747b9abe2d -r 4276bf56dd72 Python/compile.c --- a/Python/compile.c +++ b/Python/compile.c @@ -823,6 +823,10 @@ opcode_stack_effect(int opcode, int opar case JUMP_ABSOLUTE: return 0; + case POP_JUMP_IF_FALSE: + case POP_JUMP_IF_TRUE: + return -1; + case LOAD_GLOBAL: return 1; @@ -1664,12 +1668,10 @@ compiler_ifexp(struct compiler *c, expr_ if (next == NULL) return 0; VISIT(c, expr, e->v.IfExp.test); - ADDOP_JREL(c, JUMP_IF_FALSE, next); - ADDOP(c, POP_TOP); + ADDOP_JABS(c, POP_JUMP_IF_FALSE, next); VISIT(c, expr, e->v.IfExp.body); ADDOP_JREL(c, JUMP_FORWARD, end); compiler_use_next_block(c, next); - ADDOP(c, POP_TOP); VISIT(c, expr, e->v.IfExp.orelse); compiler_use_next_block(c, end); return 1; @@ -1727,9 +1729,6 @@ compiler_if(struct compiler *c, stmt_ty end = compiler_new_block(c); if (end == NULL) return 0; - next = compiler_new_block(c); - if (next == NULL) - return 0; constant = expr_constant(s->v.If.test); /* constant = 0: "if 0" @@ -1741,15 +1740,21 @@ compiler_if(struct compiler *c, stmt_ty } else if (constant == 1) { VISIT_SEQ(c, stmt, s->v.If.body); } else { + if (s->v.If.orelse) { + next = compiler_new_block(c); + if (next == NULL) + return 0; + } + else + next = end; VISIT(c, expr, s->v.If.test); - ADDOP_JREL(c, JUMP_IF_FALSE, next); - ADDOP(c, POP_TOP); + ADDOP_JABS(c, POP_JUMP_IF_FALSE, next); VISIT_SEQ(c, stmt, s->v.If.body); ADDOP_JREL(c, JUMP_FORWARD, end); - compiler_use_next_block(c, next); - ADDOP(c, POP_TOP); - if (s->v.If.orelse) + if (s->v.If.orelse) { + compiler_use_next_block(c, next); VISIT_SEQ(c, stmt, s->v.If.orelse); + } } compiler_use_next_block(c, end); return 1; @@ -1823,8 +1828,7 @@ compiler_while(struct compiler *c, stmt_ so we need to set an extra line number. */ c->u->u_lineno_set = 0; VISIT(c, expr, s->v.While.test); - ADDOP_JREL(c, JUMP_IF_FALSE, anchor); - ADDOP(c, POP_TOP); + ADDOP_JABS(c, POP_JUMP_IF_FALSE, anchor); } VISIT_SEQ(c, stmt, s->v.While.body); ADDOP_JABS(c, JUMP_ABSOLUTE, loop); @@ -1835,7 +1839,6 @@ compiler_while(struct compiler *c, stmt_ if (constant == -1) { compiler_use_next_block(c, anchor); - ADDOP(c, POP_TOP); ADDOP(c, POP_BLOCK); } compiler_pop_fblock(c, LOOP, loop); @@ -2011,8 +2014,7 @@ compiler_try_except(struct compiler *c, ADDOP(c, DUP_TOP); VISIT(c, expr, handler->v.ExceptHandler.type); ADDOP_I(c, COMPARE_OP, PyCmp_EXC_MATCH); - ADDOP_JREL(c, JUMP_IF_FALSE, except); - ADDOP(c, POP_TOP); + ADDOP_JABS(c, POP_JUMP_IF_FALSE, except); } ADDOP(c, POP_TOP); if (handler->v.ExceptHandler.name) { @@ -2083,8 +2085,6 @@ compiler_try_except(struct compiler *c, } ADDOP_JREL(c, JUMP_FORWARD, end); compiler_use_next_block(c, except); - if (handler->v.ExceptHandler.type) - ADDOP(c, POP_TOP); } ADDOP(c, END_FINALLY); compiler_use_next_block(c, orelse); @@ -2263,8 +2263,7 @@ compiler_assert(struct compiler *c, stmt end = compiler_new_block(c); if (end == NULL) return 0; - ADDOP_JREL(c, JUMP_IF_TRUE, end); - ADDOP(c, POP_TOP); + ADDOP_JABS(c, POP_JUMP_IF_TRUE, end); ADDOP_O(c, LOAD_GLOBAL, assertion_error, names); if (s->v.Assert.msg) { VISIT(c, expr, s->v.Assert.msg); @@ -2272,7 +2271,6 @@ compiler_assert(struct compiler *c, stmt } ADDOP_I(c, RAISE_VARARGS, 1); compiler_use_next_block(c, end); - ADDOP(c, POP_TOP); return 1; } @@ -2867,10 +2865,9 @@ compiler_comprehension_generator(struct for (i = 0; i < n; i++) { expr_ty e = (expr_ty)asdl_seq_GET(gen->ifs, i); VISIT(c, expr, e); - ADDOP_JREL(c, JUMP_IF_FALSE, if_cleanup); + ADDOP_JABS(c, POP_JUMP_IF_FALSE, if_cleanup); NEXT_BLOCK(c); - ADDOP(c, POP_TOP); - } + } if (++gen_index < asdl_seq_LEN(generators)) if (!compiler_comprehension_generator(c, @@ -2908,13 +2905,7 @@ compiler_comprehension_generator(struct compiler_use_next_block(c, skip); } - for (i = 0; i < n; i++) { - ADDOP_I(c, JUMP_FORWARD, 1); - if (i == 0) - compiler_use_next_block(c, if_cleanup); - - ADDOP(c, POP_TOP); - } + compiler_use_next_block(c, if_cleanup); ADDOP_JABS(c, JUMP_ABSOLUTE, start); compiler_use_next_block(c, anchor); diff -r 56747b9abe2d -r 4276bf56dd72 Python/import.c --- a/Python/import.c +++ b/Python/import.c @@ -89,8 +89,9 @@ extern time_t PyOS_GetLastModificationTi Python 3.0a5: 3130 (lexical exception stacking, including POP_EXCEPT) Python 3.1a0: 3140 (optimize list, set and dict comprehensions: change LIST_APPEND and SET_ADD, add MAP_ADD) + Python 3.1a0: 3142 (optimize conditional branches) */ -#define MAGIC (3140 | ((long)'\r'<<16) | ((long)'\n'<<24)) +#define MAGIC (3142 | ((long)'\r'<<16) | ((long)'\n'<<24)) /* Magic word as global; note that _PyImport_Init() can change the value of this global to accommodate for alterations of how the diff -r 56747b9abe2d -r 4276bf56dd72 Python/peephole.c --- a/Python/peephole.c +++ b/Python/peephole.c @@ -13,7 +13,8 @@ #define GETARG(arr, i) ((int)((arr[i+2]<<8) + arr[i+1])) #define UNCONDITIONAL_JUMP(op) (op==JUMP_ABSOLUTE || op==JUMP_FORWARD) -#define ABSOLUTE_JUMP(op) (op==JUMP_ABSOLUTE || op==CONTINUE_LOOP) +#define ABSOLUTE_JUMP(op) (op==JUMP_ABSOLUTE || op==CONTINUE_LOOP \ + || op==POP_JUMP_IF_FALSE || op==POP_JUMP_IF_TRUE) #define GETJUMPTGT(arr, i) (GETARG(arr,i) + (ABSOLUTE_JUMP(arr[i]) ? 0 : i+3)) #define SETARG(arr, i, val) arr[i+2] = val>>8; arr[i+1] = val & 255 #define CODESIZE(op) (HAS_ARG(op) ? 3 : 1) @@ -239,6 +240,8 @@ markblocks(unsigned char *code, Py_ssize case JUMP_FORWARD: case JUMP_IF_FALSE: case JUMP_IF_TRUE: + case POP_JUMP_IF_FALSE: + case POP_JUMP_IF_TRUE: case JUMP_ABSOLUTE: case CONTINUE_LOOP: case SETUP_LOOP: @@ -371,20 +374,31 @@ PyCode_Optimize(PyObject *code, PyObject switch (opcode) { /* Replace UNARY_NOT JUMP_IF_FALSE POP_TOP with - with JUMP_IF_TRUE POP_TOP */ + with JUMP_IF_TRUE POP_TOP + and UNARY_NOT POP_JUMP_IF_FALSE + with POP_JUMP_IF_TRUE */ case UNARY_NOT: - if (codestr[i+1] != JUMP_IF_FALSE || - codestr[i+4] != POP_TOP || - !ISBASICBLOCK(blocks,i,5)) + if ((codestr[i+1] != POP_JUMP_IF_FALSE + && codestr[i+1] != JUMP_IF_FALSE) + || !ISBASICBLOCK(blocks,i,5)) continue; tgt = GETJUMPTGT(codestr, (i+1)); - if (codestr[tgt] != POP_TOP) - continue; - j = GETARG(codestr, i+1) + 1; - codestr[i] = JUMP_IF_TRUE; - SETARG(codestr, i, j); - codestr[i+3] = POP_TOP; - codestr[i+4] = NOP; + if (codestr[i+1] == JUMP_IF_FALSE) { + if (codestr[tgt] != POP_TOP + || codestr[i+4] != POP_TOP) + continue; + j = GETARG(codestr, i+1) + 1; + codestr[i] = JUMP_IF_TRUE; + SETARG(codestr, i, j); + codestr[i+3] = POP_TOP; + codestr[i+4] = NOP; + } + else { + j = GETARG(codestr, i+1); + codestr[i] = POP_JUMP_IF_TRUE; + SETARG(codestr, i, j); + codestr[i+3] = NOP; + } break; /* not a is b --> a is not b @@ -545,6 +559,8 @@ PyCode_Optimize(PyObject *code, PyObject /* Intentional fallthrough */ /* Replace jumps to unconditional jumps */ + case POP_JUMP_IF_FALSE: + case POP_JUMP_IF_TRUE: case FOR_ITER: case JUMP_FORWARD: case JUMP_ABSOLUTE: @@ -621,6 +637,8 @@ PyCode_Optimize(PyObject *code, PyObject case JUMP_ABSOLUTE: case CONTINUE_LOOP: + case POP_JUMP_IF_FALSE: + case POP_JUMP_IF_TRUE: j = addrmap[GETARG(codestr, i)]; SETARG(codestr, i, j); break;