> On Oct 24, 2016, at 1:36 PM, John McCall <rjmcc...@apple.com> wrote: > >> On Oct 24, 2016, at 1:23 PM, Joe Groff <jgr...@apple.com >> <mailto: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?
Ah, I see what you're saying now. Yeah, setting the sign bit for extra inhabitants definitely makes sense, for the benefit of platforms with less clever immediate encodings. -Joe
_______________________________________________ swift-dev mailing list swift-dev@swift.org https://lists.swift.org/mailman/listinfo/swift-dev