Hi all,
lately I have been experimenting on a similar idea that you are
implementing, i.e. replacing the CPython interpreter loop with an LLVM
JIT. Since I have no more time to work on this, I'd like to share my
results with you, if it can be of any help.
What I've done so far is just a compiler that compiles a code object
when PyEval_EvalFrameEx is going to execute it (and then caches the
machine code), by translating the sequence of opcodes into a sequence
of function calls in LLVM. Every function implements an opcode. So it
is was just matter of turn the switch cases of the interpreter loop
into normal C functions in a separate translation unit, and compile it
with llvm-gcc to a bitcode file that is later loaded by the compiler.
All the opcode functions have the same prototype, they take as an
argument a structure describing the interpreter state, and return an
error code which is used for exception handling (I have experimented
with DWARF exceptions but they gave some 40x slowdown when soft-
exceptions were thrown, i.e. always). Appended to the email there is
an example of the generated code.
Smaller opcodes are inlined, I noticed that inlining everything gives
huge compilation times while inling nothing produce code slower than
the interpreter loop. Your approach of writing LLVM IR from C is
certainly more efficient, cause in my "functional" approach a lot of
time for small opcodes is spent (i think) in extracting the frame,
code, etc.. from the interpreter_state structure. However I think that
you should be careful about "big" opcodes, which could cause the same
problems I had with compilation time and slowdown caused by
instruction cache misses. Calling a function would probably be better
(if the opcode is "big", the function call overhead is negligible).
With the current implementation almost everything (except tracing and
some opcodes I haven't implemented) works, including generators,
exceptions, etc... Most unit tests don't work because, if I understood
correctly, doctest needs tracing to work, but I hand-tested the test
cases and they pass (I have also tried some scripts and
applications).
However this implementation is not intended to be furtherly developed:
my idea was to write a JIT extension a-la-psyco, but inspired to
LuaJIT: write just a compilation pipeline in C/C++ with an LLVM
backend, and the JIT optimizer in pure python to keep the code
maintainable (and easy to experiment with) and avoid the psyco mess.
This is more or less whay pypy is trying to do, but without the
RPython translation chain. And thought for CPython, which still
desperately needs a good JIT.
So this code was just a playground to learn LLVM and evaluate the
compilation times, please don't be too picky if you read it :)
Now the benchmarks: with pybench the gain is around 11% on an Intel
Core 2 Duo compiled at 32bit, something more if compiled at 64bit on
Linux. Nothing impressive, it is more or less the same gain given by
threaded interpreter (and I don't think we can shave off anything else
without resorting to runtime optimization). Of course the gain is only
in the "minimum runtime", on average we lose 10% because of
compilation time (remember that it compiles EVERY function, even the
ones executed only one time).
On long-running applications I have experienced greater speedups.
The code is available at
http://www.di.unipi.it/~ottavian/python-jit-0.01.tar.bz2
. It is based on Python 2.5.2, and is tested on Leopard and Ubuntu
Intrepid 64bit, both with llvm 2.5.
Hope this helps,
Giuseppe
-------------------------------------------------------------------------------
PYBENCH 2.0
-------------------------------------------------------------------------------
* using Python 2.5.2
* disabled garbage collection
* system check interval set to maximum:
2147483647
* using timer: time.time
-------------------------------------------------------------------------------
Benchmark: pyjit34.pybench
-------------------------------------------------------------------------------
Rounds: 10
Warp: 10
Timer: time.time
Machine Details:
Platform ID: Darwin-9.6.0-i386-32bit
Processor: i386
Python:
Executable: /Users/ot/work/experimental/Python-2.5.2-exp/
python.exe
Version: 2.5.2
Compiler: GCC 4.0.1 (Apple Inc. build 5465)
Bits: 32bit
Build: Mar 9 2009 17:01:42 (#r252:60911)
Unicode: UCS2
-------------------------------------------------------------------------------
Comparing with: py25_vanilla.pybench
-------------------------------------------------------------------------------
Rounds: 10
Warp: 10
Timer: time.time
Machine Details:
Platform ID: Darwin-9.6.0-i386-32bit
Processor: i386
Python:
Executable: /tmp/sandbox_b47ad064-e6fd-11dd-996f-001ec21bf2c7/
bin/python
Version: 2.5.2
Compiler: GCC 4.0.1 (Apple Inc. build 5465)
Bits: 32bit
Build: Jan 20 2009 15:31:21 (#r252:60911)
Unicode: UCS2
Test minimum run-time average run-
time
this other diff this
other diff
-------------------------------------------------------------------------------
BuiltinFunctionCalls: 108ms 120ms -10.3% 148ms
135ms +10.1%
BuiltinMethodLookup: 91ms 105ms -13.4% 131ms
112ms +16.4%
CompareFloats: 69ms 78ms -12.1% 93ms
82ms +14.0%
CompareFloatsIntegers: 70ms 85ms -17.6% 93ms
89ms +4.7%
CompareIntegers: 34ms 81ms -58.0% 57ms
84ms -31.8%
CompareInternedStrings: 73ms 85ms -14.1% 94ms
89ms +5.8%
CompareLongs: 63ms 78ms -19.0% 87ms
80ms +8.3%
CompareStrings: 53ms 70ms -24.2% 75ms
73ms +2.6%
CompareUnicode: 81ms 96ms -15.1% 103ms
98ms +5.1%
ConcatStrings: 119ms 120ms -1.1% 140ms
128ms +9.7%
ConcatUnicode: 72ms 70ms +2.6% 94ms
72ms +29.4%
CreateInstances: 120ms 134ms -10.6% 134ms
138ms -2.7%
CreateNewInstances: 108ms 117ms -7.8% 121ms
120ms +0.8%
CreateStringsWithConcat: 110ms 117ms -6.2% 126ms
119ms +6.0%
CreateUnicodeWithConcat: 121ms 120ms +0.9% 138ms
123ms +11.5%
DictCreation: 79ms 83ms -4.4% 96ms
84ms +14.7%
DictWithFloatKeys: 74ms 93ms -20.6% 90ms
98ms -7.7%
DictWithIntegerKeys: 67ms 88ms -23.3% 84ms
89ms -5.7%
DictWithStringKeys: 61ms 80ms -23.5% 78ms
82ms -4.7%
ForLoops: 37ms 69ms -46.9% 52ms
70ms -26.4%
IfThenElse: 57ms 80ms -28.6% 211ms
81ms +160.5%
ListSlicing: 181ms 111ms +63.6% 187ms
117ms +60.2%
NestedForLoops: 64ms 96ms -33.7% 72ms
111ms -35.8%
NormalClassAttribute: 95ms 118ms -19.6% 131ms
121ms +8.7%
NormalInstanceAttribute: 82ms 117ms -30.0% 120ms
120ms -0.2%
PythonFunctionCalls: 101ms 99ms +1.6% 133ms
102ms +29.9%
PythonMethodCalls: 127ms 141ms -10.4% 169ms
145ms +16.1%
Recursion: 123ms 130ms -5.1% 129ms
139ms -7.0%
SecondImport: 82ms 79ms +4.2% 89ms
81ms +10.6%
SecondPackageImport: 87ms 83ms +4.6% 93ms
88ms +6.5%
SecondSubmoduleImport: 110ms 107ms +2.2% 117ms
115ms +1.8%
SimpleComplexArithmetic: 78ms 101ms -22.5% 128ms
103ms +23.6%
SimpleDictManipulation: 79ms 88ms -9.9% 113ms
90ms +25.1%
SimpleFloatArithmetic: 64ms 94ms -31.8% 115ms
97ms +18.6%
SimpleIntFloatArithmetic: 54ms 78ms -30.5% 104ms
80ms +29.3%
SimpleIntegerArithmetic: 56ms 78ms -28.3% 105ms
82ms +29.2%
SimpleListManipulation: 69ms 83ms -16.5% 96ms
85ms +12.3%
SimpleLongArithmetic: 87ms 104ms -16.5% 137ms
108ms +26.2%
SmallLists: 103ms 122ms -14.9% 134ms
130ms +2.7%
SmallTuples: 101ms 105ms -3.8% 135ms
110ms +23.1%
SpecialClassAttribute: 92ms 116ms -20.5% 130ms
119ms +9.3%
SpecialInstanceAttribute: 151ms 179ms -15.5% 189ms
183ms +3.1%
StringMappings: 155ms 160ms -2.9% 168ms
164ms +2.2%
StringPredicates: 138ms 143ms -3.7% 159ms
146ms +8.4%
StringSlicing: 105ms 109ms -4.0% 117ms
117ms -0.1%
TryExcept: 54ms 71ms -24.1% 95ms
72ms +31.8%
TryRaiseExcept: 93ms 94ms -0.1% 99ms
96ms +3.0%
TupleSlicing: 113ms 112ms +0.9% 214ms
119ms +80.4%
UnicodeMappings: 99ms 100ms -0.3% 112ms
103ms +9.0%
UnicodePredicates: 107ms 106ms +0.5% 121ms
109ms +10.4%
UnicodeProperties: 91ms 98ms -7.2% 112ms
102ms +9.9%
UnicodeSlicing: 109ms 117ms -6.7% 121ms
122ms -0.9%
-------------------------------------------------------------------------------
Totals: 4718ms 5308ms -11.1% 6186ms
5522ms +12.0%
(this=pyjit34.pybench, other=py25_vanilla.pybench)
GENERATED CODE
==============
for i in [1, 2, 3]:
if i == 2:
print i
1 0 SETUP_LOOP 45 (to 48)
3 LOAD_CONST 0 (1)
6 LOAD_CONST 1 (2)
9 LOAD_CONST 2 (3)
12 BUILD_LIST 3
15 GET_ITER
>> 16 FOR_ITER 28 (to 47)
19 STORE_NAME 0 (i)
2 22 LOAD_NAME 0 (i)
25 LOAD_CONST 1 (2)
28 COMPARE_OP 2 (==)
31 JUMP_IF_FALSE 9 (to 43)
34 POP_TOP
3 35 LOAD_NAME 0 (i)
38 PRINT_ITEM
39 PRINT_NEWLINE
40 JUMP_ABSOLUTE 16
>> 43 POP_TOP
44 JUMP_ABSOLUTE 16
>> 47 POP_BLOCK
>> 48 LOAD_CONST 3 (None)
51 RETURN_VALUE
define %struct.PyObject* @bytecode_at_12102064(%struct.PyFrameObject*
%f, %struct.PyThreadState* %tstate, i32 %throwflag) {
entry:
%st = alloca %struct.interpreter_state ; <
%struct.interpreter_state*> [#uses=20]
%0 = getelementptr %struct.interpreter_state* %st, i32 0, i32 0 ; <
%struct.PyFrameObject**> [#uses=4]
store %struct.PyFrameObject* %f, %struct.PyFrameObject** %0, align 8
%1 = getelementptr %struct.PyFrameObject* %f, i32 0, i32 9 ; <
%struct.PyObject***> [#uses=2]
%2 = load %struct.PyObject*** %1, align 4 ; <%struct.PyObject**>
[#uses=1]
%3 = getelementptr %struct.interpreter_state* %st, i32 0, i32 1 ; <
%struct.PyObject***> [#uses=23]
store %struct.PyObject** %2, %struct.PyObject*** %3, align 4
store %struct.PyObject** null, %struct.PyObject*** %1, align 4
%4 = getelementptr %struct.interpreter_state* %st, i32 0, i32 2 ; <
%struct.PyThreadState**> [#uses=2]
store %struct.PyThreadState* %tstate, %struct.PyThreadState** %4,
align 8
%5 = getelementptr %struct.PyFrameObject* %f, i32 0, i32 4 ; <
%struct.PyCodeObject**> [#uses=1]
%6 = load %struct.PyCodeObject** %5, align 4 ; <
%struct.PyCodeObject*> [#uses=3]
%7 = getelementptr %struct.interpreter_state* %st, i32 0, i32 3 ; <
%struct.PyCodeObject**> [#uses=1]
store %struct.PyCodeObject* %6, %struct.PyCodeObject** %7, align 4
%8 = getelementptr %struct.PyCodeObject* %6, i32 0, i32 8 ; <
%struct.PyObject**> [#uses=1]
%9 = load %struct.PyObject** %8, align 4 ; <%struct.PyObject*>
[#uses=1]
%10 = getelementptr %struct.interpreter_state* %st, i32 0, i32 4 ; <
%struct.PyObject**> [#uses=1]
store %struct.PyObject* %9, %struct.PyObject** %10, align 8
%11 = getelementptr %struct.PyCodeObject* %6, i32 0, i32 7 ; <
%struct.PyObject**> [#uses=1]
%12 = load %struct.PyObject** %11, align 4 ; <%struct.PyObject*>
[#uses=1]
%13 = getelementptr %struct.interpreter_state* %st, i32 0, i32 5 ; <
%struct.PyObject**> [#uses=6]
store %struct.PyObject* %12, %struct.PyObject** %13, align 4
%14 = getelementptr %struct.PyFrameObject* %f, i32 0, i32 19, i32
0 ; <%struct.PyObject**> [#uses=1]
%15 = getelementptr %struct.interpreter_state* %st, i32 0, i32 6 ; <
%struct.PyObject***> [#uses=1]
store %struct.PyObject** %14, %struct.PyObject*** %15, align 8
%16 = getelementptr %struct.interpreter_state* %st, i32 0, i32 7 ;
<i32*> [#uses=4]
store i32 1, i32* %16, align 4
%17 = getelementptr %struct.interpreter_state* %st, i32 0, i32 8 ; <
%struct.PyObject**> [#uses=3]
store %struct.PyObject* null, %struct.PyObject** %17, align 8
%dispatch_to_instr = alloca i32 ; <i32*> [#uses=3]
%18 = getelementptr %struct.PyFrameObject* %f, i32 0, i32 15 ;
<i32*> [#uses=1]
%19 = load i32* %18, align 4 ; <i32> [#uses=1]
%20 = add i32 %19, 1 ; <i32> [#uses=1]
store i32 %20, i32* %dispatch_to_instr
%21 = icmp eq i32 %throwflag, 0 ; <i1> [#uses=1]
br i1 %21, label %dispatch, label %gen_throw
gen_throw: ; preds = %entry
store i32 2, i32* %16, align 4
br label %block_end
end: ; preds = %block_end, %dispatch
%22 = load %struct.PyObject** %17, align 8 ; <%struct.PyObject*>
[#uses=1]
ret %struct.PyObject* %22
dispatch: ; preds = %block_end, %entry
%23 = load i32* %dispatch_to_instr ; <i32> [#uses=1]
switch i32 %23, label %end [
i32 0, label %__op_0
i32 3, label %__op_3
i32 6, label %__op_6
i32 9, label %__op_9
i32 12, label %__op_12
i32 15, label %__op_15
i32 16, label %__op_16
i32 19, label %__op_19
i32 22, label %__op_22
i32 25, label %__op_25
i32 28, label %__op_28
i32 31, label %__op_31
i32 34, label %__op_34
i32 35, label %__op_35
i32 38, label %__op_38
i32 39, label %__op_39
i32 40, label %__op_16
i32 43, label %__op_43
i32 44, label %__op_16
i32 47, label %__op_47
i32 48, label %__op_48
i32 51, label %__op_51
]
__op_0: ; preds = %dispatch
%24 = call fastcc i32 @opcode_SETUP_LOOP(%struct.interpreter_state*
%st, i32 0, i32 120, i32 45) ; <i32> [#uses=1]
%25 = icmp eq i32 %24, 0 ; <i1> [#uses=1]
br i1 %25, label %__op_3, label %block_end
__op_3: ; preds = %__op_0, %dispatch
%26 = load %struct.PyObject** %13, align 4 ; <%struct.PyObject*>
[#uses=1]
%27 = bitcast %struct.PyObject* %26 to %struct.PyTupleObject* ; <
%struct.PyTupleObject*> [#uses=1]
%28 = getelementptr %struct.PyTupleObject* %27, i32 0, i32 3, i32
0 ; <%struct.PyObject**> [#uses=1]
%29 = load %struct.PyObject** %28, align 4 ; <%struct.PyObject*>
[#uses=2]
%30 = getelementptr %struct.PyObject* %29, i32 0, i32 0 ; <i32*>
[#uses=2]
%31 = load i32* %30, align 4 ; <i32> [#uses=1]
%32 = add i32 %31, 1 ; <i32> [#uses=1]
store i32 %32, i32* %30, align 4
%33 = load %struct.PyObject*** %3, align 4 ; <%struct.PyObject**>
[#uses=2]
store %struct.PyObject* %29, %struct.PyObject** %33, align 4
%34 = getelementptr %struct.PyObject** %33, i32 1 ; <
%struct.PyObject**> [#uses=1]
store %struct.PyObject** %34, %struct.PyObject*** %3, align 4
br label %__op_6
__op_6: ; preds = %__op_3, %dispatch
%35 = load %struct.PyObject** %13, align 4 ; <%struct.PyObject*>
[#uses=1]
%36 = bitcast %struct.PyObject* %35 to %struct.PyTupleObject* ; <
%struct.PyTupleObject*> [#uses=1]
%37 = getelementptr %struct.PyTupleObject* %36, i32 0, i32 3, i32
1 ; <%struct.PyObject**> [#uses=1]
%38 = load %struct.PyObject** %37, align 4 ; <%struct.PyObject*>
[#uses=2]
%39 = getelementptr %struct.PyObject* %38, i32 0, i32 0 ; <i32*>
[#uses=2]
%40 = load i32* %39, align 4 ; <i32> [#uses=1]
%41 = add i32 %40, 1 ; <i32> [#uses=1]
store i32 %41, i32* %39, align 4
%42 = load %struct.PyObject*** %3, align 4 ; <%struct.PyObject**>
[#uses=2]
store %struct.PyObject* %38, %struct.PyObject** %42, align 4
%43 = getelementptr %struct.PyObject** %42, i32 1 ; <
%struct.PyObject**> [#uses=1]
store %struct.PyObject** %43, %struct.PyObject*** %3, align 4
br label %__op_9
__op_9: ; preds = %__op_6, %dispatch
%44 = load %struct.PyObject** %13, align 4 ; <%struct.PyObject*>
[#uses=1]
%45 = bitcast %struct.PyObject* %44 to %struct.PyTupleObject* ; <
%struct.PyTupleObject*> [#uses=1]
%46 = getelementptr %struct.PyTupleObject* %45, i32 0, i32 3, i32
2 ; <%struct.PyObject**> [#uses=1]
%47 = load %struct.PyObject** %46, align 4 ; <%struct.PyObject*>
[#uses=2]
%48 = getelementptr %struct.PyObject* %47, i32 0, i32 0 ; <i32*>
[#uses=2]
%49 = load i32* %48, align 4 ; <i32> [#uses=1]
%50 = add i32 %49, 1 ; <i32> [#uses=1]
store i32 %50, i32* %48, align 4
%51 = load %struct.PyObject*** %3, align 4 ; <%struct.PyObject**>
[#uses=2]
store %struct.PyObject* %47, %struct.PyObject** %51, align 4
%52 = getelementptr %struct.PyObject** %51, i32 1 ; <
%struct.PyObject**> [#uses=1]
store %struct.PyObject** %52, %struct.PyObject*** %3, align 4
br label %__op_12
__op_12: ; preds = %__op_9, %dispatch
%53 = call fastcc i32 @opcode_BUILD_LIST(%struct.interpreter_state*
%st, i32 12, i32 103, i32 3) ; <i32> [#uses=1]
%54 = icmp eq i32 %53, 0 ; <i1> [#uses=1]
br i1 %54, label %__op_15, label %block_end
__op_15: ; preds = %__op_12, %dispatch
%55 = call fastcc i32 @opcode_GET_ITER(%struct.interpreter_state*
%st, i32 15, i32 68, i32 0) ; <i32> [#uses=1]
%56 = icmp eq i32 %55, 0 ; <i1> [#uses=1]
br i1 %56, label %__op_16, label %block_end
__op_16: ; preds = %dispatch, %__op_43, %bb.i5, %dispatch, %__op_39,
%__op_15, %dispatch
%57 = volatile load i32* @_Py_Ticker, align 4 ; <i32> [#uses=1]
%58 = add i32 %57, -1 ; <i32> [#uses=1]
volatile store i32 %58, i32* @_Py_Ticker, align 4
%59 = volatile load i32* @_Py_Ticker, align 4 ; <i32> [#uses=1]
%.not.i = icmp sgt i32 %59, -1 ; <i1> [#uses=1]
br i1 %.not.i, label %bb3.i, label %bb1.i
bb1.i: ; preds = %__op_16
%60 = load %struct.PyThreadState** %4, align 8 ; <
%struct.PyThreadState*> [#uses=1]
%61 = call fastcc i32 @do_periodic_things(%struct.PyThreadState* %60)
nounwind ; <i32> [#uses=1]
%62 = icmp eq i32 %61, 0 ; <i1> [#uses=1]
br i1 %62, label %bb2.i, label %bb3.i
bb2.i: ; preds = %bb1.i
store i32 2, i32* %16, align 4
%63 = load %struct.PyFrameObject** %0, align 8 ; <
%struct.PyFrameObject*> [#uses=1]
%64 = getelementptr %struct.PyFrameObject* %63, i32 0, i32 15 ;
<i32*> [#uses=1]
store i32 16, i32* %64, align 4
br label %opcode_FOR_ITER.exit
bb3.i: ; preds = %bb1.i, %__op_16
%65 = load %struct.PyObject*** %3, align 4 ; <%struct.PyObject**>
[#uses=1]
%66 = getelementptr %struct.PyObject** %65, i32 -1 ; <
%struct.PyObject**> [#uses=1]
%67 = load %struct.PyObject** %66, align 4 ; <%struct.PyObject*>
[#uses=2]
%68 = getelementptr %struct.PyObject* %67, i32 0, i32 1 ; <
%struct._typeobject**> [#uses=1]
%69 = load %struct._typeobject** %68, align 4 ; <
%struct._typeobject*> [#uses=1]
%70 = getelementptr %struct._typeobject* %69, i32 0, i32 28 ; <
%struct.PyObject* (%struct.PyObject*)**> [#uses=1]
%71 = load %struct.PyObject* (%struct.PyObject*)** %70, align 4 ; <
%struct.PyObject* (%struct.PyObject*)*> [#uses=1]
%72 = call %struct.PyObject* %71(%struct.PyObject* %67) nounwind ; <
%struct.PyObject*> [#uses=2]
%73 = icmp eq %struct.PyObject* %72, null ; <i1> [#uses=1]
br i1 %73, label %bb5.i, label %bb4.i
bb4.i: ; preds = %bb3.i
%74 = load %struct.PyObject*** %3, align 4 ; <%struct.PyObject**>
[#uses=2]
store %struct.PyObject* %72, %struct.PyObject** %74, align 4
%75 = getelementptr %struct.PyObject** %74, i32 1 ; <
%struct.PyObject**> [#uses=1]
store %struct.PyObject** %75, %struct.PyObject*** %3, align 4
br label %opcode_FOR_ITER.exit
bb5.i: ; preds = %bb3.i
%76 = call %struct.PyObject* @PyErr_Occurred() nounwind ; <
%struct.PyObject*> [#uses=1]
%77 = icmp eq %struct.PyObject* %76, null ; <i1> [#uses=1]
br i1 %77, label %bb9.i, label %bb6.i
bb6.i: ; preds = %bb5.i
%78 = load %struct.PyObject** @PyExc_StopIteration, align 4 ; <
%struct.PyObject*> [#uses=1]
%79 = call i32 @PyErr_ExceptionMatches(%struct.PyObject* %78)
nounwind ; <i32> [#uses=1]
%80 = icmp eq i32 %79, 0 ; <i1> [#uses=1]
br i1 %80, label %bb7.i, label %bb8.i
bb7.i: ; preds = %bb6.i
%81 = load %struct.PyFrameObject** %0, align 8 ; <
%struct.PyFrameObject*> [#uses=1]
%82 = getelementptr %struct.PyFrameObject* %81, i32 0, i32 15 ;
<i32*> [#uses=1]
store i32 16, i32* %82, align 4
br label %opcode_FOR_ITER.exit
bb8.i: ; preds = %bb6.i
call void @PyErr_Clear() nounwind
br label %bb9.i
bb9.i: ; preds = %bb8.i, %bb5.i
%83 = load %struct.PyObject*** %3, align 4 ; <%struct.PyObject**>
[#uses=1]
%84 = getelementptr %struct.PyObject** %83, i32 -1 ; <
%struct.PyObject**> [#uses=2]
store %struct.PyObject** %84, %struct.PyObject*** %3, align 4
%85 = load %struct.PyObject** %84, align 4 ; <%struct.PyObject*>
[#uses=3]
%86 = getelementptr %struct.PyObject* %85, i32 0, i32 0 ; <i32*>
[#uses=2]
%87 = load i32* %86, align 4 ; <i32> [#uses=1]
%88 = add i32 %87, -1 ; <i32> [#uses=2]
store i32 %88, i32* %86, align 4
%89 = icmp eq i32 %88, 0 ; <i1> [#uses=1]
br i1 %89, label %bb10.i, label %opcode_FOR_ITER.exit
bb10.i: ; preds = %bb9.i
%90 = getelementptr %struct.PyObject* %85, i32 0, i32 1 ; <
%struct._typeobject**> [#uses=1]
%91 = load %struct._typeobject** %90, align 4 ; <
%struct._typeobject*> [#uses=1]
%92 = getelementptr %struct._typeobject* %91, i32 0, i32 6 ; <void
(%struct.PyObject*)**> [#uses=1]
%93 = load void (%struct.PyObject*)** %92, align 4 ; <void
(%struct.PyObject*)*> [#uses=1]
call void %93(%struct.PyObject* %85) nounwind
br label %opcode_FOR_ITER.exit
opcode_FOR_ITER.exit: ; preds = %bb9.i, %bb2.i, %bb7.i, %bb10.i,
%bb4.i
%94 = phi i32 [ 0, %bb4.i ], [ 2, %bb10.i ], [ 1, %bb7.i ], [ 1,
%bb2.i ], [ 2, %bb9.i ] ; <i32> [#uses=1]
switch i32 %94, label %block_end [
i32 0, label %__op_19
i32 2, label %__op_47
]
__op_19: ; preds = %opcode_FOR_ITER.exit, %dispatch
%95 = call fastcc i32 @opcode_STORE_NAME(%struct.interpreter_state*
%st, i32 19, i32 90, i32 0) ; <i32> [#uses=1]
%96 = icmp eq i32 %95, 0 ; <i1> [#uses=1]
br i1 %96, label %__op_22, label %block_end
__op_22: ; preds = %__op_19, %dispatch
%97 = call fastcc i32 @opcode_LOAD_NAME(%struct.interpreter_state*
%st, i32 22, i32 101, i32 0) ; <i32> [#uses=1]
%98 = icmp eq i32 %97, 0 ; <i1> [#uses=1]
br i1 %98, label %__op_25, label %block_end
__op_25: ; preds = %__op_22, %dispatch
%99 = load %struct.PyObject** %13, align 4 ; <%struct.PyObject*>
[#uses=1]
%100 = bitcast %struct.PyObject* %99 to %struct.PyTupleObject* ; <
%struct.PyTupleObject*> [#uses=1]
%101 = getelementptr %struct.PyTupleObject* %100, i32 0, i32 3, i32
1 ; <%struct.PyObject**> [#uses=1]
%102 = load %struct.PyObject** %101, align 4 ; <%struct.PyObject*>
[#uses=2]
%103 = getelementptr %struct.PyObject* %102, i32 0, i32 0 ; <i32*>
[#uses=2]
%104 = load i32* %103, align 4 ; <i32> [#uses=1]
%105 = add i32 %104, 1 ; <i32> [#uses=1]
store i32 %105, i32* %103, align 4
%106 = load %struct.PyObject*** %3, align 4 ; <%struct.PyObject**>
[#uses=2]
store %struct.PyObject* %102, %struct.PyObject** %106, align 4
%107 = getelementptr %struct.PyObject** %106, i32 1 ; <
%struct.PyObject**> [#uses=1]
store %struct.PyObject** %107, %struct.PyObject*** %3, align 4
br label %__op_28
__op_28: ; preds = %__op_25, %dispatch
%108 = call fastcc i32 @opcode_COMPARE_OP(%struct.interpreter_state*
%st, i32 28, i32 106, i32 2) ; <i32> [#uses=1]
%109 = icmp eq i32 %108, 0 ; <i1> [#uses=1]
br i1 %109, label %__op_31, label %block_end
__op_31: ; preds = %__op_28, %dispatch
%110 = load %struct.PyObject*** %3, align 4 ; <%struct.PyObject**>
[#uses=1]
%111 = getelementptr %struct.PyObject** %110, i32 -1 ; <
%struct.PyObject**> [#uses=1]
%112 = load %struct.PyObject** %111, align 4 ; <%struct.PyObject*>
[#uses=3]
%113 = icmp eq %struct.PyObject* %112, bitcast (%struct.PyIntObject*
@_Py_TrueStruct to %struct.PyObject*) ; <i1> [#uses=1]
br i1 %113, label %is_top_true.exit, label %bb1.i1
bb1.i1: ; preds = %__op_31
%114 = icmp eq %struct.PyObject* %112, bitcast (%struct.PyIntObject*
@_Py_ZeroStruct to %struct.PyObject*) ; <i1> [#uses=1]
br i1 %114, label %is_top_true.exit, label %bb3.i2
bb3.i2: ; preds = %bb1.i1
%115 = call i32 @PyObject_IsTrue(%struct.PyObject* %112) nounwind ;
<i32> [#uses=1]
%116 = icmp sgt i32 %115, 0 ; <i1> [#uses=1]
%retval.i = zext i1 %116 to i32 ; <i32> [#uses=1]
br label %is_top_true.exit
is_top_true.exit: ; preds = %__op_31, %bb1.i1, %bb3.i2
%117 = phi i32 [ %retval.i, %bb3.i2 ], [ 1, %__op_31 ], [ 0,
%bb1.i1 ] ; <i32> [#uses=1]
%118 = icmp eq i32 %117, 0 ; <i1> [#uses=1]
br i1 %118, label %__op_43, label %__op_34
__op_34: ; preds = %is_top_true.exit, %dispatch
%119 = load %struct.PyObject*** %3, align 4 ; <%struct.PyObject**>
[#uses=1]
%120 = getelementptr %struct.PyObject** %119, i32 -1 ; <
%struct.PyObject**> [#uses=2]
store %struct.PyObject** %120, %struct.PyObject*** %3, align 4
%121 = load %struct.PyObject** %120, align 4 ; <%struct.PyObject*>
[#uses=3]
%122 = getelementptr %struct.PyObject* %121, i32 0, i32 0 ; <i32*>
[#uses=2]
%123 = load i32* %122, align 4 ; <i32> [#uses=1]
%124 = add i32 %123, -1 ; <i32> [#uses=2]
store i32 %124, i32* %122, align 4
%125 = icmp eq i32 %124, 0 ; <i1> [#uses=1]
br i1 %125, label %bb.i, label %__op_35
bb.i: ; preds = %__op_34
%126 = getelementptr %struct.PyObject* %121, i32 0, i32 1 ; <
%struct._typeobject**> [#uses=1]
%127 = load %struct._typeobject** %126, align 4 ; <
%struct._typeobject*> [#uses=1]
%128 = getelementptr %struct._typeobject* %127, i32 0, i32 6 ; <void
(%struct.PyObject*)**> [#uses=1]
%129 = load void (%struct.PyObject*)** %128, align 4 ; <void
(%struct.PyObject*)*> [#uses=1]
call void %129(%struct.PyObject* %121) nounwind
br label %__op_35
__op_35: ; preds = %bb.i, %__op_34, %dispatch
%130 = call fastcc i32 @opcode_LOAD_NAME(%struct.interpreter_state*
%st, i32 35, i32 101, i32 0) ; <i32> [#uses=1]
%131 = icmp eq i32 %130, 0 ; <i1> [#uses=1]
br i1 %131, label %__op_38, label %block_end
__op_38: ; preds = %__op_35, %dispatch
%132 = call fastcc i32 @opcode_PRINT_ITEM(%struct.interpreter_state*
%st, i32 38, i32 71, i32 0) ; <i32> [#uses=1]
%133 = icmp eq i32 %132, 0 ; <i1> [#uses=1]
br i1 %133, label %__op_39, label %block_end
__op_39: ; preds = %__op_38, %dispatch
%134 = call fastcc i32 @opcode_PRINT_NEWLINE
(%struct.interpreter_state* %st, i32 39, i32 72, i32 0) ; <i32>
[#uses=1]
%135 = icmp eq i32 %134, 0 ; <i1> [#uses=1]
br i1 %135, label %__op_16, label %block_end
__op_43: ; preds = %is_top_true.exit, %dispatch
%136 = load %struct.PyObject*** %3, align 4 ; <%struct.PyObject**>
[#uses=1]
%137 = getelementptr %struct.PyObject** %136, i32 -1 ; <
%struct.PyObject**> [#uses=2]
store %struct.PyObject** %137, %struct.PyObject*** %3, align 4
%138 = load %struct.PyObject** %137, align 4 ; <%struct.PyObject*>
[#uses=3]
%139 = getelementptr %struct.PyObject* %138, i32 0, i32 0 ; <i32*>
[#uses=2]
%140 = load i32* %139, align 4 ; <i32> [#uses=1]
%141 = add i32 %140, -1 ; <i32> [#uses=2]
store i32 %141, i32* %139, align 4
%142 = icmp eq i32 %141, 0 ; <i1> [#uses=1]
br i1 %142, label %bb.i5, label %__op_16
bb.i5: ; preds = %__op_43
%143 = getelementptr %struct.PyObject* %138, i32 0, i32 1 ; <
%struct._typeobject**> [#uses=1]
%144 = load %struct._typeobject** %143, align 4 ; <
%struct._typeobject*> [#uses=1]
%145 = getelementptr %struct._typeobject* %144, i32 0, i32 6 ; <void
(%struct.PyObject*)**> [#uses=1]
%146 = load void (%struct.PyObject*)** %145, align 4 ; <void
(%struct.PyObject*)*> [#uses=1]
call void %146(%struct.PyObject* %138) nounwind
br label %__op_16
__op_47: ; preds = %opcode_FOR_ITER.exit, %dispatch
%147 = call fastcc i32 @opcode_POP_BLOCK(%struct.interpreter_state*
%st, i32 47, i32 87, i32 0) ; <i32> [#uses=1]
%148 = icmp eq i32 %147, 0 ; <i1> [#uses=1]
br i1 %148, label %__op_48, label %block_end
__op_48: ; preds = %__op_47, %dispatch
%149 = load %struct.PyObject** %13, align 4 ; <%struct.PyObject*>
[#uses=1]
%150 = bitcast %struct.PyObject* %149 to %struct.PyTupleObject* ; <
%struct.PyTupleObject*> [#uses=1]
%151 = getelementptr %struct.PyTupleObject* %150, i32 0, i32 3, i32
3 ; <%struct.PyObject**> [#uses=1]
%152 = load %struct.PyObject** %151, align 4 ; <%struct.PyObject*>
[#uses=2]
%153 = getelementptr %struct.PyObject* %152, i32 0, i32 0 ; <i32*>
[#uses=2]
%154 = load i32* %153, align 4 ; <i32> [#uses=1]
%155 = add i32 %154, 1 ; <i32> [#uses=1]
store i32 %155, i32* %153, align 4
%156 = load %struct.PyObject*** %3, align 4 ; <%struct.PyObject**>
[#uses=2]
store %struct.PyObject* %152, %struct.PyObject** %156, align 4
%157 = getelementptr %struct.PyObject** %156, i32 1 ; <
%struct.PyObject**> [#uses=1]
store %struct.PyObject** %157, %struct.PyObject*** %3, align 4
br label %__op_51
__op_51: ; preds = %__op_48, %dispatch
%158 = load %struct.PyObject*** %3, align 4 ; <%struct.PyObject**>
[#uses=1]
%159 = getelementptr %struct.PyObject** %158, i32 -1 ; <
%struct.PyObject**> [#uses=2]
store %struct.PyObject** %159, %struct.PyObject*** %3, align 4
%160 = load %struct.PyObject** %159, align 4 ; <%struct.PyObject*>
[#uses=1]
store %struct.PyObject* %160, %struct.PyObject** %17, align 8
store i32 8, i32* %16, align 4
%161 = load %struct.PyFrameObject** %0, align 8 ; <
%struct.PyFrameObject*> [#uses=1]
%162 = getelementptr %struct.PyFrameObject* %161, i32 0, i32 15 ;
<i32*> [#uses=1]
store i32 51, i32* %162, align 4
br label %block_end
block_end: ; preds = %__op_51, %__op_47, %__op_39, %__op_38,
%__op_35, %__op_28, %__op_22, %__op_19, %opcode_FOR_ITER.exit,
%__op_15, %__op_12, %__op_0, %gen_throw
%163 = call fastcc i32 @unwind_stack(%struct.interpreter_state* %st,
i32* %dispatch_to_instr) ; <i32> [#uses=1]
%164 = icmp eq i32 %163, 0 ; <i1> [#uses=1]
br i1 %164, label %dispatch, label %end
}