<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div><blockquote type="cite" class=""><div class="">On Oct 24, 2016, at 1:23 PM, Joe Groff &lt;<a href="mailto:jgroff@apple.com" class="">jgroff@apple.com</a>&gt; wrote:</div><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><blockquote type="cite" class=""><div class="">On Oct 24, 2016, at 12:58 PM, John McCall &lt;<a href="mailto:rjmccall@apple.com" class="">rjmccall@apple.com</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><div style="" class=""><blockquote type="cite" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;" class="">On Oct 24, 2016, at 12:30 PM, Stephen Canon &lt;<a href="mailto:scanon@apple.com" class="">scanon@apple.com</a>&gt; wrote:<br class=""><blockquote type="cite" class="">On Oct 24, 2016, at 2:55 PM, John McCall via swift-dev &lt;<a href="mailto:swift-dev@swift.org" class="">swift-dev@swift.org</a>&gt; wrote:<br class=""><br class=""><blockquote type="cite" class="">On Oct 24, 2016, at 8:49 AM, Joe Groff via swift-dev &lt;<a href="mailto:swift-dev@swift.org" class="">swift-dev@swift.org</a>&gt; wrote:<br class=""><blockquote type="cite" class="">On Oct 22, 2016, at 10:39 AM, Chris Lattner &lt;<a href="mailto:clattner@apple.com" class="">clattner@apple.com</a>&gt; wrote:<br class=""><br class=""><blockquote type="cite" class="">On Oct 20, 2016, at 2:59 PM, Joe Groff via swift-dev &lt;<a href="mailto:swift-dev@swift.org" class="">swift-dev@swift.org</a>&gt; wrote:<br class=""><blockquote type="cite" class=""><br class="">copysign( ) is a reason to not pick the first option. &nbsp;I’m not very worried about it, but it is a reason. &nbsp;I see no problem with the second option.<br class=""></blockquote><br class="">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.<br class=""></blockquote><br class="">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.<br class=""><br class="">That said, I don’t understand the above. &nbsp;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.<br class=""></blockquote><br class="">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.<br class=""></blockquote><br class="">There isn't any efficient way of just testing the sign bit of a value using FP instructions that I can see. &nbsp;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. &nbsp;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. &nbsp;And in that case, in both representations it seems to me that the obvious extra-inhabitant sequence is 0xFFFFFFFF, 0xFFFFFFFE, …<br class=""></blockquote><br class="">The test for detecting the reserved encoding is essentially identical either way (pseudo-assembly):<br class=""><br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>detectNegativeNaN:<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span>ADD encoding, encoding, 0x0010000000000000<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span>JC nil<br class=""><br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>detectLeading11NaN:<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span>ADD encoding, encoding, 0x0004000000000000<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span>JO nil<br class=""></blockquote><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">Sure, that's basically just a different way of spelling the comparison. &nbsp;For the most part, though, Swift will not need to perform this operation; it'll be checking for a specific value. &nbsp;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.</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""></div></div></blockquote><div class=""><br class=""></div><div class="">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.</div></div></div></div></blockquote><div><br class=""></div>Sure.</div><div><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><div class="">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.</div></div></div></div></blockquote><div><br class=""></div>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? &nbsp;Or am I missing something important?</div><div><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><blockquote type="cite" class=""><div class=""><div style="" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">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. &nbsp;It's not as pure a win as we might hope. &nbsp;Still probably worthwhile, though.</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""></div></div></blockquote></div><br class=""><div class="">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.</div></div></div></blockquote><br class=""></div><div>I agree.</div><br class=""><div class="">John.</div></body></html>