Marking a function prototype as being "persistent"

Hello and happy new year,

I'm using LLVM to JIT-compile the XL programming language. I've recently added a whole-program optimization phase that gives excellent results, but I noticed that the StripDeadPrototypesPass was removing all references to my runtime support functions.

Apparently, this depends on the oddly-named UnitAtATime parameter. Set it to false. Try again. Suggestion: what about a comment explaining what "UnitAtATime" means :slight_smile:

Even then, my runtime function prorotypes are still being stripped away by the GlobalDCE added by createStandardLTOPasses.

So my question is: what is the correct, officially recommended way to reference runtime functions so that global DCE won't get rid of them? Or am I supposed to re-create the corresponding Function instances for every translation?

Thank you in advance for enlightening me
Christophe

Hi Christophe,

I'm using LLVM to JIT-compile the XL programming language. I've recently added a whole-program optimization phase that gives excellent results, but I noticed that the StripDeadPrototypesPass was removing all references to my runtime support functions.

why is that a problem?

Apparently, this depends on the oddly-named UnitAtATime parameter. Set it to false. Try again. Suggestion: what about a comment explaining what "UnitAtATime" means :slight_smile:

If UnitAtATime is false this means that you are optimizing functions as you are
generating them, rather than first generating all functions and other globals
and only then optimizing. It's basically a historical anachronism coming from
the way GCC used to work.

Even then, my runtime function prorotypes are still being stripped away by the GlobalDCE added by createStandardLTOPasses.

Sure, and why not? Unused prototypes are not used for anything, they won't
turn up in the generated code for example.

So my question is: what is the correct, officially recommended way to reference runtime functions so that global DCE won't get rid of them? Or am I supposed to re-create the corresponding Function instances for every translation?

There's some kind of disconnect here, so you need to explain more :slight_smile:

Ciao, Duncan.

Presumably since he's using the JIT he's generating more code later
that uses the runtime functions, which he wants to be marked as
available.

The disconnect is wanting to apply whole-program/LTO type
optimizations before you have the whole program.

I think the answer is to not use the standard LTO passes and to create
your own versions that are careful not to do things like delete types
and prototypes that you might need later.

Reid

So my question is: what is the correct, officially recommended way to reference runtime functions so that global DCE won't get rid of them? Or am I supposed to re-create the corresponding Function instances for every translation?

There's some kind of disconnect here, so you need to explain more :slight_smile:

Presumably since he's using the JIT he's generating more code later
that uses the runtime functions, which he wants to be marked as
available.

That's correct. Basically, when my runtime decides to JIT some code, it generates a top-level entry point, all the required functions, and then runs LTO on the result. One reason I want LTO is inlining.

The disconnect is wanting to apply whole-program/LTO type
optimizations before you have the whole program.

This is a dynamic language. Part of the program source may be a result of previous evaluations, so there's now way to even know when I have the whole program. That doesn't mean I don't want to inline.

I think the answer is to not use the standard LTO passes and to create
your own versions that are careful not to do things like delete types
and prototypes that you might need later.

But standard passes exist for a reason. I tried the approach you suggest, and since I did it (around 2.5 I guess), I didn't keep up. That cost me something like 20% in performance compared to standard passes.

Now, copy-pasting standard passes code just to remove the passes I don't want... nuf said.

It's actually easier in my case to recreate the prototypes each time. But I wanted to check first if there wasn't an obvious way I had missed to bump the use count of a global value or function to indicate that one of my own classes has a live pointer to it.

Thanks
Christophe