> On Oct 24, 2016, at 1:23 PM, Joe Groff <jgr...@apple.com> wrote:
>> On Oct 24, 2016, at 12:58 PM, John McCall <rjmcc...@apple.com 
>> <mailto:rjmcc...@apple.com>> wrote:
>> 
>>> On Oct 24, 2016, at 12:30 PM, Stephen Canon <sca...@apple.com 
>>> <mailto:sca...@apple.com>> wrote:
>>>> On Oct 24, 2016, at 2:55 PM, John McCall via swift-dev 
>>>> <swift-dev@swift.org <mailto:swift-dev@swift.org>> wrote:
>>>> 
>>>>> On Oct 24, 2016, at 8:49 AM, Joe Groff via swift-dev <swift-dev@swift.org 
>>>>> <mailto:swift-dev@swift.org>> wrote:
>>>>>> On Oct 22, 2016, at 10:39 AM, Chris Lattner <clatt...@apple.com 
>>>>>> <mailto:clatt...@apple.com>> wrote:
>>>>>> 
>>>>>>> On Oct 20, 2016, at 2:59 PM, Joe Groff via swift-dev 
>>>>>>> <swift-dev@swift.org <mailto: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.
> 
> When we know there's exactly one no-payload case, as with .none in Optional, 
> we do have the option of testing for an arbitrary extra inhabitant if it 
> happens to be cheaper/smaller code, since having any extra inhabitant 
> representation other than the first would be UB anyway.

Sure.

> In these cases, either the mask or first inhabitant should fit in an ARM64 
> bitmask immediate, and are a 64-bit movabs on Intel either way, so it's 
> probably not worthwhile.

Well, if we always set the sign bit on our extra inhabitants, we end up with a 
prefix that's amenable to extra inhabitants typically being small-magnitude 
negative numbers, right?  Or am I missing something important?

>> 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.
> 
> Right. Since there's no perf benefit to using the sign bit, using b11 
> payloads has the least potential of interfering with users trying to use 
> specific NaN encodings for their own purposes.

I agree.

John.
_______________________________________________
swift-dev mailing list
swift-dev@swift.org
https://lists.swift.org/mailman/listinfo/swift-dev

Reply via email to