PyPy コードリーディングその2

PyPy コードリーディング の続き。

今回は Flow Graph まわり。

読んだときのメモは折角なので ここらへん に置いてあるのでお好きにどうぞ。

取っ掛かり

translatorshell.py を実行した結果から FunctionGraph が取得できたのでそれをつらつら眺めていた。

$ python pypy/bin/translatorshell.py 
[version:WARNING] Errors getting Mercurial information: command does not identify itself as Mercurial
PyPy Translator Frontend

Glue script putting together the various pieces of the translator.
Can be used for interactive testing of the translator.

Example:

    t = Translation(func)
    t.view()                           # control flow graph

    t.annotate([int])                  # pass the list of args types
    t.view()                           # graph + annotations under the mouse

    t.rtype()                          # use low level operations 
    f = t.compile_c()                  # C compilation
    assert f(arg) == func(arg)         # sanity check (for C)
    

Some functions are provided for the benefit of interactive testing.
Try dir(snippet) for list of current snippets.

>>> def aa(x, y): return x + y
... 
>>> t = Translation(aa)
[flowgraph] (__main__:1)aa
>>> t.context._prebuilt_graphs.values()[0]
<FunctionGraph of (__main__:1)aa at 0x952c16c>
>>> g = t.context._prebuilt_graphs.values()[0]
>>> g
<FunctionGraph of (__main__:1)aa at 0x952c16c>
>>> g.__module__
'pypy.objspace.flow.model'

で、これを探るべく pypy.objspace.flow.model を見ていたのでした。

FunctionGraph 周りのクラスとその相関は こんな感じ っぽい。

まあこんなの見るより 本家 を見たほうがいいかも。

これと t.view() で表示される グラフ が非常に参考になる。

これとクラス相関だけでとりあえずなんとかなるっぽい。

試しに定義してみる

で、上記から引数を二つ取って足して返す関数は以下のように定義できそう。

#-*- coding:utf-8 -*-

from pypy.objspace.flow import model
from pypy.interpreter import baseobjspace

from pypy.rpython import rtyper
from pypy.annotation import annrpython


# 引数
x = model.Variable('x')
y = model.Variable('y')

# 演算結果格納
tmpvar = model.Variable('tmp')

# 加算
add_op = model.SpaceOperation('add', [x, y], tmpvar)

# 返り値
retvar = model.Variable('ret')

# 演算するところ
block = model.Block([x, y])
block.operations = [add_op]

# 関数データ
func = model.FunctionGraph('add', block, retvar)

# 返り値ブロックへのリンク
link = model.Link([tmpvar], func.returnblock)
link.prevblock = block

# リンク貼る
block.exits = (link, )

print func
print block
print link
print add_op

ただ、これだけだと分岐やループ周りがまだまだなので、色々試しつつやってみないとダメですねー。