<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Thu, Apr 23, 2015 at 3:46 AM, Clément Bera <span dir="ltr">&lt;<a href="mailto:bera.clement@gmail.com" target="_blank">bera.clement@gmail.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"> <br><div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">2015-04-23 1:20 GMT+02:00 Eliot Miranda <span dir="ltr">&lt;<a href="mailto:eliot.miranda@gmail.com" target="_blank">eliot.miranda@gmail.com</a>&gt;</span>:<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"> <br><div dir="ltr">Hi Clément,<div><br><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Apr 22, 2015 at 2:07 AM, Clément Bera <span dir="ltr">&lt;<a href="mailto:bera.clement@gmail.com" target="_blank">bera.clement@gmail.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"> <br><div dir="ltr">Eliot here&#39;s a good example to stress the register allocation:<div><br></div><div><div>Integer&gt;&gt;#regStress</div><div><span style="white-space:pre-wrap">        </span>| t t2 |</div><div><span style="white-space:pre-wrap">        </span>t := self yourself.</div><div><span style="white-space:pre-wrap">        </span>t2 := self + 1.</div><div><span style="white-space:pre-wrap">        </span>^ { t == t2 .   t == t2 .  t == t2 .  t == t2 .  t == t2 .  t == t2 .  t == t2 }</div></div><div><br></div><div>I think the resulting machine code method is beautiful, it needs to spill only when it runs out of registers :-). Of course it makes sense mainly when you use inlined bytecodes instead of only #==.</div><div><br></div><div>Some extra register moves are done because the JIT does remember if a temporary value is currently in a register (It moves each time the temp t to the same register whereas the register value is not changed). Maybe we should add a feature that remembers if temporaries are currently in a register, and if so, when doing push temp, only push the register directly in the simStack, and in case of temporary store or stack flush the register associated with a temp is not valid anymore somehow...<br></div></div></blockquote><div><br></div><div>Here&#39;s a sketch of something that looks to me like it would work.</div><div><br></div><div>A CogSimStackEntry for a temp var is of type SSBaseOffset.  Its register field is used to hold the frame pointer.  We want to mark it as having its value in a register, so it needs a new field, lets call it allocatedRegOrNil.  At start of compilation all SSBaseOffset entries have allocatedRegOrNil nil.</div><div><br></div><div>Whenever popToReg: finds it is popping an SSBaseOffset entry it sets that entry&#39;s allocatedRegOrNil to the register.</div><div>Whenever a register is spilled (in ssFlushTo:) the sim stack is also scanned looking for all SSBaseOffset entries whose allocatedRegOrNil equals the register, and simply sets allocatedRegOrNil back to nil.</div><div><br></div><div>On merge, with the current representation we merely set all allocatedRegOrNil fields back to nil.  But with the more sophisticated stack copy merge we can preserve allocation for entries whose registers match.</div><div><br></div><div>There are perhaps tricky details in merge (the same register used for different temporaries in different branches, etc) but otherwise it is very simple, no?</div></div></div></div></div></blockquote><div><br></div><div>Yeah something like that would be nice. There are details such as liveRegisters should include those registers. Maybe this logic could be somehow merged with the one of ReceiverResultReg which has currently its own live status and may not need so.</div></div></div></div></blockquote><div><br></div><div>Yes that&#39;s a good idea.  One would just do popToRequiredReg: ResultReceiverReg on the self stack entry and if ResultReceiverReg currently held the receiver it would be a no-op.  Nice.</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div>Btw I changed <span style="font-size:12.8000001907349px">#genStorePop: popBoolean LiteralVariable: litVarIndex so it uses register allocation instead of ReceiverResultReg and ClassReg. There was a flag saying that it could be used in frameless methods if register allocation was used. However I wonder, can you have a ceStoreCheck in a frameless method ? I could work around the need for ReceiverResultReg in the trampoline by adding extra register moves but I am not sure a trampoline can work fine in frameless method.</span></div></div></div></div></blockquote><div><br></div><div><span class="Apple-style-span">Yes, trampolines can work in any state.  They&#39;re orthogonal to framelessness.  Trampolines call into the C run-time.  To do so they must switch stack, saving the hardware stack pointers into stackPointer and framePointer. loading the hardware stack pointers with the C stack, making the call, and on return, switching back to the Smalltalk stack.  But it doesn&#39;t matter what state Smalltalk is in; the stack pointers referring to the caller method or the callee method makes no difference to the trampoline, only to the code </span>the<span class="Apple-style-span"> trampoline calls.  With something like the store check, the stack is unexamined; all that happens is that </span>the<span class="Apple-style-span"> argument gets added to the remembered table.</span></div><div><span class="Apple-style-span"><br></span></div><div><span class="Apple-style-span">Framelessness occurs in three different forms:</span></div><div><span class="Apple-style-span"><br></span></div><div><span class="Apple-style-span">- One is a method that doesn&#39;t contain any sends other than the special selectors #== and #class, doesn&#39;t access temporaries beyond the arguments.  So for example Interval&gt;&gt;setFrom:to:by:, which contains three inst var assignments and three store checks. </span></div><div><span class="Apple-style-span"><br></span></div><div><span class="Apple-style-span">- Another is a frameless block.  This is the same as a frameless method except that block activation implies that the receiver and register arguments will have been pushed, so the stack layout is a little different.</span></div><div><span class="Apple-style-span"><br></span></div><div><span class="Apple-style-span">- the final case is a method with a primitive.  The code up until a primitive fails is frameless.  If a primitive is implemented in machine code then the stack and register arguments are undisturbed; the primitive will access its operands from the registers if that&#39;s where they are.  If a primitive is implemented in C (an interpreter primitive), or the machine code primitive calls the interpreter primitive when it fails (which allows the machine code to handle the simple common cases, falling back on slower more comprehensive C code), then, like a frameless block, receiver and arguments are pushed on the stack, because interpreter primitives can only get their operands from the stack via stackPointer.</span></div><div><span class="Apple-style-span"><br></span></div><div><span class="Apple-style-span">The above implies that the ceStoreCheck trampoline may be called from any of the above frameless forms, as well as from a method with a full frame.</span></div><div><span class="Apple-style-span"><br></span></div><div><span class="Apple-style-span">So if you&#39;ve broken frameless inst var store pop, please fix it ;-).  But I doubt you have because the code is explicit:</span></div><div><span class="Apple-style-span"><br></span></div><div><span class="Apple-style-span"><div>genStorePop: popBoolean ReceiverVariable: slotIndex</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>&lt;inline: false&gt;</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>| topReg valueReg constVal |</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>needsFrame ifFalse:</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>[^self genFramelessStorePop: popBoolean ReceiverVariable: slotIndex].</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>self ssFlushUpThroughReceiverVariable: slotIndex.</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>&quot;Avoid store check for immediate values&quot;</div><div>...</div><div><br></div></span>so the body of genStorePop:ReceiverVariable: does not have to deal with framelessness.  Remember that in a frameless method (and IIRC in a frameless block) ReceiverResultReg /always/ contains self.<span class="Apple-style-span"><div><br></div><div>The limitation of the trampolines is that they expect specific register arguments; each one expects its own particular sequence of register arguments that the code generator must use to call them.  But that doesn&#39;t mean you couldn&#39;t for example implement ceStoreCheckReceiverRegTrampoline, ceStoreCheckClassRegTrampoline etc, etc, provided you can handle the complexity.</div><div><br></div><div><br></div></span></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><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"><div dir="ltr"><div><div class="gmail_extra"><div class="gmail_quote"><div><br></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"><div dir="ltr"><div></div><div>2015-04-22 10:08 GMT+02:00  <span dir="ltr">&lt;<a href="mailto:commits@source.squeak.org" target="_blank">commits@source.squeak.org</a>&gt;</span>:<br></div></div><div class="gmail_extra"><div class="gmail_quote"><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>
Eliot Miranda uploaded a new version of VMMaker to project VM Maker:<br>
<a href="http://source.squeak.org/VMMaker/VMMaker.oscog-cb.1236.mcz" target="_blank">http://source.squeak.org/VMMaker/VMMaker.oscog-cb.1236.mcz</a><br>
<br>
==================== Summary ====================<br>
<br>
Name: VMMaker.oscog-cb.1236<br>
Author: cb<br>
Time: 22 April 2015, 10:07:41.028 am<br>
UUID: cf4af270-9dfa-4f2a-b84c-0cdb3c5f4913<br>
Ancestors: VMMaker.oscog-tpr.1235<br>
<br>
changed the names of register allocation methods for more explict names, for instance, allocateOneReg -&gt; allocateRegForStackTop<br>
<br>
Fixed a bug where not the best register was allocated in #== (was allocating a reg based on stackTop value instead of ssValue: 1)<br>
<br>
=============== Diff against VMMaker.oscog-tpr.1235 ===============<br>
<br>
Item was changed:<br>  </blockquote></div></div></blockquote></div></div></div></div></blockquote></div></div></div></blockquote><div> </div><div>deletia</div></div>-- <br><div class="gmail_signature">best,<div>Eliot</div></div>
</div></div>