Hi Ulrich, and any other llvm PowerPC/JIT users,

It looks like the Numba maintainers have run in to an issue with RuntimeDyldELF’s PowerPC support (See https://github.com/numba/numba/issues/2451#issuecomment-377739948 and later comments)

Due to a recent change to weak symbol handling, we now always resolve to the first copy of a function that is emitted (discarding redundant weak/odr definitions in the subsequent objects). It seems that this is resulting in PPC functions referring to the wrong TOC.

I think one valid solution would be to always use to the global function entry point and update the TOC pointer, but I don’t have a good sense of how much overhead this would impose, or how performance sensitive current powerpc clients are.

Otherwise I think we should track which functions came from which object and pick the global entry point where appropriate.

Do you have any thoughts on this? Or any suggestions on the best person to speak to about ELF/PowerPC JIT support?


Hi Lang,

yes, if the target function resides in a different module, we must go via the target’s global entry point (which actually implies constructing and using a stub, since the GEP requires r12 to be set up, which only the stub will do), and we must also insert the load instruction to reload the prior TOC after the function has returned.

The current code in RuntimeDyldELF::processRelocationRef uses this test:

// A PPC branch relocation will need a stub function if the target is
// an external symbol (either Value.SymbolName is set, or SymType is
// Symbol::ST_Unknown) or if the target address is not within the
// signed 24-bits branch address.

and later:

if (Value.SymbolName || SymType == SymbolRef::ST_Unknown) {
// Restore the TOC for external calls

From the discussion it appears that this condition (SymbolName set or SymbolType is unknown) is not sufficient, and there are other cases where the target routine may be in a different module. In that case, the correct fix would be to update those checks to make the condition precise.

I do not think we can simply unconditionally use a stub for every function call – not only would this be a significant performance overhead, it may not even be possible: in order to insert code to restore the TOC, there has to be a nop placeholder in the appropriate spot (after the call), and the compiler does not even put the nop there if it knowns for sure that the target is in the same module.

Mit freundlichen Gruessen / Best Regards

Ulrich Weigand