> On Oct 24, 2016, at 12:58, John McCall via swift-dev <[email protected]>
> wrote:
>
>> On Oct 24, 2016, at 12:30 PM, Stephen Canon <[email protected]> wrote:
>>> On Oct 24, 2016, at 2:55 PM, John McCall via swift-dev
>>> <[email protected]> wrote:
>>>
>>>> On Oct 24, 2016, at 8:49 AM, Joe Groff via swift-dev <[email protected]>
>>>> wrote:
>>>>> On Oct 22, 2016, at 10:39 AM, Chris Lattner <[email protected]> wrote:
>>>>>
>>>>>> On Oct 20, 2016, at 2:59 PM, Joe Groff via swift-dev
>>>>>> <[email protected]> wrote:
>>>>>>>
>>>>>>> copysign( ) is a reason to not pick the first option. I’m not very
>>>>>>> worried about it, but it is a reason. I see no problem with the second
>>>>>>> option.
>>>>>>
>>>>>> As we discussed in person this morning, de-canonicalizing b11 might be a
>>>>>> better compromise to minimize the potential impact of layout
>>>>>> optimizations. That would leave the implementation with 2^51 NaN
>>>>>> representations (50 significand bits, plus the sign bit) in Double to
>>>>>> play with, which ought to be enough for anyone™. I liked the idea of
>>>>>> using the sign bit originally since testing for NaNs and sign bits is
>>>>>> something that can be easily done using common FPU instructions without
>>>>>> crossing domains, but as you noted, it sounds like comparison and
>>>>>> branching operations tend to do that anyway, so masking and branching
>>>>>> using integer operations shouldn't be too much of a burden. Jordan's
>>>>>> question of to what degree we consider different NaN encodings to be
>>>>>> distinct semantic values is still an interesting one, but if we take
>>>>>> only the b11 NaN payloads away, that should minimize the degree to which
>>>>>> the implementation needs to be considered as a constraint in having that
>>>>>> discussion.
>>>>>
>>>>> To your original email, I agree this is an important problem to tackle,
>>>>> and that we should handle the inhabitant masking when the FP value is
>>>>> converted to optional.
>>>>>
>>>>> That said, I don’t understand the above. With the “b11” representation,
>>>>> what how is a "Double?" tested for “.None"? One advantage of using the
>>>>> signbit is that “is negative” comparisons are very cheap on risc systems,
>>>>> because you don’t have to materialize a large/weird immediate.
>>>>
>>>> That's why I liked using the sign bit originally too. Steve noted that,
>>>> since any operation on an Optional is probably going to involve testing
>>>> and branching before revealing the underlying float value, and float
>>>> comparisons and branches tend to unavoidably burn a couple cycles engaging
>>>> the integer ALU, there's unlikely to be much benefit on ARM or Intel
>>>> avoiding integer masking operations. (More strictly RISCy architectures
>>>> like Power would be more negatively impacted, perhaps.) On ARM64 at least,
>>>> the bitmask for a b11 NaN is still representable as an immediate, since it
>>>> involves a single contiguous run of 1 bits.
>>>
>>> There isn't any efficient way of just testing the sign bit of a value using
>>> FP instructions that I can see. You could maybe take advantage of the
>>> vector registers overlapping the FP registers and use integer vector
>>> operations, but it would take a lot of code and have false-dependency
>>> problems. So in both representations, the most efficient test sequence
>>> seems to be (1) get value in integer register (2) compare against some
>>> specific integer value. And in that case, in both representations it seems
>>> to me that the obvious extra-inhabitant sequence is 0xFFFFFFFF, 0xFFFFFFFE,
>>> …
>>
>> The test for detecting the reserved encoding is essentially identical either
>> way (pseudo-assembly):
>>
>> detectNegativeNaN:
>> ADD encoding, encoding, 0x0010000000000000
>> JC nil
>>
>> detectLeading11NaN:
>> ADD encoding, encoding, 0x0004000000000000
>> JO nil
>
> Sure, that's basically just a different way of spelling the comparison. For
> the most part, though, Swift will not need to perform this operation; it'll
> be checking for a specific value. I don't see any reason to say that e.g.
> .none can be encoded by an arbitrary reserved NaN rather than a specific one.
That doesn't quite happen when the other case also has a payload.
enum SmallIntOrBigFloat {
case small(Int8)
case big(Double)
}
Jordan
> Anyway, we're agreed that both representations require doing integer
> comparisons on the value, not FP comparisons, and so operations on Float?
> will generally require moving the value between register banks if we do this.
> It's not as pure a win as we might hope. Still probably worthwhile, though.
_______________________________________________
swift-dev mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-dev