2.5系の最適化

そういえば以前にソースを読もうとして僕もこんがらかっていた部分、、、とか思い出した。

shou 2009/01/26 15:13
2.5.1でもCONSTになるけど、これはバックポートされたもんなんだろうか?

この部分って、2.5だとcompile.cあたりでassemble()->makecode()->optimize_code()と進んで、ここで最適化が行われるんだけど、二項演算子の場合

			/* 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_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;

てな感じになっていて、上記の演算子の場合にfold_binops_*()にて定数畳み込みが行われるらしい。3.0になるとpeephole.cというのが増えたそうなんだけど、こっちは良く知らない。そのうち読もう読もうと思っていながらたぶん忘れる><

しかし、こういう方式だから、

 >>> def foo():
...  return 1+5*3
... 
>>> dis.dis(foo)
  2           0 LOAD_CONST               1 (1) 
              3 LOAD_CONST               4 (15) 
              6 BINARY_ADD           
              7 RETURN_VALUE         

のようになる。なんだかなあ。。。
#これは3.0でも同じっぽい。インタプリタに定数伝播はムチャなのかな。他を知らない・・・

追記:
そんなわけで、実は西尾さんとこで出ていた割り算が最適化された、というのはむしろ3.0の割り算デフォルトがTrue Divideになった副作用。実際2.5でも from __future__ import divisionすれば最適化されるはず。