summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRaymond Hettinger <python@rcn.com>2003-03-26 01:07:54 (GMT)
committerRaymond Hettinger <python@rcn.com>2003-03-26 01:07:54 (GMT)
commitf6f575ae6fc4b58f8735b6aebaa422d48bedcef4 (patch)
treeebbdb1739641b823f80570b2806dace3adc7db9c
parent590fe02ebdc2ec11347441ae31e71d2d6cd52ad3 (diff)
downloadcpython-f6f575ae6fc4b58f8735b6aebaa422d48bedcef4.zip
cpython-f6f575ae6fc4b58f8735b6aebaa422d48bedcef4.tar.gz
cpython-f6f575ae6fc4b58f8735b6aebaa422d48bedcef4.tar.bz2
SF patch #707257: Improve code generation
Adds a single function to improve generated bytecode. Has a single line attachment point, so it is completely de-coupled from both the compiler and ceval.c. Makes three simple transforms that do not require a basic block analysis or re-ordering of code. Gives improved timings on pystone, pybench, and any code using either "while 1" or "x,y=y,x".
-rw-r--r--Python/compile.c96
1 files changed, 94 insertions, 2 deletions
diff --git a/Python/compile.c b/Python/compile.c
index 6616c58..8c259c1 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -323,6 +323,99 @@ intern_strings(PyObject *tuple)
return 0;
}
+#define GETARG(arr, i) ((int)((arr[i+2]<<8) + arr[i+1]))
+#define UNCONDITIONAL_JUMP(op) (op==JUMP_ABSOLUTE || op==JUMP_FORWARD)
+#define GETJUMPTGT(arr, i) (GETARG(arr,i) + (arr[i]==JUMP_ABSOLUTE ? 0 : i+3))
+#define SETARG(arr, i, val) arr[i+2] = val>>8; arr[i+1] = val & 255
+
+static PyObject *
+optimize_code(PyObject *code, PyObject* consts)
+{
+ int i, j, codelen;
+ int tgt, tgttgt, opcode;
+ unsigned char *codestr;
+
+ /* Make a modifiable copy of the code string */
+ if (!PyString_Check(code))
+ goto exitUnchanged;
+ codelen = PyString_Size(code);
+ codestr = PyMem_Malloc(codelen);
+ if (codestr == NULL)
+ goto exitUnchanged;
+ codestr = memcpy(codestr, PyString_AS_STRING(code), codelen);
+ assert(PyTuple_Check(consts));
+
+ for (i=0 ; i<codelen-7 ; i += HAS_ARG(codestr[i]) ? 3 : 1) {
+ opcode = codestr[i];
+ switch (opcode) {
+
+ /* Skip over LOAD_CONST trueconst JUMP_IF_FALSE xx POP_TOP.
+ Note, only the first opcode is changed, the others still
+ perform normally if they happen to be jump targets. */
+ case LOAD_CONST:
+ j = GETARG(codestr, i);
+ if (codestr[i+3] != JUMP_IF_FALSE ||
+ codestr[i+6] != POP_TOP ||
+ !PyObject_IsTrue(PyTuple_GET_ITEM(consts, j)))
+ continue;
+ codestr[i] = JUMP_FORWARD;
+ SETARG(codestr, i, 4);
+ break;
+
+ /* Replace BUILD_SEQN 2 UNPACK_SEQN 2 with ROT2 JMP+2.
+ Note, these opcodes occur together only in assignment
+ statements. Accordingly, the unpack opcode is never
+ a jump target. */
+ case BUILD_TUPLE:
+ case BUILD_LIST:
+ if (codestr[i+3] != UNPACK_SEQUENCE ||
+ GETARG(codestr, i) != 2 ||
+ GETARG(codestr, i+3) != 2)
+ continue;
+ codestr[i] = ROT_TWO;
+ codestr[i+1] = JUMP_FORWARD;
+ SETARG(codestr, i+1, 2);
+ codestr[i+4] = DUP_TOP; /* Filler codes used as NOPs */
+ codestr[i+5] = POP_TOP;
+ break;
+
+ /* Replace jumps to unconditional jumps */
+ case JUMP_FORWARD:
+ case JUMP_IF_FALSE:
+ case JUMP_IF_TRUE:
+ case JUMP_ABSOLUTE:
+ case CONTINUE_LOOP:
+ case SETUP_LOOP:
+ case SETUP_EXCEPT:
+ case SETUP_FINALLY:
+ tgt = GETJUMPTGT(codestr, i);
+ if (!UNCONDITIONAL_JUMP(codestr[tgt]))
+ continue;
+ tgttgt = GETJUMPTGT(codestr, tgt);
+ if (opcode == JUMP_FORWARD) /* JMP_ABS can go backwards */
+ opcode = JUMP_ABSOLUTE;
+ if (opcode != JUMP_ABSOLUTE && opcode != CONTINUE_LOOP)
+ tgttgt -= i + 3; /* Calc relative jump addr */
+ if (tgttgt < 0) /* No backward relative jumps */
+ continue;
+ codestr[i] = opcode;
+ SETARG(codestr, i, tgttgt);
+ break;
+
+ case EXTENDED_ARG:
+ PyMem_Free(codestr);
+ goto exitUnchanged;
+ }
+ }
+ code = PyString_FromStringAndSize(codestr, codelen);
+ PyMem_Free(codestr);
+ return code;
+
+exitUnchanged:
+ Py_INCREF(code);
+ return code;
+}
+
PyCodeObject *
PyCode_New(int argcount, int nlocals, int stacksize, int flags,
PyObject *code, PyObject *consts, PyObject *names,
@@ -366,8 +459,7 @@ PyCode_New(int argcount, int nlocals, int stacksize, int flags,
co->co_nlocals = nlocals;
co->co_stacksize = stacksize;
co->co_flags = flags;
- Py_INCREF(code);
- co->co_code = code;
+ co->co_code = optimize_code(code, consts);
Py_INCREF(consts);
co->co_consts = consts;
Py_INCREF(names);