This is an archive of the discontinued LLVM Phabricator instance.

[InstCombine][SimplifyLibCalls] convert sqrt libcalls with "nnan" to sqrt intrinsics
AbandonedPublic

Authored by spatel on Jul 5 2022, 11:00 AM.

Details

Summary

If a sqrt call has "nnan", that implies that the input argument is never negative because sqrt of {negative number} --> NAN.
If the argument is never negative, then we can assume that errno is not written, so the call can be translated to the LLVM intrinsic.

This affects codegen for targets like x86 that have a sqrt instruction, but we still have to conservatively assume that a libcall may be needed to set errno as shown in issue #52620.

This patch won't solve that example - we will need to extend this to use CannotBeOrderedLessThanZero or similar, enhance that analysis for new operators, and deal with llvm.assume too.

Diff Detail

Event Timeline

spatel created this revision.Jul 5 2022, 11:00 AM
Herald added a project: Restricted Project. · View Herald TranscriptJul 5 2022, 11:00 AM
spatel requested review of this revision.Jul 5 2022, 11:00 AM
Herald added a project: Restricted Project. · View Herald TranscriptJul 5 2022, 11:00 AM

I hate trying to reason about this stuff.

The intrinsics for sqrt/sin/cos/pow/exp/exp2/log/log2/log10 are theoretically supposed to not write to errno, but in practice they do because we call the libc implementations. So even though this is safe in theory, in practice it could cause a miscompile (if we hoist a sqrt operation past a load from errno). Not sure what, if anything, we should do about this.

spatel added a comment.Jul 5 2022, 3:49 PM

I hate trying to reason about this stuff.

The intrinsics for sqrt/sin/cos/pow/exp/exp2/log/log2/log10 are theoretically supposed to not write to errno, but in practice they do because we call the libc implementations. So even though this is safe in theory, in practice it could cause a miscompile (if we hoist a sqrt operation past a load from errno). Not sure what, if anything, we should do about this.

Ah, I didn't think of the sqrt call moving relative to other calls/accesses of errno. Are we already exposed to that problem in a bigger way when the front-end creates intrinsics too?
As an alternative, we could put this kind of check into PartiallyInlineLibCalls - that's where we create the extra call (that we then expect to be lowered to an instruction) after checking TTI->haveFastSqrt(). Or since we have TTI in AggressiveInstCombine, we could do the transform there. Do you see any potential miscompiles if we use that hook to guard the transform?

Are we already exposed to that problem in a bigger way when the front-end creates intrinsics too?

Sort of. clang generally won't create calls to llvm.sqrt if -fmath-errno is enabled (which is the default on targets where sqrt sets errno). clang will create intrinsics with -ffast-math, though. And other frontends probably just blindly call the intrinsic.

Do you see any potential miscompiles if we use that hook to guard the transform?

That's probably safe enough.

spatel abandoned this revision.Jul 26 2022, 12:34 PM

Abandoning for the alternative that uses TTI via aggressive-instcombine ( D129167 ).