[Python-checkins] python/dist/src/Python compile.c,2.276,2.277

rhettinger@users.sourceforge.net rhettinger@users.sourceforge.net
Tue, 25 Mar 2003 17:07:57 -0800


Update of /cvsroot/python/python/dist/src/Python
In directory sc8-pr-cvs1:/tmp/cvs-serv12892

Modified Files:
	compile.c 
Log Message:
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".



Index: compile.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Python/compile.c,v
retrieving revision 2.276
retrieving revision 2.277
diff -C2 -d -r2.276 -r2.277
*** compile.c	24 Mar 2003 17:22:24 -0000	2.276
--- compile.c	26 Mar 2003 01:07:54 -0000	2.277
***************
*** 324,327 ****
--- 324,420 ----
  }
  
+ #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,
***************
*** 367,372 ****
  		co->co_stacksize = stacksize;
  		co->co_flags = flags;
! 		Py_INCREF(code);
! 		co->co_code = code;
  		Py_INCREF(consts);
  		co->co_consts = consts;
--- 460,464 ----
  		co->co_stacksize = stacksize;
  		co->co_flags = flags;
! 		co->co_code = optimize_code(code, consts);
  		Py_INCREF(consts);
  		co->co_consts = consts;