[llvm-dev] RFC: Add guard intrinsics to LLVM

Sanjoy Das via llvm-dev llvm-dev at lists.llvm.org
Tue Feb 23 15:06:41 PST 2016

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

> 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

More information about the llvm-dev mailing list