isSafeToSpeculativelyExecute() for CallInst

Hello,

Currently, llvm::isSafeToSpeculativelyExecute() always returns false for Call instructions.

This has actual performance implications, because loop-invariant code motion makes this check, and will never hoist instructions that are not safe to speculatively execute.

Unfortunately, there is currently no way to signal to LICM that a function is safe to speculatively execute. The implementation of isSafeToSpeculativelyExecute() explicitly states that marking a function nounwind and readnone are not sufficient. The rationale, if I understand it correctly, is that even readnone nounwind functions can contain undefined behavior, so hoisting them may be unsafe. A trivial example of this are functions with infinite loops (By the way, I saw an earlier discussion about a “halting” attribute – I understand this never made it into the trunk?)

A comment in the implementation also says a readnone nounwind function may have side effects, but this, to the best of my understanding, contradicts the language reference manual which explicitly states that a readnone function may not “access any mutable state visible to caller functions”.

Does adding a new attribute to signal that a function is speculation-safe sound reasonable? If not, anyone has any other ideas on how this can be resolved? It doesn’t seem like LICM can safely make a weaker query than isSafeToSpeculativelyExecute().

If you think the attribute is a good idea, name suggestions for it are also welcome: “pure” and “const” are already used in gcc in a slightly different meaning (equivalent to LLVM “readonly” and “readnone”, I think), “nosideeffects” risks confusion with mayHaveSideEffects(), and anything that has the word “speculatively” in it is probably too long.

Thanks,

Michael

LICM::canSinkOrHoistInst has special handling for hoisting Call Instructiobns. It looks like readonly functions should be hoisted. Do you have test cases which fail ?

Thanks,
Nadav

Hi Nadav,

So we have a bug in canSinkOrHoistInst because it only checks for memory deps.