[llvm-commits] [llvm] r48020 - in /llvm/trunk: lib/Transforms/Utils/InlineFunction.cpp test/Transforms/SRETPromotion/2008-03-07-Inline-2.ll test/Transforms/SRETPromotion/2008-03-07-Inline.ll
Devang Patel
dpatel at apple.com
Fri Mar 7 17:30:07 PST 2008
On Mar 7, 2008, at 5:19 PM, Chris Lattner wrote:
> On Mar 7, 2008, at 12:06 PM, Devang Patel wrote:
>> URL: http://llvm.org/viewvc/llvm-project?rev=48020&view=rev
>> Log:
>> Update inliner to handle functions that return multiple values.
>
> Nice.
>
>> @@ -0,0 +1,46 @@
>> +; RUN: llvm-as < %s | opt -inline -sretpromotion -disable-output
>
> Again, your test should only be for the inliner, not both passes.
ok
>> =
>> =
>> =====================================================================
>> --- llvm/trunk/lib/Transforms/Utils/InlineFunction.cpp (original)
>> +++ llvm/trunk/lib/Transforms/Utils/InlineFunction.cpp Fri Mar 7
>> 14:06:16 2008
>>
>> // Handle all of the return instructions that we just cloned in,
>> and eliminate
>> // any users of the original call/invoke instruction.
>> - if (Returns.size() > 1) {
>> + if (!Returns.empty()) {
>
> You are (apparently, I may be mistaken) dropping an important
> optimization here.
You're not mistaken. I expect simplification pass to merge the block
easily, but did not realize that extra br and one additional block can
have significant impact on inlining cost. I'll restore this.
> When a function only has a single return, we don't
> want the inliner to turn:
>
> ...
> call foo()
> ...
>
> into:
>
> ...
> somestuff
> br label x
>
> x:
> ...
>
> This increases the apparent inlining cost of the resultant code and is
> slow. Please don't lose this. The trick here is that you can't
> insert a phi node into the middle of the block, even if it's a single
> entry one. Not doing this optimization for multiple return calls
> would be fine.
>
>> // The PHI node should go at the front of the new basic block to
>> merge all
>> // possible incoming values.
>> + SmallVector<PHINode *, 4> PHIs;
>> if (!TheCall->use_empty()) {
>> + const Type *RTy = CalledFunc->getReturnType();
>> + if (const StructType *STy = dyn_cast<StructType>(RTy)) {
>> + unsigned NumRetVals = STy->getNumElements();
>> + // Create new phi nodes such that phi node number in the
>> PHIs vector
>> + // match corresponding return value operand number.
>> + for (unsigned i = 0; i < NumRetVals; ++i) {
>> + PHINode *PHI = new PHINode(STy->getElementType(i),
>> + TheCall->getName(),
>> AfterCallBB->begin());
>
> I'd suggest naming these things 'TheCall->getName()+"."+utostr(i)'.
ok
> Also, you're inserting the phi nodes in backwards order (the block
> will have rv3,rv2,rv1,rv0 in that order) which is not a functionality
> issue but will make the ir be a bit strange looking.
I already noticed that :) I'll restore natural order.
>
>
>>
>> + PHIs.push_back(PHI);
>> + }
>> + // TheCall results are used by GetResult instructions.
>> + while (!TheCall->use_empty()) {
>> + GetResultInst *GR = cast<GetResultInst>(TheCall-
>>> use_back());
>> + GR->replaceAllUsesWith(PHIs[GR->getIndex()]);
>> + GR->eraseFromParent();
>
> Nice.
>
>> + // Loop over all of the return instructions adding entries to
>> the PHI node as
>> // appropriate.
>> + if (!PHIs.empty()) {
>> + const Type *RTy = CalledFunc->getReturnType();
>> + if (const StructType *STy = dyn_cast<StructType>(RTy)) {
>
> I don't think you need to distinguish between the multiple return and
> scalar return case here. Just loop over all the elements of Returns,
> and then loop over all their operands.
ok
>> - // Add a branch to the merge point where the PHI node lives
>> if it exists.
>> + // Add a branch to the merge points and remove retrun
>> instructions.
>> + for (unsigned i = 0, e = Returns.size(); i != e; ++i) {
>> + ReturnInst *RI = Returns[i];
>> new BranchInst(AfterCallBB, RI);
>> RI->getParent()->getInstList().erase(RI);
>> }
>
> How about RI->eraseFromParent();
good idea!
-
Devang
More information about the llvm-commits
mailing list