diff options
author | Raymond Hettinger <python@rcn.com> | 2005-01-02 06:17:33 (GMT) |
---|---|---|
committer | Raymond Hettinger <python@rcn.com> | 2005-01-02 06:17:33 (GMT) |
commit | c34f8673a194180ab3b258e821f72f25514aa948 (patch) | |
tree | 756647bb00c7617ee8d2bca72ff91018b66d8965 /Python/compile.c | |
parent | 64585988af7277aa831c66b971fe726207b38cd1 (diff) | |
download | cpython-c34f8673a194180ab3b258e821f72f25514aa948.zip cpython-c34f8673a194180ab3b258e821f72f25514aa948.tar.gz cpython-c34f8673a194180ab3b258e821f72f25514aa948.tar.bz2 |
Teach the peephole optimizer to fold simple constant expressions.
Diffstat (limited to 'Python/compile.c')
-rw-r--r-- | Python/compile.c | 119 |
1 files changed, 118 insertions, 1 deletions
diff --git a/Python/compile.c b/Python/compile.c index ea325ff..15c8436 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -439,6 +439,99 @@ tuple_of_constants(unsigned char *codestr, int n, PyObject *consts) return 1; } +/* Replace LOAD_CONST c1. LOAD_CONST c2 BINOP + with LOAD_CONST binop(c1,c2) + The consts table must still be in list form so that the + new constant can be appended. + Called with codestr pointing to the first LOAD_CONST. + Abandons the transformation if the folding fails (i.e. 1+'a'). */ +static int +fold_binops_on_constants(unsigned char *codestr, PyObject *consts) +{ + PyObject *newconst, *v, *w; + int len_consts, opcode; + + /* Pre-conditions */ + assert(PyList_CheckExact(consts)); + assert(codestr[0] == LOAD_CONST); + assert(codestr[3] == LOAD_CONST); + + /* Create new constant */ + v = PyList_GET_ITEM(consts, GETARG(codestr, 0)); + w = PyList_GET_ITEM(consts, GETARG(codestr, 3)); + opcode = codestr[6]; + switch (opcode) { + case BINARY_POWER: + newconst = PyNumber_Power(v, w, Py_None); + break; + case BINARY_MULTIPLY: + newconst = PyNumber_Multiply(v, w); + break; + case BINARY_DIVIDE: + if (!_Py_QnewFlag) { + newconst = PyNumber_Divide(v, w); + break; + } + /* -Qnew is in effect: fall through to + BINARY_TRUE_DIVIDE */ + case BINARY_TRUE_DIVIDE: + newconst = PyNumber_TrueDivide(v, w); + break; + case BINARY_FLOOR_DIVIDE: + newconst = PyNumber_FloorDivide(v, w); + break; + case BINARY_MODULO: + newconst = PyNumber_Remainder(v, w); + break; + case BINARY_ADD: + newconst = PyNumber_Add(v, w); + break; + case BINARY_SUBTRACT: + newconst = PyNumber_Subtract(v, w); + break; + case BINARY_SUBSCR: + newconst = PyObject_GetItem(v, w); + break; + case BINARY_LSHIFT: + newconst = PyNumber_Lshift(v, w); + break; + case BINARY_RSHIFT: + newconst = PyNumber_Rshift(v, w); + break; + case BINARY_AND: + newconst = PyNumber_And(v, w); + break; + case BINARY_XOR: + newconst = PyNumber_Xor(v, w); + break; + case BINARY_OR: + newconst = PyNumber_Or(v, w); + break; + default: + /* Called with an unknown opcode */ + assert(0); + return 0; + } + if (newconst == NULL) { + PyErr_Clear(); + return 0; + } + + /* Append folded constant into consts table */ + len_consts = PyList_GET_SIZE(consts); + if (PyList_Append(consts, newconst)) { + Py_DECREF(newconst); + return 0; + } + Py_DECREF(newconst); + + /* Write NOP NOP NOP NOP LOAD_CONST newconst */ + memset(codestr, NOP, 4); + codestr[4] = LOAD_CONST; + SETARG(codestr, 4, len_consts); + return 1; +} + static unsigned int * markblocks(unsigned char *code, int len) { @@ -614,7 +707,6 @@ optimize_code(PyObject *code, PyObject* consts, PyObject *names, PyObject *linen h = i - 3 * j; if (h >= 0 && j <= lastlc && - codestr[h] == LOAD_CONST && ISBASICBLOCK(blocks, h, 3*(j+1)) && tuple_of_constants(&codestr[h], j, consts)) { assert(codestr[i] == LOAD_CONST); @@ -640,6 +732,31 @@ optimize_code(PyObject *code, PyObject* consts, PyObject *names, PyObject *linen } break; + /* Fold binary ops on constants. + LOAD_CONST c1 LOAD_CONST c2 BINOP --> LOAD_CONST binop(c1,c2) */ + case BINARY_POWER: + case BINARY_MULTIPLY: + case BINARY_DIVIDE: + case BINARY_TRUE_DIVIDE: + case BINARY_FLOOR_DIVIDE: + case BINARY_MODULO: + case BINARY_ADD: + case BINARY_SUBTRACT: + case BINARY_SUBSCR: + case BINARY_LSHIFT: + case BINARY_RSHIFT: + case BINARY_AND: + case BINARY_XOR: + case BINARY_OR: + if (lastlc >= 2 && + ISBASICBLOCK(blocks, i-6, 7) && + fold_binops_on_constants(&codestr[i-6], consts)) { + i -= 2; + assert(codestr[i] == LOAD_CONST); + cumlc = 1; + } + break; + /* Simplify conditional jump to conditional jump where the result of the first test implies the success of a similar test or the failure of the opposite test. |