Sanjoy Das via llvm-dev
2016-Feb-23 23:06 UTC
[llvm-dev] RFC: Add guard intrinsics to LLVM
On Tue, Feb 23, 2016 at 10:55 AM, Chandler Carruth <chandlerc at gmail.com> wrote:>> Part of the challenge here is to specify the attribute in a way that >> allows inlining, but not IPA without inlining. In fact, maybe it is >> best to not call it "interposable" at all? > > > Yea, this is something *very* different from interposable. GCC and other > compilers that work to support symbol interposition make specific efforts to > not inline them in specific ways (that frankly I don't fully understand, as > it doesn't seem to be always which is what the definition of interposable > indicates to me...).Sure, not calling it interposable is fine for me. Credit where credit is due: Philip had warned me about this exact thing offline (that the term "interposable" is already taken).>> In other words, opt refined the semantics of @foo() (i.e. reduced the >> set of behaviors it may have) in ways that would make later >> optimizations invalid if we de-refine the implementation of @foo(). >> >> Given this, I'd say we don't need a new attribute / linkage type, and >> can add our restriction to the available_externally linkage. > > > Interesting example, I agree it seems quite broken. Even more interesting, I > can't see anything we do in LLVM that prevents this from breaking > essentially everywhere. =[[[[[[ > > link_once and link_once_odr at least seem equally broken because we don't > put the caller and callee into a single comdat or anything to ensure that > the optimized one is selected at link time. > > But there are also multiple different kinds of overriding we should think > about: > > 1) Can the definition get replaced at link time (or at runtime via an > interpreter) with a differently *optimized* variant stemming from the same > definition (thus it has the same behavior but not the same refinement). This > is the "ODR" guarantee in some linkages (and vaguely implied for > available_externally) > > 2) Can the definition get replaced at link time (or at runtime via an > interpreter) with a function that has fundamentally different behavior > > 3) To support replacing the definition, the call edge must be preserved.I'm working under context of a optimizer that does not know if its input has been previously optimized or if its input is "raw" IR. Realistically, I'd say deviating LLVM from this will be painful. Given that I don't see how (2) and (3) are different: Firstly, (1) and (2) are not _that_ different -- a differently optimized variant of a function can have completely different observable behavior (e.g. the "original" function could have started with "if (*ptr != *ptr) { call @unknown(); return; }"). The only practical difference I can see between (1) and (2) is that in (2) inlining is incorrect since it would be retroactively invalid on replacement. In (1) we have the invariant that the function in question is always *a* valid implementation of what we started with, but this can not be used to infer anything about the function we'll actually call at runtime. Thus, I don't understand the difference between (2) and (3); both of them seem to imply "don't do IPA/IPO, including inlining" while (1) implies "the only IPA/IPO you can do is inlining".> I'm curious whether your use case is actually in the #1 bucket or #2 > bucket. That is, I'm wondering if there is any way in which the > "different implementation" would actually break in the face of > optimizations on things like *non-deduced* function attributes, etc.With the understanding I have at this time (that isn't complete, as I say above) I'd say we're (1). We can replace a possibly inlined callee with another arbitrary function, but if that happens the runtime will deoptimize the caller. I'm not sure if I understood your second statement -- but assuming I did -- we do "manually" attach attributes to some well-known functions (e.g. in the standard library), but they never get replaced. -- Sanjoy
Chandler Carruth via llvm-dev
2016-Feb-23 23:34 UTC
[llvm-dev] RFC: Add guard intrinsics to LLVM
On Tue, Feb 23, 2016 at 3:07 PM Sanjoy Das <sanjoy at playingwithpointers.com> wrote:> On Tue, Feb 23, 2016 at 10:55 AM, Chandler Carruth <chandlerc at gmail.com> > wrote: > >> Part of the challenge here is to specify the attribute in a way that > >> allows inlining, but not IPA without inlining. In fact, maybe it is > >> best to not call it "interposable" at all? > > > > > > Yea, this is something *very* different from interposable. GCC and other > > compilers that work to support symbol interposition make specific > efforts to > > not inline them in specific ways (that frankly I don't fully understand, > as > > it doesn't seem to be always which is what the definition of interposable > > indicates to me...). > > Sure, not calling it interposable is fine for me. Credit where credit > is due: Philip had warned me about this exact thing offline (that the > term "interposable" is already taken). > > >> In other words, opt refined the semantics of @foo() (i.e. reduced the > >> set of behaviors it may have) in ways that would make later > >> optimizations invalid if we de-refine the implementation of @foo(). > >> > >> Given this, I'd say we don't need a new attribute / linkage type, and > >> can add our restriction to the available_externally linkage. > > > > > > Interesting example, I agree it seems quite broken. Even more > interesting, I > > can't see anything we do in LLVM that prevents this from breaking > > essentially everywhere. =[[[[[[ > > > > link_once and link_once_odr at least seem equally broken because we don't > > put the caller and callee into a single comdat or anything to ensure that > > the optimized one is selected at link time. > > > > But there are also multiple different kinds of overriding we should think > > about: > > > > 1) Can the definition get replaced at link time (or at runtime via an > > interpreter) with a differently *optimized* variant stemming from the > same > > definition (thus it has the same behavior but not the same refinement). > This > > is the "ODR" guarantee in some linkages (and vaguely implied for > > available_externally) > > > > 2) Can the definition get replaced at link time (or at runtime via an > > interpreter) with a function that has fundamentally different behavior > > > > 3) To support replacing the definition, the call edge must be preserved. > > I'm working under context of a optimizer that does not know if its > input has been previously optimized or if its input is "raw" IR. > Realistically, I'd say deviating LLVM from this will be painful. >I'm not suggesting that either. I think there is a happy middle ground, but I'm probably not explaining it very effectively, sorry. Lemme just try again. There are two conceptually separable aspects of IPO as it is commonly performed within LLVM. One is to use attributes on a function to optimize callers. The second is to use the definition of a function to deduce more refined attributes. This separation is what I was trying to draw attention to between (1) and (2) above. My idea is that with (1) it remains fine to optimize callers based on a function's attributes, but not to deduce more refined attributes. But with (2) I don't think you can do either. I think (3) differs from both (1) and (2) because in some cases the restrictions only remain *if* the call edge remains. If you nuke (or rename) the call edge, the restrictions go away completely. In other cases though (my (3) example), the compiler is required to leave that exact call edge in place. Currently, we clearly don't actually separate these conceptual sides of IPO. We have a very all-or-nothing approach instead. So maybe this distinction isn't interesting. But hopefully it explains how I'm thinking of it. And because frontends can often directly specify *some* attributes that we know a-priori, it doesn't seem a vacuous distinction to me in theory. Does that explain things any better? -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20160223/d38d49ee/attachment.html>
Sanjoy Das via llvm-dev
2016-Feb-23 23:59 UTC
[llvm-dev] RFC: Add guard intrinsics to LLVM
On Tue, Feb 23, 2016 at 3:34 PM, Chandler Carruth <chandlerc at gmail.com> wrote:> I'm not suggesting that either. I think there is a happy middle ground, but > I'm probably not explaining it very effectively, sorry. Lemme just try > again. > > There are two conceptually separable aspects of IPO as it is commonly > performed within LLVM. One is to use attributes on a function to optimize > callers. The second is to use the definition of a function to deduce more > refined attributes.But we also have more aggressive opts like IPSCCP that don't fall in either category.> This separation is what I was trying to draw attention to between (1) and > (2) above. My idea is that with (1) it remains fine to optimize callers > based on a function's attributes, but not to deduce more refined attributes. > But with (2) I don't think you can do either. > > I think (3) differs from both (1) and (2) because in some cases the > restrictions only remain *if* the call edge remains. If you nuke (or rename) > the call edge, the restrictions go away completely. In other cases though > (my (3) example), the compiler is required to leave that exact call edge in > place. > > Currently, we clearly don't actually separate these conceptual sides of IPO. > We have a very all-or-nothing approach instead. So maybe this distinction > isn't interesting. But hopefully it explains how I'm thinking of it. And > because frontends can often directly specify *some* attributes that we know > a-priori, it doesn't seem a vacuous distinction to me in theory. > > Does that explain things any better?Yes, I think I see what you are going for (what I thought was (2)/(3) is really just (3) in your scheme). Practically, I don't think it is useful to differentiate between (1) and (2). To get (2)-like behavior, the frontend can always emit a function definition without any pre-defined attributes; annotated with (1)'s linkage type (available_externally or linkonce_odr). -- Sanjoy