[swift-dev] Making the sign of NaNs unspecified to enable enum layout optimization
rjmccall at apple.com
Thu Oct 20 13:11:12 CDT 2016
> On Oct 20, 2016, at 10:50 AM, Joe Groff <jgroff at apple.com> wrote:
>> On Oct 20, 2016, at 10:45 AM, John McCall <rjmccall at apple.com <mailto:rjmccall at apple.com>> wrote:
>>> On Oct 19, 2016, at 8:42 PM, Joe Groff via swift-dev <swift-dev at swift.org <mailto:swift-dev at swift.org>> wrote:
>>> However, the way we usually handle enum optimization with extra inhabitants is problematic for floats. We normally say that it is undefined behavior for a value to have an extra inhabitant representation—a class reference cannot be null, a Bool can only be 0 or 1, and so on. With floats, we need to interoperate with numerics code not written in Swift, and we want to be able to read floating-point data out of memory that may use arbitrary bit patterns. We don't want every double-returning C function or load from memory to require a check for reserved values afterward. Making it undefined behavior for floats to have "extra inhabitant" representations is thus probably not practical.
>>> Instead of saying that extra inhabitants are undefined behavior, we could instead continue to allow Floats and Doubles to have arbitrary bit patterns, and only check for reserved values at the point we construct an enum that wants to use reserved values for layout. If we reserve negative NaNs, then for example, constructing a Float? or Double? from a nonoptional value would check whether the payload value is NaN and if so, clear the sign bit at that point. That way, we don't have any ABI problems with Floats and Doubles from foreign sources, but still get the benefits of layout optimization for Swift types. On the other hand, this would mean that supposedly-idempotent operations like '.some(x)!' lose the sign information for NaNs. Since we wouldn't want to prevent the optimizer from folding those kinds of operations away, we could define Swift's semantics to say that querying the sign of a NaN value produces an unspecified value. This matches the intent of IEEE 754, and shouldn't impact most numerics code in practice. If we were interested in pursuing enum layout optimization with float payloads, I think this would be the best approach.
>> As an implementation matter, is this going to significantly complicate the "make a T? from an unknown T" path? Currently, I think that logic just asks whether a type has extra inhabitants; it doesn't have any notion of having to rewrite actual values to avoid colliding with the "extra" inhabitants.
> It's true that it would no longer be a guaranteed identity operation, but we already have the notion of "inject tag" in the abstract access pattern for enums, which occurs after the payload has been stored, which normally sets the extra tag bits. It seems to me we could also use it to collapse NaN representations when the "some" tag is injected over a float (though we would need a "evacuateExtraInhabitantRepresentations" value witness to do this generically).
This seems reasonable. We could use the same thing to take advantage of spare bits that the type doesn't promise to initialize, e.g. in a struct with internal padding.
-------------- next part --------------
An HTML attachment was scrubbed...
More information about the swift-dev