Issues with IPO optimization passes and JIT


I am working on an LLVM-based JIT for a dynamically typed language
(, and would like to commend the LLVM team on an
awesome piece of work. One issue I ran into that I was hoping for
some clarification. Nominally, I had started out by performing code
generation from the AST into a function that was added to the current
module. I then ran a PassManager on that module to optimize the
function -- this included several IPO passes (the entire list from -O3
for opt, in fact). I ran the optimizer after each function was
generated. I found that when I tried to execute functions via the
JIT, I got unexpected and incorrect results -- for example, calling
Invoke on a function would execute the wrong function. The only
solution was to replace the PassManager with a FunctionPassManager
(following the example in the tutorial), and keep only basic block and
function-level optimization steps. Is this expected behavior? Is it
documented? Should it be considered a bug?

Thanks in advance for any clarification.

Were you running the Internalize pass? You should only do that on a finished program on which absolutely no new functions can possibly be added.

As an aside, if you remove Internalize you'll find that the other IPO functions do very little or nothing and should probably be removed.


Samit Basu wrote:

The general issue is that IPO can do very little safely unless the entire program is already present. As Nicholas mentioned, the Internalize pass is used to mark that this has happened, allowing the IPO passes to make assumptions that would not be safe otherwise. If you're generating code a function at a time, you should not be running internalize, in which case running IPO passes is probably also a waste.