<div dir="ltr">Hi David,<div class="gmail_extra"><br><div class="gmail_quote">On Mon, Dec 29, 2014 at 7:58 PM, David T. Lewis <span dir="ltr">&lt;<a href="mailto:lewis@mail.msen.com" target="_blank">lewis@mail.msen.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><span class=""><br>
On Mon, Dec 29, 2014 at 01:45:17PM +0100, Bert Freudenberg wrote:<br>
&gt;<br>
&gt; How about making SmallIntegers be 53 bits? Could the VM be as efficient if it masked off more bits?<br>
<br>
</span>I would expect no difference in VM performance for values within the 53 bit<br>
range. There is no additional masking required, and there would not be any<br>
need to change the internal storage format. It&#39;s really just a matter of what<br>
point you choose to begin using large integer objects rather than immediates.<br>
<span class=""><br>
&gt;<br>
&gt; IMHO the additional 8 bits we get by going to 61 bits will not significantly enhance performance. In fact, the payoff is probably rather small beyond 32 bits (but still useful e.g. for bit shifts beyond the 32 bit boundary).<br>
&gt;<br>
<br>
</span>I have a hard time thinking of real world cases where the extra range would<br>
have a meaningful impact. The only thing I can think of is my UTCDateAndTime<br>
implementation (<a href="http://wiki.squeak.org/squeak/6197" target="_blank">http://wiki.squeak.org/squeak/6197</a>), which is using large<br>
integers to represent microseconds since the Posix epoch. In 64 bit Spur, if<br>
immediate integers were to have a range of 52 bits, then these DateAndTime<br>
values would be using immediates for dates in the range of year 1827 through<br>
year 2112. For most practical uses within my own expected life span, this<br>
is a useful range of values.<br>
<br>
So even for this use case (which affects almost nobody, at least not now) the<br>
reduction in range of immediate integers has little or no performance impact.<br>
Furthermore, I would note that the UTCDateAndTime implementation that uses<br>
large integers (not immediate short integers) in the current 32 bit images is<br>
already faster than the Squeak trunk DateAndTime implementation. So I have a<br>
hard time believing that extending the range of immediate short integers<br>
beyond 52 bits of precision would have any meaningful real world impact.<br>
<span class=""><br>
&gt; On Mon, Dec 29, 2014 at 02:59:07PM -0800, Eliot Miranda wrote:<br>
&gt;<br>
&gt; On Dec 29, 2014, at 4:45 AM, Bert Freudenberg &lt;<a href="mailto:bert@freudenbergs.de">bert@freudenbergs.de</a>&gt; wrote:<br>
&gt;<br>
&gt; &gt;<br>
</span><span class="">&gt; &gt; IMHO the additional 8 bits we get by going to 61 bits will not significantly enhance performance. I<br>
n fact, the payoff is probably rather small beyond 32 bits (but still useful e.g. for bit shifts beyond<br>
 the 32 bit boundary).<br>
<br>
<br>
&gt; &gt;<br>
&gt; &gt; The question is why only some operations should fail if the SmallInt has more than 53 bits, or if w<br>
e should consistently switch to LargeInts above that. OTOH wasting 8 bits in every SmallInt oop may not<br>
 be a good tradeoff.<br>
&gt;<br>
&gt; Doesn&#39;t feel right for me.  All we&#39;re considering is a few floating-point primitives which need an ad<br>
ditional failure case.  Whereas truncating 64-bit SmallInteger has its own negative effects (microsecon<br>
d clock range, many more large integers created, eg when dealing with addresses, temptation to find use<br>
s for missing bits, such as another ~2^11 tag patterns).  Good to mention an alternative but feels wron<br>
g to me.<br>
&gt;<br>
<br>
</span>I&#39;m inclined to agree with Eliot on this, even though I do not think that<br>
performance would be an issue one way or the other. It seems to me that<br>
having the implementation details of floating point objects creeping into<br>
the implementation of integers is not a good thing in principle, even though<br>
in practice it would be fine.<br>
<br>
Bert&#39;s suggestion is a simple and practical short term solution. It has no<br>
practical performance impact, and it is trivial to implement. The only serious<br>
negative is that it would require a good method comment to explain the rationale<br>
for the short integer range limitation.<br>
<br>
However, with a bit of additional work, the range checks can be added to the<br>
floating point primitives. This seems better, because it puts the responsibility<br>
with the floating point logic, which is where it belongs.<br></blockquote><div><br></div><div>The work is very small.  As far as I can tell it is merely the change of</div><div><br></div><div>Spur64BitMemoryManager methods for interpreter access</div><div><div>loadFloatOrIntFrom: floatOrIntOop</div><div><span class="" style="white-space:pre">        </span>&quot;If floatOrInt is an integer, then convert it to a C double float and return it.</div><div><span class="" style="white-space:pre">        </span> If it is a Float, then load its value and return it.</div><div><span class="" style="white-space:pre">        </span> Otherwise fail -- ie return with primErrorCode non-zero.&quot;</div><div><br></div><div><span class="" style="white-space:pre">        </span>&lt;inline: true&gt;</div><div><span class="" style="white-space:pre">        </span>&lt;returnTypeC: #double&gt;</div><div><span class="" style="white-space:pre">        </span>| result tagBits |</div><div><span class="" style="white-space:pre">        </span>&lt;var: #result type: #double&gt;</div><div><br></div><div><span class="" style="white-space:pre">        </span>(tagBits := floatOrIntOop bitAnd: self tagMask) ~= 0</div><div><span class="" style="white-space:pre">                </span>ifTrue:</div><div><span class="" style="white-space:pre">                        </span>[tagBits = self smallFloatTag ifTrue:</div><div><span class="" style="white-space:pre">                                </span>[^self smallFloatValueOf: floatOrIntOop].</div><div><span class="" style="white-space:pre">                        </span> tagBits = self smallIntegerTag ifTrue:</div><div><span class="" style="white-space:pre">                                </span>[^(self integerValueOf: floatOrIntOop) asFloat]]</div><div><span class="" style="white-space:pre">                </span>ifFalse:</div><div><span class="" style="white-space:pre">                        </span>[(self classIndexOf: floatOrIntOop) = ClassFloatCompactIndex ifTrue:</div><div><span class="" style="white-space:pre">                                </span>[self cCode: &#39;&#39; inSmalltalk: [result := Float new: 2].</div><div><span class="" style="white-space:pre">                                </span> self fetchFloatAt: floatOrIntOop + self baseHeaderSize into: result.</div><div><span class="" style="white-space:pre">                                </span> ^result]].</div><div><span class="" style="white-space:pre">        </span>coInterpreter primitiveFail.</div><div><span class="" style="white-space:pre">        </span>^0.0</div></div><div><br></div><div>to</div><div><div>loadFloatOrIntFrom: floatOrIntOop</div><div><span class="" style="white-space:pre">        </span>&quot;If floatOrInt is an integer, then convert it to a C double float and return it.</div><div><span class="" style="white-space:pre">        </span> If it is a Float, then load its value and return it.</div><div><span class="" style="white-space:pre">        </span> Otherwise fail -- ie return with primErrorCode non-zero.&quot;</div><div><br></div><div><span class="" style="white-space:pre">        </span>&lt;inline: true&gt;</div><div><span class="" style="white-space:pre">        </span>&lt;returnTypeC: #double&gt;</div><div><span class="" style="white-space:pre">        </span>| result tagBits shift |</div><div><span class="" style="white-space:pre">        </span>&lt;var: #result type: #double&gt;</div><div><br></div><div><span class="" style="white-space:pre">        </span>(tagBits := floatOrIntOop bitAnd: self tagMask) ~= 0</div><div><span class="" style="white-space:pre">                </span>ifTrue:</div><div><span class="" style="white-space:pre">                        </span>[tagBits = self smallFloatTag ifTrue:</div><div><span class="" style="white-space:pre">                                </span>[^self smallFloatValueOf: floatOrIntOop].</div><div><span class="" style="white-space:pre">                        </span> (tagBits = self smallIntegerTag</div><div><span class="" style="white-space:pre">                        </span>  and: [shift := 64 - self numTagBits - self smallFloatMantissaBits.</div><div><span class="" style="white-space:pre">                                </span>(self cCode: [floatOrIntOop &lt;&lt; shift]</div><div><span class="" style="white-space:pre">                                                </span>inSmalltalk: [floatOrIntOop &lt;&lt; shift bitAnd: 1 &lt;&lt; 64 - 1]) &gt;&gt; shift = floatOrIntOop]) ifTrue:</div><div><span class="" style="white-space:pre">                                </span>[^(self integerValueOf: floatOrIntOop) asFloat]]</div><div><span class="" style="white-space:pre">                </span>ifFalse:</div><div><span class="" style="white-space:pre">                        </span>[(self classIndexOf: floatOrIntOop) = ClassFloatCompactIndex ifTrue:</div><div><span class="" style="white-space:pre">                                </span>[self cCode: &#39;&#39; inSmalltalk: [result := Float new: 2].</div><div><span class="" style="white-space:pre">                                </span> self fetchFloatAt: floatOrIntOop + self baseHeaderSize into: result.</div><div><span class="" style="white-space:pre">                                </span> ^result]].</div><div><span class="" style="white-space:pre">        </span>coInterpreter primitiveFail.</div><div><span class="" style="white-space:pre">        </span>^0.0</div></div><div><br></div><div>i.e. </div><div><div><span class="" style="white-space:pre">                        </span> tagBits = self smallIntegerTag ifTrue:</div><div><span class="" style="white-space:pre">                                </span>[^(self integerValueOf: floatOrIntOop) asFloat]</div></div><div><br></div><div>becomes</div><div><br></div><div><div><span class="" style="white-space:pre">                        </span> (tagBits = self smallIntegerTag</div><div><span class="" style="white-space:pre">                        </span>  and: [shift := 64 - self numTagBits - self smallFloatMantissaBits.</div><div><span class="" style="white-space:pre">                                </span>(self cCode: [floatOrIntOop &lt;&lt; shift]</div><div><span class="" style="white-space:pre">                                                </span>inSmalltalk: [floatOrIntOop &lt;&lt; shift bitAnd: 1 &lt;&lt; 64 - 1]) &gt;&gt; shift = floatOrIntOop]) ifTrue:</div><div><span class="" style="white-space:pre">                                </span>[^(self integerValueOf: floatOrIntOop) asFloat]</div></div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<br>
My remaining concern would be that handling the logic in the VM (floating point<br>
primitives) is less flexible than handling it in the image. I am not really<br>
convinced that the immediate float format in Spur 64 will prove to be of<br>
practical value, so I think that maintaining some flexibility around the<br>
implmentation might be a good thing.<br></blockquote><div><br></div><div>Based on the experience with 64-bit VisualWorks I can assure you it has an impact.  Floating point arithmetic will be considerably faster (2 to 3x) and allocations will go way down.  </div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">So my $0.02:<br>
<br>
Do it in careful steps. Release 1 of Spur 64 could have immediate short integers<br>
in the same range as the 32-bit image. Release 2 could follow Bert&#39;s guidance.<br>
Release 3 could fix up the various float primitives and extend the range to 61 bits.<br></blockquote><div><br></div><div>I&#39;m not going to go this way.  I&#39;m going to stick with 61-bit SmallIntegers and SmallFloat64s.  We have a comprehensive test suite and this is core behaviour.  t&#39;s very easy to find issues in this area so, given that the code has been written and is working, there&#39;s no case for backing out.  There&#39;s really nothing to be gained by being conservative here.  Nicolas&#39; concern has been addressed and tests can be written to check.  We can have our cake and eat it to.</div><div><br></div><div>Happy New Year!</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<br>
Dave<br>
<br>
</blockquote></div><br><br clear="all"><div><br></div>-- <br><div class="gmail_signature">best,<div>Eliot</div></div>
</div></div>