The newlib C library provides iprintf(), a restricted version of printf
without support for floating-point formatting. I'd like to add an
optimization which turns calls to printf() into calls to iprintf() if
the format string has no floating point specifiers.
Cool, ok. I can see how this would be very useful for a variety of embedded systems.
At the moment I've got this working locally by adding code to the
simplify-libcalls pass. However this will break on targets where
iprintf() isn't available. Is there a sensible place to add information
about which library functions are available for a particular target?
I'd suggest adding a bool argument (HasIPrintf) to the createSimplifyLibCallsPass function and the pass constructor. Then clang (or whatever is setting up the pass manager) can query the appropriate target info to pass down this flag.
Sorry to jump into something midstream, but I just happened to read the above paragraph and thought I should comment. Adding a boolean argument to a pass's constructor method is one of the things I have learned not to do. If I ever give a "How Not to Write an LLVM Pass" talk, this will be one of the things in the list.
The problem with boolean default arguments in pass constructors is that they make a pass more difficult to use within the opt and bugpoint tools. Inevitably you'll find some bug that only occurs when the flag is set to a non-default value, you'll fire up bugpoint, pass in the arguments printed by your tool's -debug-pass=Arguments option, and then wonder why the bug doesn't trigger. Eventually you find out that it's due to the boolean flag you put into the constructor not being set the way you want. You then have to manually change the constructor in the source code, recompile, run bugpoint, and then remember to change it back before committing your fix.
Perhaps you can escape this problem because you're working on a pass that is hard-coded into opt and bugpoint, but it'll only work if opt and bugpoint and whatever special tool that this pass is incorporated into all set that boolean in the same way under the same conditions. If someone uses it in a tool that sets it using some non-standard criteria, then you run into this problem.
We went through this with Automatic Pool Allocation and SAFECode: it was one of several things that made bugpoint inconvenient or impossible to use.
I have not actually fixed this problem in Poolalloc/SAFECode yet, but I've got the following ideas to try:
1) Create one version of your pass that sets the boolean flag to true and another version of your pass that sets the boolean flag to false. You can probably use C++ templates or inheritance to do this. Register each pass as a separate pass and have your tool pick which pass to run based upon whatever conditions you want.
For example, the Poolalloc pass has to use either EQTDDataStructures or EQBUDataStructures pass depending on whether it is used for SAFECode. Right now it picks one based on a boolean constructor. Instead, I would have the Poolalloc pass be a template that takes the name of the pass to use as input and create two passes:Poolalloc<EQTDDataStructures> and Poolalloc<EQBUDataStructures>. SAFECode would use Poolalloc<EQTDDataStructures>.
2) Create an analysis group that tells your pass what to do (i.e., your pass calls a method on the analysis group to get the boolean flag). Create two immutable passes belonging to the group and return different values for the boolean flag.
Either of these techniques will ensure that any PassManager based tool can print out a string with -debug-pass=Arguments that can be fed into opt or bugpoint to reproduce the same behavior.
My 4 cents.
-- John T.