Commit effb3931 authored by Raymond Hettinger's avatar Raymond Hettinger

Adopt some peepholer suggestions from Armin Rigo:

* Use simpler, faster two pass algorithm for markblocks().
* Free the blocks variable if not NULL and exiting without change.
* Verify that the rest of the compiler has not set an exception.
* Make the test for tuple of constants less restrictive.
* Embellish the comment for chained conditional jumps.
parent 0c1b253f
...@@ -406,14 +406,10 @@ tuple_of_constants(unsigned char *codestr, int n, PyObject *consts) ...@@ -406,14 +406,10 @@ tuple_of_constants(unsigned char *codestr, int n, PyObject *consts)
/* Pre-conditions */ /* Pre-conditions */
assert(PyList_CheckExact(consts)); assert(PyList_CheckExact(consts));
assert(codestr[0] == LOAD_CONST);
assert(codestr[n*3] == BUILD_TUPLE); assert(codestr[n*3] == BUILD_TUPLE);
assert(GETARG(codestr, (n*3)) == n); assert(GETARG(codestr, (n*3)) == n);
/* Verify chain of n load_constants */
for (i=0 ; i<n ; i++) for (i=0 ; i<n ; i++)
if (codestr[i*3] != LOAD_CONST) assert(codestr[i*3] == LOAD_CONST);
return 0;
/* Buildup new tuple of constants */ /* Buildup new tuple of constants */
newconst = PyTuple_New(n); newconst = PyTuple_New(n);
...@@ -447,11 +443,13 @@ static unsigned int * ...@@ -447,11 +443,13 @@ static unsigned int *
markblocks(unsigned char *code, int len) markblocks(unsigned char *code, int len)
{ {
unsigned int *blocks = PyMem_Malloc(len*sizeof(int)); unsigned int *blocks = PyMem_Malloc(len*sizeof(int));
int i,j, opcode, oldblock, newblock, blockcnt = 0; int i,j, opcode, blockcnt = 0;
if (blocks == NULL) if (blocks == NULL)
return NULL; return NULL;
memset(blocks, 0, len*sizeof(int)); memset(blocks, 0, len*sizeof(int));
/* Mark labels in the first pass */
for (i=0 ; i<len ; i+=CODESIZE(opcode)) { for (i=0 ; i<len ; i+=CODESIZE(opcode)) {
opcode = code[i]; opcode = code[i];
switch (opcode) { switch (opcode) {
...@@ -465,16 +463,15 @@ markblocks(unsigned char *code, int len) ...@@ -465,16 +463,15 @@ markblocks(unsigned char *code, int len)
case SETUP_EXCEPT: case SETUP_EXCEPT:
case SETUP_FINALLY: case SETUP_FINALLY:
j = GETJUMPTGT(code, i); j = GETJUMPTGT(code, i);
oldblock = blocks[j]; blocks[j] = 1;
newblock = ++blockcnt;
for (; j<len ; j++) {
if (blocks[j] != (unsigned)oldblock)
break;
blocks[j] = newblock;
}
break; break;
} }
} }
/* Build block numbers in the second pass */
for (i=0 ; i<len ; i++) {
blockcnt += blocks[i]; /* increment blockcnt over labels */
blocks[i] = blockcnt;
}
return blocks; return blocks;
} }
...@@ -503,9 +500,13 @@ optimize_code(PyObject *code, PyObject* consts, PyObject *names, PyObject *linen ...@@ -503,9 +500,13 @@ optimize_code(PyObject *code, PyObject* consts, PyObject *names, PyObject *linen
int *addrmap = NULL; int *addrmap = NULL;
int new_line, cum_orig_line, last_line, tabsiz; int new_line, cum_orig_line, last_line, tabsiz;
int cumlc=0, lastlc=0; /* Count runs of consecutive LOAD_CONST codes */ int cumlc=0, lastlc=0; /* Count runs of consecutive LOAD_CONST codes */
unsigned int *blocks; unsigned int *blocks = NULL;
char *name; char *name;
/* Bail out if an exception is set */
if (PyErr_Occurred())
goto exitUnchanged;
/* Bypass optimization when the lineno table is too complex */ /* Bypass optimization when the lineno table is too complex */
assert(PyString_Check(lineno_obj)); assert(PyString_Check(lineno_obj));
lineno = PyString_AS_STRING(lineno_obj); lineno = PyString_AS_STRING(lineno_obj);
...@@ -614,7 +615,7 @@ optimize_code(PyObject *code, PyObject* consts, PyObject *names, PyObject *linen ...@@ -614,7 +615,7 @@ optimize_code(PyObject *code, PyObject* consts, PyObject *names, PyObject *linen
j = GETARG(codestr, i); j = GETARG(codestr, i);
h = i - 3 * j; h = i - 3 * j;
if (h >= 0 && if (h >= 0 &&
j == lastlc && j <= lastlc &&
codestr[h] == LOAD_CONST && codestr[h] == LOAD_CONST &&
ISBASICBLOCK(blocks, h, 3*(j+1)) && ISBASICBLOCK(blocks, h, 3*(j+1)) &&
tuple_of_constants(&codestr[h], j, consts)) { tuple_of_constants(&codestr[h], j, consts)) {
...@@ -647,6 +648,8 @@ optimize_code(PyObject *code, PyObject* consts, PyObject *names, PyObject *linen ...@@ -647,6 +648,8 @@ optimize_code(PyObject *code, PyObject* consts, PyObject *names, PyObject *linen
result of the first test implies the success of a similar result of the first test implies the success of a similar
test or the failure of the opposite test. test or the failure of the opposite test.
Arises in code like: Arises in code like:
"if a and b:"
"if a or b:"
"a and b or c" "a and b or c"
"a and b and c" "a and b and c"
x:JUMP_IF_FALSE y y:JUMP_IF_FALSE z --> x:JUMP_IF_FALSE z x:JUMP_IF_FALSE y y:JUMP_IF_FALSE z --> x:JUMP_IF_FALSE z
...@@ -755,6 +758,8 @@ optimize_code(PyObject *code, PyObject* consts, PyObject *names, PyObject *linen ...@@ -755,6 +758,8 @@ optimize_code(PyObject *code, PyObject* consts, PyObject *names, PyObject *linen
return code; return code;
exitUnchanged: exitUnchanged:
if (blocks != NULL)
PyMem_Free(blocks);
if (addrmap != NULL) if (addrmap != NULL)
PyMem_Free(addrmap); PyMem_Free(addrmap);
if (codestr != NULL) if (codestr != NULL)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment