[PATCH] instcombine: Only create library call simplifier once
Meador Inge
meadori at codesourcery.com
Thu Mar 7 14:23:33 PST 2013
On 03/07/2013 03:56 PM, Michael Ilseman wrote:
> On Mar 7, 2013, at 12:52 PM, Meador Inge <meadori at codesourcery.com> wrote:
>
>> Nadav reported a performance regression due to the work I did to
>> merge the library call simplifier into instcombine [1]. The issue
>> is that a new LibCallSimplifier object is being created every time
>> InstCombiner::runOnFunction is called. The is very inefficient
>> because every time a LibCallSimplifier object is new'd up it creates
>> a hash table to map from a function name to an object that optimizes
>> functions of that name.
>>
>
> Actually, I think only one was new-ed up. Also, it was the
> "LibCallSimplifierImpl::optimizeCall()" method which would call
> "initOptimizations()" only if Optimizations wasn't already set up.
Yeah, but in 'InstCombiner::runOnFunction' we have:
InstCombinerLibCallSimplifier TheSimplifier(TD, TLI, this);
Simplifier = &TheSimplifier;
So a new LibCallSimplifier object gets created *each* time
'InstCombiner::runOnFunction' is called. Even though the hash table is not
constructed until later when 'optimizeCall' is invoked we still start fresh
with a new object each time.
>> The original library call simplifier avoided this problem by only
>> initializing that table *once* in SimplifyLibCalls::runOnFunction.
>> This patch fixes the problem by implementing a similar idea in
>> instcombine. LibCallSimplifier objects are only created the first
>> time InstCombiner::runOnFunction is called.
>
> Did you do any measurements, and if so what was the data?
I did. I profiled it with 'perf' on an x86_64 Fedora system using a sample
program that contained 20,000 small functions. Before the patch about 32% of
the time spent in LibCallSimplifier was in building the table. After the patch
it was basically 0%.
>> diff --git a/lib/Transforms/InstCombine/InstructionCombining.cpp b/lib/Transforms/InstCombine/InstructionCombining.cpp
>> index c6115e3..327c70c 100644
>> --- a/lib/Transforms/InstCombine/InstructionCombining.cpp
>> +++ b/lib/Transforms/InstCombine/InstructionCombining.cpp
>> @@ -2456,10 +2456,9 @@ namespace {
>> class InstCombinerLibCallSimplifier : public LibCallSimplifier {
>> InstCombiner *IC;
>> public:
>> - InstCombinerLibCallSimplifier(const DataLayout *TD,
>> - const TargetLibraryInfo *TLI,
>> + InstCombinerLibCallSimplifier(const TargetLibraryInfo *TLI,
>> InstCombiner *IC)
>> - : LibCallSimplifier(TD, TLI, UnsafeFPShrink) {
>> + : LibCallSimplifier(TLI, UnsafeFPShrink) {
>> this->IC = IC;
>> }
>>
>> @@ -2485,8 +2484,8 @@ bool InstCombiner::runOnFunction(Function &F) {
>> InstCombineIRInserter(Worklist));
>> Builder = &TheBuilder;
>>
>> - InstCombinerLibCallSimplifier TheSimplifier(TD, TLI, this);
>> - Simplifier = &TheSimplifier;
>> + if (!Simplifier)
>> + Simplifier = new InstCombinerLibCallSimplifier(TLI, this);
>>
>
> Are you sure you want to keep pointers live across multiple compilations?
> I would think you would have to destroy this in releaseMemory().
Hmmmm. I will have to look into that. I may have to go a different route.
> I'm also not sure what's gained here, the constructor is fairly trivial.
As explained above creating a new LibCallSimplifier object for every function is
avoided (and thus we avoid having to rebuild the hash table whenever
optimizeCall is invoked).
Thanks for the review!
--
Meador Inge
CodeSourcery / Mentor Embedded
More information about the llvm-commits
mailing list