This is an archive of the discontinued LLVM Phabricator instance.

Fix `compiler_rt_logbf_test.c` test failure for Builtins-i386-darwin test suite.
ClosedPublic

Authored by delcypher on Sep 24 2019, 5:14 PM.

Details

Summary

It seems that compiler-rt's implementation and Darwin
libm's implementation of logbf() differ when given a NaN
with raised sign bit. Strangely this behaviour only happens with
i386 Darwin libm. For x86_64 and x86_64h the existing compiler-rt
implementation matched Darwin libm.

To workaround this the compiler_rt_logbf_test.c has been modified
to do a comparison on the fp_t type and if that fails check if both
values are NaN. If both values are NaN they are equivalent and no
error needs to be raised.

rdar://problem/55565503

Event Timeline

delcypher created this revision.Sep 24 2019, 5:14 PM
Herald added projects: Restricted Project, Restricted Project. · View Herald TranscriptSep 24 2019, 5:14 PM
Herald added a subscriber: Restricted Project. · View Herald Transcript

So... on one hand, there are several reasons this is probably fine:

  • The first spec I found [1] (linked from cppreference, not claiming it's the authoritative one) just says that logb should return "a NaN" and not specifically +/- NaN... so this is conforming
  • The call sites I looked at don't seem to distinguish between +/- NaN, so it shouldn't have an effect on them anyway
  • At any rate, this is not an exposed logb method that needs to comply w/ posix, this is just internal to builtins. The logb test just compares it to libm to make sure it's sane.

On the other hand, this makes builtins needlessly diverge on different platforms that may come up and bite someone when debugging this. A different (I won't claim "better" just yet) fix would be to just suppress/update test assertions on i386-darwin.

I'd like to let others weigh in too. What do you think?

(I don't think I can see the rdar link, lemme know if there's some public way to view it)

[1] https://pubs.opengroup.org/onlinepubs/9699919799/functions/logb.html

lib/builtins/fp_lib.h
279–281 ↗(On Diff #221629)

Instead of taking a branch, it might be faster to always return fromRep((~signBit) & rep) -- if the sign bit is not set, it shouldn't have an effect.

@rupprecht as much as I really want to agree with you in that this isn't needed to match the behaviour of the system's libm, the problem is that __builtin_logb can be misused to implement a library. So, really, I would really urge Apple to consider maintaining similarity across all the platforms for the builtins - there is no official guarantee that is made on the behaviour of the builtin operations, so If there is a strong reason to have the divergence, please do share that, and I think that we can probably accommodate that with the small tweak that @rupprecht points out:

if (x != x) {
#if defined(__APPLE__) && defined(__i386__)
  return fromRep(~signBit & rep);
#else
  return x;
#endif
} else if ((rep & signBit) == 0) {
rupprecht added a subscriber: efriedma.

@efriedma reviewed my original change, so may also have context on this.

... the problem is that __builtin_logb can be misused to implement a library ...

The method here is __compiler_rt_logbX (defined as __compiler_rt_logbf etc.), not __builtin_logb. Any code that generates a call to __builtin_logb would need that to be satisfied by linking against libm for the logb symbol definition, not compiler-rt.

IIRC, when I tested this a long time ago by building the builtins library and poking it with nm, none of the __compiler_rt_logbX methods were being exposed (due to static __inline), so I'm not sure how this could be misused to implement a library outside of compiler-rt. I may be missing something.

I'd like to let others weigh in too. What do you think?

Well I'm not very happy with this patch but it was a quick fix that got the test passing again so I thought I'd suggest this first. I do have an alternative in mind. If we don't care about bit identical representations of NaN then what we could do is change the test (compiler_rt_logbf_test.c) by replacing

if (toRep(crt_value) !=  toRep(libm_value)) {

with

if (canonicalizeReprNan(toRep(crt_value)) !=  canonicalizeReprNan(toRep(libm_value))) {

Here canonicalizeReprNan() would be a function that returns the input it is given unless it is the bit pattern for a NaN. If the bit pattern is a NaN then it returns a canonical representation of NaN (probably a quiet NaN with the sign bit set to zero).

This means that we don't need to change the implementation of __compiler_rt_logbX() and in testing we will tolerate libm implementations that decide to return different NaN representations than compiler-rt does.

What do you think?

(I don't think I can see the rdar link, lemme know if there's some public way to view it)

The radar number here is just so Apple can track upstream changes landing into internal repos. The contents of this particular radar doesn't add anything to this discussion because it's just a report that this test is failing.

Backing up what everyone says here: logb doesn't define the sign of NaN results, and 754 explicitly says not to interpret the sign of NaN as having any meaning except in the copySign, absoluteValue, negate, and copy operations. (That's a semantically meaningless statement, since those operations do not exist in a vacuum, which means that you can't actually say anything about the sign of NaN from a formal perspective, but, well, it's the standard we have.)

Matching the libm behavior is nice, but normally outside the scope of compiler-rt w.r.t. NaN encodings (sign, payload, and signaling status--since compiler-rt is meant for use in soft-float contexts, it doesn't have a meaningful notion of signaling NaNs, and generally doesn't even try. We could pin that down more for hybrid situations, but that's a much larger change.)

There's nothing *wrong* with making this match, but we should also relax the test to not expect that it do so.

delcypher updated this revision to Diff 221884.Sep 25 2019, 8:53 PM

Modify test instead.

delcypher edited the summary of this revision. (Show Details)Sep 25 2019, 8:54 PM

@rupprecht @scanon I've reworked this patch to make the test more forgiving of different NaN representations.

rupprecht accepted this revision.Sep 26 2019, 10:29 AM

LGTM, thanks! Please wait for someone else to stamp too, it's been a while since I touched compiler-rt.

This revision is now accepted and ready to land.Sep 26 2019, 10:29 AM
delcypher updated this revision to Diff 222652.Oct 1 2019, 10:51 AM

Compare using comparison operator for fp_t and use crt_isnan() to
check for NaNs.

delcypher updated this revision to Diff 222653.Oct 1 2019, 10:57 AM

Fix comment typos.

delcypher edited the summary of this revision. (Show Details)Oct 1 2019, 10:58 AM

@rupprecht I talked with @scanon offline and he came up with a much simpler solution. Could you re-approve this change if you're happy with it?

This revision was automatically updated to reflect the committed changes.

@rupprecht I talked with @scanon offline and he came up with a much simpler solution. Could you re-approve this change if you're happy with it?

Sorry, didn't see this earlier. The committed patch LGTM!