> On Oct 24, 2016, at 12:58, John McCall via swift-dev <swift-dev@swift.org> 
> wrote:
> 
>> On Oct 24, 2016, at 12:30 PM, Stephen Canon <sca...@apple.com> wrote:
>>> On Oct 24, 2016, at 2:55 PM, John McCall via swift-dev 
>>> <swift-dev@swift.org> wrote:
>>> 
>>>> On Oct 24, 2016, at 8:49 AM, Joe Groff via swift-dev <swift-dev@swift.org> 
>>>> wrote:
>>>>> On Oct 22, 2016, at 10:39 AM, Chris Lattner <clatt...@apple.com> wrote:
>>>>> 
>>>>>> On Oct 20, 2016, at 2:59 PM, Joe Groff via swift-dev 
>>>>>> <swift-dev@swift.org> 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
swift-dev@swift.org
https://lists.swift.org/mailman/listinfo/swift-dev

Reply via email to