[llvm-dev] Orc JIT vs. implicit template instanciation in LLVM 8
Geoff Levner via llvm-dev
llvm-dev at lists.llvm.org
Tue Sep 17 01:20:02 PDT 2019
That works, too. I didn't try that because I thought there might be
undesirable side effects...
Should I commit the fix, or leave that to whomever usually does that
sort of thing?
Thanks,
Geoff
On Tue, Sep 17, 2019 at 1:27 AM Lang Hames <lhames at gmail.com> wrote:
>
> Hi Geoff,
>
> Ahh. That might be the problem. What happens if you move the 'Finalized = true;' assignment below the call to loadObject in ConcreteLinkedObject::finalize?
>
> Cheers,
> Lang.
>
> On Mon, Sep 16, 2019 at 3:11 PM Geoff Levner <glevner at gmail.com> wrote:
>>
>> No, the problem is that Finalized is true. It is set to true at the start of the finalize() method. That's why I added a test causing that line to be executed if the symbol's address is zero...
>>
>> On Tue, 17 Sep 2019, 00:05 Lang Hames, <lhames at gmail.com> wrote:
>>>
>>> Hi Geoff,
>>>
>>> Oof. I don't know what this is yet, but I bet it's going to be awful. Quick apology up-front: I'm sorry about the state of weak symbol support in ORCv1 / Legacy: it was always best effort. ORCv2's solution to these problems is much more robust, but required fundamentally changing the resolution model (i.e. introducing the idea of responsibility sets), which may have shaken loose other bugs in ORCv1/Legacy handling of these symbols.
>>>
>>>> The problem is, findSymbol() returns a null JITSymbol (address 0) if the symbol has not been materialized yet. And naturally it hasn't, since we are trying to determine which symbols need to be materialized...
>>>
>>>
>>> If Finalized == false, then we should be hitting this:
>>>
>>> if (!Finalized)
>>> return JITSymbol(getSymbolMaterializer(Name),
>>> SymEntry->second.getFlags());
>>>
>>> That's not a null symbol, it's a lazy symbol with a materializer attached. It *should* compare non-null in the following test in getResponsibilitySetWithLegacyFn, which in turn should cause it to be added to the responsibility set:
>>>
>>> if (JITSymbol Sym = FindSymbol(*S)) {
>>> if (!Sym.getFlags().isStrong())
>>> Result.insert(S); // <- _ZNSt6vectorIfSaIfEE17_M_default_appendEm should be added here.
>>> } else if (auto Err = Sym.takeError())
>>> return std::move(Err);
>>>
>>> Is that not happening?
>>>
>>> Cheers,
>>> Lang.
>>>
>>>
>>> On Mon, Sep 16, 2019 at 9:36 AM Geoff Levner <glevner at gmail.com> wrote:
>>>>
>>>> I have found the cause of our problems with implicit template
>>>> instantiation, and it looks to me like a bug in Orc JIT in LLVM 8.
>>>> (Perhaps Lang could confirm?)
>>>>
>>>> We use createLegacyLookupResolver() to create our symbol resolver,
>>>> passing it a lookup function. Amongst other things, our function calls
>>>> LegacyRTDyldObjectLinkingLayer::findSymbol() to look up symbols in the
>>>> JIT.
>>>>
>>>> When a module is finalized, the legacy lookup resolver calls
>>>> getResponsibilitySetWithLegacyFn() to find any symbols with weak
>>>> linkage (e.g. function templates) that need to be materialized; that
>>>> function calls our symbol resolver, which calls
>>>> LegacyRTDyldObjectLinkingLayer::findSymbol(). The problem is,
>>>> findSymbol() returns a null JITSymbol (address 0) if the symbol has
>>>> not been materialized yet. And naturally it hasn't, since we are
>>>> trying to determine which symbols need to be materialized...
>>>>
>>>> My quick fix is to change these lines in
>>>> LegacyRTDyldObjectLinkingLayerBase::LinkedObject::getSymbol():
>>>>
>>>> if (!Finalized)
>>>> return JITSymbol(getSymbolMaterializer(Name),
>>>> SymEntry->second.getFlags());
>>>>
>>>> to:
>>>>
>>>> if (!Finalized || SymEntry->second.getAddress() == 0)
>>>> return JITSymbol(getSymbolMaterializer(Name),
>>>> SymEntry->second.getFlags());
>>>>
>>>> That works for me, but I am not sure it is the right way to do it...
>>>> Perhaps somebody else has a better idea?
>>>>
>>>> Geoff
>>>>
>>>> On Mon, Sep 16, 2019 at 3:56 PM Geoff Levner <glevner at gmail.com> wrote:
>>>> >
>>>> > In my test case it seems my module does define the symbol for the
>>>> > missing function template, with weak linkage. But when the module is
>>>> > finalized, LegacyRTDyldObjectLinkingLayer fails to assign it an
>>>> > address, for some reason.
>>>> >
>>>> > I will continue to dig, but if anyone with a better understanding of
>>>> > the code has any ideas, I would appreciate it...
>>>> >
>>>> > Geoff
>>>> >
>>>> > On Sun, Sep 15, 2019 at 6:01 PM Geoff Levner <glevner at gmail.com> wrote:
>>>> > >
>>>> > > Well, I agree the front end must be responsible for (not)
>>>> > > instantiating the function templates. However the problem shows up
>>>> > > only when JIT compiling, for some reason, and only with LLVM 8. Is
>>>> > > there perhaps something else that needs to be done before resolving
>>>> > > symbols, in addition to running constructors, to ensure that
>>>> > > instantiated function templates are taken into account?
>>>> > >
>>>> > > Or perhaps there is some option we are not passing to the front end
>>>> > > (clang -std=c++11) that tells it, "do instantiate function templates
>>>> > > as needed"...?
>>>> > >
>>>> > > On Fri, Sep 13, 2019 at 8:13 PM David Blaikie <dblaikie at gmail.com> wrote:
>>>> > > >
>>>> > > > This sounds like it's beyond the domain of ORC though - if the
>>>> > > > function definition is missing, ORC (at least the bits in LLVM) know
>>>> > > > nothing about your frontend or how to request it to manifest that
>>>> > > > function. In your old version, when/where/how did your frontend
>>>> > > > generate LLVM IR for this function? I'd check that and then see why a
>>>> > > > similar thing isn't happening in the new version.
>>>> > > >
>>>> > > > - Dave
>>>> > > >
>>>> > > > On Fri, Sep 13, 2019 at 8:03 AM Geoff Levner via llvm-dev
>>>> > > > <llvm-dev at lists.llvm.org> wrote:
>>>> > > > >
>>>> > > > > The short version:
>>>> > > > >
>>>> > > > > When I port our application from LLVM 7 to 8, some JIT-compiled code
>>>> > > > > seems to break the implicit instanciation of C++ templates. That is,
>>>> > > > > when I try to resolve a symbol defined by the code, I get undefined
>>>> > > > > symbols corresponding to methods that are actually function templates.
>>>> > > > > If the code adds explicit template instanciations, the problem goes
>>>> > > > > away.
>>>> > > > >
>>>> > > > > Does anybody have an intuition as to what might cause this?
>>>> > > > >
>>>> > > > > Now the longer version:
>>>> > > > >
>>>> > > > > Specifically, we use the Orc JIT (v1) to compile and execute C++ code
>>>> > > > > on the fly. To move to LLVM 8, I am using the corresponding "legacy"
>>>> > > > > classes before attempting the move to Orc v2. But when I do that, some
>>>> > > > > code which compiles fine with LLVM 7 breaks. I might get an undefined
>>>> > > > > symbol like the following when I try to resolve a symbol defined by
>>>> > > > > the code, after running constructors (successfully):
>>>> > > > >
>>>> > > > > _ZNSt6vectorIfSaIfEE17_M_default_appendEm
>>>> > > > >
>>>> > > > > Unmangled, that's:
>>>> > > > >
>>>> > > > > std::vector<float, std::allocator<float> >::_M_default_append(unsigned long)
>>>> > > > >
>>>> > > > > which is a function template defined by the C++ vector header file. If
>>>> > > > > I add an explicit instanciation like so:
>>>> > > > >
>>>> > > > > template class std::vector<float>;
>>>> > > > >
>>>> > > > > the problem goes away. I have tried to reproduce the problem with the
>>>> > > > > Clang front end to no avail, so I assume it is specific to symbol
>>>> > > > > resolution in Orc JIT. Has something changed there between LLVM 7 and
>>>> > > > > 8?
>>>> > > > >
>>>> > > > > Any help would be much appreciated!
>>>> > > > >
>>>> > > > > Thanks,
>>>> > > > > Geoff
>>>> > > > > _______________________________________________
>>>> > > > > LLVM Developers mailing list
>>>> > > > > llvm-dev at lists.llvm.org
>>>> > > > > https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
More information about the llvm-dev
mailing list