From 3d8cfd2a2d24b44aab6eafa4e1293508b45d7eec Mon Sep 17 00:00:00 2001 From: Antoine Pitrou Date: Fri, 11 Mar 2011 17:27:02 +0100 Subject: Issue #11244: The peephole optimizer is now able to constant-fold arbitrarily complex expressions. This also fixes a 3.2 regression where operations involving negative numbers were not constant-folded. --- Python/peephole.c | 167 +++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 120 insertions(+), 47 deletions(-) (limited to 'Python/peephole.c') diff --git a/Python/peephole.c b/Python/peephole.c index f972e1611e..ab96ce9def 100644 --- a/Python/peephole.c +++ b/Python/peephole.c @@ -23,6 +23,64 @@ #define ISBASICBLOCK(blocks, start, bytes) \ (blocks[start]==blocks[start+bytes-1]) + +#define CONST_STACK_CREATE() { \ + const_stack_size = 256; \ + const_stack = PyMem_New(PyObject *, const_stack_size); \ + load_const_stack = PyMem_New(Py_ssize_t, const_stack_size); \ + if (!const_stack || !load_const_stack) { \ + PyErr_NoMemory(); \ + goto exitError; \ + } \ + } + +#define CONST_STACK_DELETE() do { \ + if (const_stack) \ + PyMem_Free(const_stack); \ + if (load_const_stack) \ + PyMem_Free(load_const_stack); \ + } while(0) + +#define CONST_STACK_LEN() (const_stack_top + 1) + +#define CONST_STACK_PUSH_OP(i) do { \ + PyObject *_x; \ + assert(codestr[i] == LOAD_CONST); \ + assert(PyList_GET_SIZE(consts) > GETARG(codestr, i)); \ + _x = PyList_GET_ITEM(consts, GETARG(codestr, i)); \ + if (++const_stack_top >= const_stack_size) { \ + const_stack_size *= 2; \ + PyMem_Resize(const_stack, PyObject *, const_stack_size); \ + PyMem_Resize(load_const_stack, Py_ssize_t, const_stack_size); \ + if (!const_stack || !load_const_stack) { \ + PyErr_NoMemory(); \ + goto exitError; \ + } \ + } \ + load_const_stack[const_stack_top] = i; \ + const_stack[const_stack_top] = _x; \ + in_consts = 1; \ + } while(0) + +#define CONST_STACK_RESET() do { \ + const_stack_top = -1; \ + } while(0) + +#define CONST_STACK_TOP(x) \ + const_stack[const_stack_top] + +#define CONST_STACK_LASTN(i) \ + &const_stack[const_stack_top - i + 1] + +#define CONST_STACK_POP(i) do { \ + assert(const_stack_top + 1 >= i); \ + const_stack_top -= i; \ + } while(0) + +#define CONST_STACK_OP_LASTN(i) \ + ((const_stack_top >= i - 1) ? load_const_stack[const_stack_top - i + 1] : -1) + + /* Replace LOAD_CONST c1. LOAD_CONST c2 ... LOAD_CONST cn BUILD_TUPLE n with LOAD_CONST (c1, c2, ... cn). The consts table must still be in list form so that the @@ -33,17 +91,14 @@ test; for BUILD_SET it assembles a frozenset rather than a tuple. */ static int -tuple_of_constants(unsigned char *codestr, Py_ssize_t n, PyObject *consts) +tuple_of_constants(unsigned char *codestr, Py_ssize_t n, + PyObject *consts, PyObject **objs) { PyObject *newconst, *constant; - Py_ssize_t i, arg, len_consts; + Py_ssize_t i, len_consts; /* Pre-conditions */ assert(PyList_CheckExact(consts)); - assert(codestr[n*3] == BUILD_TUPLE || codestr[n*3] == BUILD_LIST || codestr[n*3] == BUILD_SET); - assert(GETARG(codestr, (n*3)) == n); - for (i=0 ; i= 0 && - j <= lastlc && + if (j == 0) + break; + h = CONST_STACK_OP_LASTN(j); + assert((h >= 0 || CONST_STACK_LEN() < j)); + if (h >= 0 && j > 0 && j <= CONST_STACK_LEN() && ((opcode == BUILD_TUPLE && - ISBASICBLOCK(blocks, h, 3*(j+1))) || + ISBASICBLOCK(blocks, h, i-h+3)) || ((opcode == BUILD_LIST || opcode == BUILD_SET) && codestr[i+3]==COMPARE_OP && - ISBASICBLOCK(blocks, h, 3*(j+2)) && + ISBASICBLOCK(blocks, h, i-h+6) && (GETARG(codestr,i+3)==6 || GETARG(codestr,i+3)==7))) && - tuple_of_constants(&codestr[h], j, consts)) { + tuple_of_constants(&codestr[i], j, consts, CONST_STACK_LASTN(j))) { assert(codestr[i] == LOAD_CONST); - cumlc = 1; + memset(&codestr[h], NOP, i - h); + CONST_STACK_POP(j); + CONST_STACK_PUSH_OP(i); break; } if (codestr[i+3] != UNPACK_SEQUENCE || @@ -482,10 +542,12 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names, } else if (j == 2) { codestr[i] = ROT_TWO; memset(codestr+i+1, NOP, 5); + CONST_STACK_RESET(); } else if (j == 3) { codestr[i] = ROT_THREE; codestr[i+1] = ROT_TWO; memset(codestr+i+2, NOP, 4); + CONST_STACK_RESET(); } break; @@ -504,12 +566,18 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names, 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)) { + /* NOTE: LOAD_CONST is saved at `i-2` since it has an arg + while BINOP hasn't */ + h = CONST_STACK_OP_LASTN(2); + assert((h >= 0 || CONST_STACK_LEN() < 2)); + if (h >= 0 && + ISBASICBLOCK(blocks, h, i-h+1) && + fold_binops_on_constants(&codestr[i], consts, CONST_STACK_LASTN(2))) { i -= 2; + memset(&codestr[h], NOP, i - h); assert(codestr[i] == LOAD_CONST); - cumlc = 1; + CONST_STACK_POP(2); + CONST_STACK_PUSH_OP(i); } break; @@ -518,12 +586,15 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names, case UNARY_NEGATIVE: case UNARY_INVERT: case UNARY_POSITIVE: - if (lastlc >= 1 && - ISBASICBLOCK(blocks, i-3, 4) && - fold_unaryops_on_constants(&codestr[i-3], consts)) { + h = CONST_STACK_OP_LASTN(1); + assert((h >= 0 || CONST_STACK_LEN() < 1)); + if (h >= 0 && + ISBASICBLOCK(blocks, h, i-h+1) && + fold_unaryops_on_constants(&codestr[i-3], consts, CONST_STACK_TOP())) { i -= 2; assert(codestr[i] == LOAD_CONST); - cumlc = 1; + CONST_STACK_POP(1); + CONST_STACK_PUSH_OP(i); } break; @@ -680,6 +751,7 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names, assert(h + nops == codelen); code = PyBytes_FromStringAndSize((char *)codestr, h); + CONST_STACK_DELETE(); PyMem_Free(addrmap); PyMem_Free(codestr); PyMem_Free(blocks); @@ -689,6 +761,7 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names, code = NULL; exitUnchanged: + CONST_STACK_DELETE(); if (blocks != NULL) PyMem_Free(blocks); if (addrmap != NULL) -- cgit v1.2.1 From 312c21bb172f56ba90c4c06e2873ceac1170aa18 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Tue, 15 Mar 2011 15:03:36 -0700 Subject: Issue 11510: Fix BUILD_SET optimizer bug. --- Python/peephole.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'Python/peephole.c') diff --git a/Python/peephole.c b/Python/peephole.c index ab96ce9def..4bc65dcc31 100644 --- a/Python/peephole.c +++ b/Python/peephole.c @@ -535,7 +535,8 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names, } if (codestr[i+3] != UNPACK_SEQUENCE || !ISBASICBLOCK(blocks,i,6) || - j != GETARG(codestr, i+3)) + j != GETARG(codestr, i+3) || + opcode == BUILD_SET) continue; if (j == 1) { memset(codestr+i, NOP, 6); -- cgit v1.2.1 From 07853354ede24bc0033485b335e0859b8212a429 Mon Sep 17 00:00:00 2001 From: Mark Dickinson Date: Wed, 23 Mar 2011 17:59:37 +0000 Subject: Issue #11244: Remove outdated peepholer check that was preventing the peepholer from folding -0 and -0.0. Thanks Eugene Toder for the patch. --- Python/peephole.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'Python/peephole.c') diff --git a/Python/peephole.c b/Python/peephole.c index 4bc65dcc31..69f61617f8 100644 --- a/Python/peephole.c +++ b/Python/peephole.c @@ -238,7 +238,7 @@ fold_binops_on_constants(unsigned char *codestr, PyObject *consts, PyObject **ob static int fold_unaryops_on_constants(unsigned char *codestr, PyObject *consts, PyObject *v) { - PyObject *newconst=NULL/*, *v*/; + PyObject *newconst; Py_ssize_t len_consts; int opcode; @@ -250,9 +250,7 @@ fold_unaryops_on_constants(unsigned char *codestr, PyObject *consts, PyObject *v opcode = codestr[3]; switch (opcode) { case UNARY_NEGATIVE: - /* Preserve the sign of -0.0 */ - if (PyObject_IsTrue(v) == 1) - newconst = PyNumber_Negative(v); + newconst = PyNumber_Negative(v); break; case UNARY_INVERT: newconst = PyNumber_Invert(v); -- cgit v1.2.1 From 4e7a29bf47bd58f536731ef33916b6518898760f Mon Sep 17 00:00:00 2001 From: Stefan Krah Date: Wed, 21 Sep 2011 19:08:39 +0200 Subject: Issue #13002: Fix Visual Studio warning (not enough actual parameters). --- Python/peephole.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Python/peephole.c') diff --git a/Python/peephole.c b/Python/peephole.c index 781498ecf2..705622f18e 100644 --- a/Python/peephole.c +++ b/Python/peephole.c @@ -66,7 +66,7 @@ const_stack_top = -1; \ } while(0) -#define CONST_STACK_TOP(x) \ +#define CONST_STACK_TOP() \ const_stack[const_stack_top] #define CONST_STACK_LASTN(i) \ -- cgit v1.2.1 From d1d013c01c268d869597b35cbcd8b5d7c5baf2ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20v=2E=20L=C3=B6wis?= Date: Wed, 28 Sep 2011 07:41:54 +0200 Subject: Implement PEP 393. --- Python/peephole.c | 18 ------------------ 1 file changed, 18 deletions(-) (limited to 'Python/peephole.c') diff --git a/Python/peephole.c b/Python/peephole.c index 705622f18e..5d536779ac 100644 --- a/Python/peephole.c +++ b/Python/peephole.c @@ -183,24 +183,6 @@ fold_binops_on_constants(unsigned char *codestr, PyObject *consts, PyObject **ob break; case BINARY_SUBSCR: newconst = PyObject_GetItem(v, w); - /* #5057: if v is unicode, there might be differences between - wide and narrow builds in cases like '\U00012345'[0]. - Wide builds will return a non-BMP char, whereas narrow builds - will return a surrogate. In both the cases skip the - optimization in order to produce compatible pycs. - */ - if (newconst != NULL && - PyUnicode_Check(v) && PyUnicode_Check(newconst)) { - Py_UNICODE ch = PyUnicode_AS_UNICODE(newconst)[0]; -#ifdef Py_UNICODE_WIDE - if (ch > 0xFFFF) { -#else - if (ch >= 0xD800 && ch <= 0xDFFF) { -#endif - Py_DECREF(newconst); - return 0; - } - } break; case BINARY_LSHIFT: newconst = PyNumber_Lshift(v, w); -- cgit v1.2.1