patch for functions with indirect calls and always_inline attribute
Hal Finkel
hfinkel at anl.gov
Mon Apr 14 21:07:30 PDT 2014
----- Original Message -----
> From: "Eric Christopher" <echristo at gmail.com>
> To: "Hal Finkel" <hfinkel at anl.gov>
> Cc: "llvm-commits" <llvm-commits at cs.uiuc.edu>, "Gerolf Hoflehner" <ghoflehner at apple.com>
> Sent: Monday, April 14, 2014 11:00:21 PM
> Subject: Re: patch for functions with indirect calls and always_inline attribute
>
> On Mon, Apr 14, 2014 at 8:39 PM, Hal Finkel <hfinkel at anl.gov> wrote:
> > ----- Original Message -----
> >> From: "Eric Christopher" <echristo at gmail.com>
> >> To: "Gerolf Hoflehner" <ghoflehner at apple.com>
> >> Cc: "llvm-commits" <llvm-commits at cs.uiuc.edu>
> >> Sent: Monday, April 14, 2014 6:11:06 PM
> >> Subject: Re: patch for functions with indirect calls and
> >> always_inline attribute
> >>
> >> On Mon, Apr 14, 2014 at 4:09 PM, Gerolf Hoflehner
> >> <ghoflehner at apple.com> wrote:
> >> > Please see below.
> >> >
> >> > On Apr 14, 2014, at 2:56 PM, Eric Christopher
> >> > <echristo at gmail.com>
> >> > wrote:
> >> >
> >> >> I could be down for this...
> >> >>
> >> >> Do you have any numbers?
> >> > No. I ran into this when creating a test case for another bug
> >> > fix.
> >>
> >> OK, would you mind running some performance numbers on this? It
> >> passes
> >> my sniff test as well, but I'd like to not be wrong :)
> >>
> >> If the numbers come out neutral/ahead/no change feel free to
> >> commit.
> >
> > And if they don't? always_inline means *always inline* -- this is a
> > correctness issue, and we should do it regardless of performance
> > considerations.
> >
>
> Turns out I agree. However, I'd like to know if we've got any
> regressions so they can be explored first and we can figure out
> what's
> wrong and then apply. I wouldn't expect anything, but running numbers
> would make sure that we're not exposing some pernicious inliner/opt
> bug somewhere else.
Fair enough.
>
> > I am curious, however, why we have this restriction at all.
> > Indirect dispatch is expensive, compounding that expense with the
> > call overhead of a small function seems suboptimal; plus, for
> > hardware that has indirect branch prediction (Intel, ARM, and
> > others), inlining should give the branch predictor a better chance
> > at doing the right thing.
> >
>
> We do have a bonus to the inliner for just that IIRC. This should be
> for something like computed branches within functions rather than
> calls to virtual functions? That said, it does seem odd since the
> branch predictor should help with those as well.
Good point. So this, in C, is for things like dispatch tables using the labels-as-values extension; anything else?
-Hal
>
> *shrug*
>
> -eric
>
> > -Hal
> >
> >>
> >> Thanks!
> >>
> >> -eric
> >>
> >> >>
> >> >> Nits on the patch:
> >> >>
> >> >> // Disallow inlining of functions which contain an indirect
> >> >> branch.
> >> >> - if (isa<IndirectBrInst>(BI->getTerminator()))
> >> >> + if (isa<IndirectBrInst>(BI->getTerminator()) &&
> >> >> + !F.hasFnAttribute(Attribute::AlwaysInline))
> >> >>
> >> >> Update the comment.
> >> > Ok.
> >> >> I'm assuming this can't be hoisted because of the
> >> >> returns_twice aspect yes?
> >> >
> >> > Yes, for now I only wanted to address indirect branches and
> >> > leave
> >> > remaining checks as they are.
> >> >
> >> >>
> >> >> -define i32 @inner5(i8* %addr) alwaysinline {
> >> >> +define i32 @inner5(i8* %addr) {
> >> >>
> >> >> Why the change?
> >> > This is to keep the old test behavior which relied on *not*
> >> > inlining inner5 because of an indirect branch.
> >> >>
> >> >> -eric
> >> >>
> >> >> On Mon, Apr 14, 2014 at 2:49 PM, Gerolf Hoflehner
> >> >> <ghoflehner at apple.com> wrote:
> >> >>> Hi
> >> >>>
> >> >>> llvm currently does not inline functions with indirect
> >> >>> branches.
> >> >>> We had some
> >> >>> internal discussion and think the always_inline attribute
> >> >>> should
> >> >>> overrule
> >> >>> that restriction.
> >> >>>
> >> >>> Gerolf
> >> >>>
> >> >>>
> >> >>>
> >> >>>
> >> >>>
> >> >>> Index: lib/Analysis/IPA/InlineCost.cpp
> >> >>> ===================================================================
> >> >>> --- lib/Analysis/IPA/InlineCost.cpp (revision 206204)
> >> >>> +++ lib/Analysis/IPA/InlineCost.cpp (working copy)
> >> >>> @@ -1301,7 +1301,8 @@
> >> >>> Attribute::ReturnsTwice);
> >> >>> for (Function::iterator BI = F.begin(), BE = F.end(); BI !=
> >> >>> BE;
> >> >>> ++BI) {
> >> >>> // Disallow inlining of functions which contain an
> >> >>> indirect
> >> >>> branch.
> >> >>> - if (isa<IndirectBrInst>(BI->getTerminator()))
> >> >>> + if (isa<IndirectBrInst>(BI->getTerminator()) &&
> >> >>> + !F.hasFnAttribute(Attribute::AlwaysInline))
> >> >>> return false;
> >> >>>
> >> >>>
> >> >>>
> >> >>> for (BasicBlock::iterator II = BI->begin(), IE =
> >> >>> BI->end();
> >> >>> II != IE;
> >> >>> Index: test/Transforms/Inline/always-inline-attribute.ll
> >> >>> ===================================================================
> >> >>> --- test/Transforms/Inline/always-inline-attribute.ll
> >> >>> (revision
> >> >>> 0)
> >> >>> +++ test/Transforms/Inline/always-inline-attribute.ll
> >> >>> (working
> >> >>> copy)
> >> >>> @@ -0,0 +1,26 @@
> >> >>> +; RUN: opt < %s -O3 -S | FileCheck %s
> >> >>> + at gv = external global i32
> >> >>> +
> >> >>> +define i32 @main() nounwind {
> >> >>> +; CHECK-NOT: call i32 @foo
> >> >>> + %1 = load i32* @gv, align 4
> >> >>> + %2 = tail call i32 @foo(i32 %1)
> >> >>> + unreachable
> >> >>> +}
> >> >>> +
> >> >>> +define internal i32 @foo(i32) alwaysinline {
> >> >>> + br label %2
> >> >>> +
> >> >>> +; <label>:2 ; preds =
> >> >>> %8,
> >> >>> %1
> >> >>> + %3 = phi i32 [ %0, %1 ], [ %10, %8 ]
> >> >>> + %4 = phi i8* [ blockaddress(@foo, %2), %1 ], [ %6, %8 ]
> >> >>> + %5 = icmp eq i32 %3, 1
> >> >>> + %6 = select i1 %5, i8* blockaddress(@foo, %8), i8* %4
> >> >>> + %7 = add nsw i32 %3, -1
> >> >>> + br label %8
> >> >>> +
> >> >>> +; <label>:8 ; preds =
> >> >>> %8,
> >> >>> %2
> >> >>> + %9 = phi i32 [ %7, %2 ], [ %10, %8 ]
> >> >>> + %10 = add nsw i32 %9, -1
> >> >>> + indirectbr i8* %6, [label %2, label %8]
> >> >>> +}
> >> >>> Index: test/Transforms/Inline/always-inline.ll
> >> >>> ===================================================================
> >> >>> --- test/Transforms/Inline/always-inline.ll (revision
> >> >>> 206203)
> >> >>> +++ test/Transforms/Inline/always-inline.ll (working copy)
> >> >>> @@ -78,7 +78,7 @@
> >> >>> ret i32 %add
> >> >>> }
> >> >>>
> >> >>>
> >> >>>
> >> >>> -define i32 @inner5(i8* %addr) alwaysinline {
> >> >>> +define i32 @inner5(i8* %addr) {
> >> >>> entry:
> >> >>> indirectbr i8* %addr, [ label %one, label %two ]
> >> >>>
> >> >>>
> >> >>> _______________________________________________
> >> >>> llvm-commits mailing list
> >> >>> llvm-commits at cs.uiuc.edu
> >> >>> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
> >> >>>
> >> >
> >> _______________________________________________
> >> llvm-commits mailing list
> >> llvm-commits at cs.uiuc.edu
> >> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
> >>
> >
> > --
> > Hal Finkel
> > Assistant Computational Scientist
> > Leadership Computing Facility
> > Argonne National Laboratory
>
--
Hal Finkel
Assistant Computational Scientist
Leadership Computing Facility
Argonne National Laboratory
More information about the llvm-commits
mailing list