summaryrefslogtreecommitdiffstats
path: root/Python
diff options
context:
space:
mode:
authorRaymond Hettinger <python@rcn.com>2005-01-02 06:17:33 (GMT)
committerRaymond Hettinger <python@rcn.com>2005-01-02 06:17:33 (GMT)
commitc34f8673a194180ab3b258e821f72f25514aa948 (patch)
tree756647bb00c7617ee8d2bca72ff91018b66d8965 /Python
parent64585988af7277aa831c66b971fe726207b38cd1 (diff)
downloadcpython-c34f8673a194180ab3b258e821f72f25514aa948.zip
cpython-c34f8673a194180ab3b258e821f72f25514aa948.tar.gz
cpython-c34f8673a194180ab3b258e821f72f25514aa948.tar.bz2
Teach the peephole optimizer to fold simple constant expressions.
Diffstat (limited to 'Python')
-rw-r--r--Python/compile.c119
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.