<br><br><div class="gmail_quote">On Tue, Feb 14, 2012 at 2:55 PM, Igor Stasenko <span dir="ltr">&lt;<a href="mailto:siguctua@gmail.com">siguctua@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">
On 15 February 2012 00:50, Nicolas Cellier<br>
<div class="im">&lt;<a href="mailto:nicolas.cellier.aka.nice@gmail.com">nicolas.cellier.aka.nice@gmail.com</a>&gt; wrote:<br>
&gt; Le 14 février 2012 23:10, Eliot Miranda &lt;<a href="mailto:eliot.miranda@gmail.com">eliot.miranda@gmail.com</a>&gt; a écrit :<br>
&gt;&gt; On Tue, Feb 14, 2012 at 5:30 AM, Nicolas Cellier<br>
&gt;&gt; &lt;<a href="mailto:nicolas.cellier.aka.nice@gmail.com">nicolas.cellier.aka.nice@gmail.com</a>&gt; wrote:<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; Ah, I came up with a relatively explicit solution, but also quite<br>
&gt;&gt;&gt; heavy in term of number of messages required to implement the<br>
&gt;&gt;&gt; optimisation.<br>
&gt;&gt;&gt; I&#39;m curious to see your implementation :)<br>
&gt;&gt;<br>
&gt;&gt;<br>
&gt;&gt; similar, but should I commit it? I think mine is fine since it is only<br>
&gt;&gt; assignments that have storepop forms, so your generality doesn&#39;t win<br>
&gt;&gt; anything.  but i could be wrong.<br>
&gt;&gt;<br>
&gt;<br>
&gt; I was thinking of<br>
&gt;<br>
&gt; 1) nested ifTrue: ifFalse:<br>
&gt; cond1 ifTrue: [x1 := y] ifFalse: [cond2 ifTrue: [x2 := y] ifFalse: [x3 := y]]<br>
&gt;<br>
&gt; elseExpr statements last is a message, not an assignment, though we<br>
&gt; can factor the pop out...<br>
&gt;<br>
&gt; 2) inlined loop messages don&#39;t require a final pop...<br>
&gt;<br>
&gt; x &lt;= y ifTrue: [x to: y do: [:i | (self at: i) doSome]] ifFalse: [y<br>
&gt; to: x do: [:i | (self at: i) doSome]].<br>
&gt;<br>
&gt; An encoder pushing a value in both branches just to pop it after<br>
&gt; wouldn&#39;t be that well behaved...<br>
&gt;<br>
&gt; I won&#39;t give any version publicly because I crashed several images in<br>
&gt; the bootstrap process, and don&#39;t know if the bug is in the bootstrap<br>
&gt; or in the code.<br>
&gt;<br>
</div>IMO, too much effort for such diminishing returns. :)<br></blockquote><div><br></div><div>That was my thought too.  It would be interesting to quantify the benefits.  I noticed some 451 methods that were improved by my simple assignment-only mod.  How many additional methods get caught by yours Nicolas?</div>
<div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div><div></div><div class="h5"><br>
&gt; Nicolas<br>
&gt;<br>
&gt;&gt;  !MessageNode methodsFor: &#39;code generation&#39; stamp: &#39;eem 2/13/2012 15:25&#39;!<br>
&gt;&gt; ifThenElseForEffectShouldSharePop<br>
&gt;&gt;         | thenExpr elseExpr |<br>
&gt;&gt;         thenExpr := arguments at: 1.<br>
&gt;&gt;         elseExpr := arguments at: 2.<br>
&gt;&gt;         ^((thenExpr isJust: NodeNil)<br>
&gt;&gt;            or: [(elseExpr isJust: NodeNil)<br>
&gt;&gt;            or: [thenExpr statements last isAssignmentNode<br>
&gt;&gt;                   and: [elseExpr statements last isAssignmentNode]]]) not<br>
&gt;&gt;<br>
&gt;&gt;         &quot;^(thenExpr isJust: NodeNil) not<br>
&gt;&gt;            and: [(elseExpr isJust: NodeNil) not<br>
&gt;&gt;            and: [thenExpr statements last isAssignmentNode not<br>
&gt;&gt;                   or: [elseExpr statements last isAssignmentNode not]]]&quot;! !<br>
&gt;&gt;<br>
&gt;&gt;&gt; Also, I&#39;m sure that multiple-jump-elimination proposed by Igor and<br>
&gt;&gt;&gt; other kind of optimization would be a perfect subject for proving<br>
&gt;&gt;&gt; concepts of NewCompiler IR infrastructure.<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; MessageNode&gt;&gt;doesEffectRequiresAPop: encoder<br>
&gt;&gt;&gt;        special &gt; 0<br>
&gt;&gt;&gt;                ifTrue:<br>
&gt;&gt;&gt;                        [^self perform: (MacroTesters at: special) with:<br>
&gt;&gt;&gt; encoder].<br>
&gt;&gt;&gt;        ^super doesEffectRequiresAPop: encoder<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; MessageNode&gt;&gt;doesEffectForIfRequiresAPop: encoder<br>
&gt;&gt;&gt;        &quot;If both branch require a pop instruction, then the pop is factored<br>
&gt;&gt;&gt; after the jump.<br>
&gt;&gt;&gt;        In this case, the translation of this node also require a final pop<br>
&gt;&gt;&gt; that can further be eliminated eventually.&quot;<br>
&gt;&gt;&gt;        | thenExpr elseExpr |<br>
&gt;&gt;&gt;        thenExpr := arguments at: 1.<br>
&gt;&gt;&gt;        elseExpr := arguments at: 2.<br>
&gt;&gt;&gt;        ^((thenExpr isJust: NodeNil) or: [elseExpr isJust: NodeNil]) not<br>
&gt;&gt;&gt;                and: [(thenExpr doesEvaluatingEffectRequiresAPop: encoder)<br>
&gt;&gt;&gt; and:<br>
&gt;&gt;&gt; [elseExpr doesEvaluatingEffectRequiresAPop: encoder]].<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; BlockNode&gt;&gt;doesEvaluatingEffectRequiresAPop: anEncoder<br>
&gt;&gt;&gt;        &quot;Test whether a pop instruction is required to skip the value on<br>
&gt;&gt;&gt; the<br>
&gt;&gt;&gt; stack when this block is inlined.&quot;<br>
&gt;&gt;&gt;        ^statements size &gt; 0 and: [statements last doesEffectRequiresAPop:<br>
&gt;&gt;&gt; anEncoder]<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; AssigmentNode&gt;&gt;doesEffectRequiresAPop: anEncoder<br>
&gt;&gt;&gt;        &quot;Test whether a pop instruction is required to skip the value on<br>
&gt;&gt;&gt; the stack&quot;<br>
&gt;&gt;&gt;        ^(variable canStorePopInASingleInstruction: anEncoder) not<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; InstanceVariableNode&gt;&gt;canStorePopInASingleInstruction: anEncoder<br>
&gt;&gt;&gt;        ^true<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; etc...<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; Le 14 février 2012 01:27, Eliot Miranda &lt;<a href="mailto:eliot.miranda@gmail.com">eliot.miranda@gmail.com</a>&gt; a écrit<br>
&gt;&gt;&gt; :<br>
&gt;&gt;&gt; &gt; OK, I fixed this (a pleasant Monday afternoon distraction) (at least I<br>
&gt;&gt;&gt; &gt; *think* I&#39;ve fixed it; I still have to check the decompiler).  But... in<br>
&gt;&gt;&gt; &gt; doing so I realised I had to fix CompiledMethod&gt;&gt;#= since I needed to<br>
&gt;&gt;&gt; &gt; see<br>
&gt;&gt;&gt; &gt; exactly which methods the compiler change affected (just committed as<br>
&gt;&gt;&gt; &gt; Kernel-eem.669).  In doing this I noticed that recent compiler changes<br>
&gt;&gt;&gt; &gt; have<br>
&gt;&gt;&gt; &gt; not been applied by recompiling affected methods in the system.  If you<br>
&gt;&gt;&gt; &gt; look<br>
&gt;&gt;&gt; &gt; at Behavior&gt;&gt;#sourceMatchesBytecodeAt: it uses CompiledMethod&gt;&gt;#= to<br>
&gt;&gt;&gt; &gt; check<br>
&gt;&gt;&gt; &gt; that the compiler&#39;s output remains unchanged.  In the 4.3 trunk image<br>
&gt;&gt;&gt; &gt; with<br>
&gt;&gt;&gt; &gt; CompiledMethod&gt;&gt;#= fixed, sourceMatchesBytecodeAt: reports that<br>
&gt;&gt;&gt; &gt; some 19654<br>
&gt;&gt;&gt; &gt; methods need recompiling:<br>
&gt;&gt;&gt; &gt;<br>
&gt;&gt;&gt; &gt; (SystemNavigation new allSelect: [:m| (m methodClass<br>
&gt;&gt;&gt; &gt; sourceMatchesBytecodeAt: m selector) not]) size 19654<br>
&gt;&gt;&gt; &gt;<br>
&gt;&gt;&gt; &gt; Being selective in recompiling, via e.g.<br>
&gt;&gt;&gt; &gt;<br>
&gt;&gt;&gt; &gt; SystemNavigation new allSelect: [:m| (m methodClass<br>
&gt;&gt;&gt; &gt; sourceMatchesBytecodeAt:<br>
&gt;&gt;&gt; &gt; m selector) ifFalse: [m methodClass recompile: m selector]. false]<br>
&gt;&gt;&gt; &gt;<br>
&gt;&gt;&gt; &gt; one gets to the desired<br>
&gt;&gt;&gt; &gt;<br>
&gt;&gt;&gt; &gt; (SystemNavigation new allSelect: [:m| (m methodClass<br>
&gt;&gt;&gt; &gt; sourceMatchesBytecodeAt: m selector) not]) size 0<br>
&gt;&gt;&gt; &gt;<br>
&gt;&gt;&gt; &gt; So the question is should we add an update that does the selective<br>
&gt;&gt;&gt; &gt; recompile?  I think we should, e.g. by committing a version of Compiler<br>
&gt;&gt;&gt; &gt; that<br>
&gt;&gt;&gt; &gt; contains the selective recompile as a post-script.  Agreed?<br>
&gt;&gt;&gt; &gt;<br>
&gt;&gt;&gt; &gt; On Mon, Feb 13, 2012 at 11:58 AM, Eliot Miranda<br>
&gt;&gt;&gt; &gt; &lt;<a href="mailto:eliot.miranda@gmail.com">eliot.miranda@gmail.com</a>&gt;<br>
&gt;&gt;&gt; &gt; wrote:<br>
&gt;&gt;&gt; &gt;&gt;<br>
&gt;&gt;&gt; &gt;&gt; Hi All,<br>
&gt;&gt;&gt; &gt;&gt;<br>
&gt;&gt;&gt; &gt;&gt;     (whitewash alert)  I just had occasion to look at the bytecode<br>
&gt;&gt;&gt; &gt;&gt; generated by the standard compiler for HashedCollection<br>
&gt;&gt;&gt; &gt;&gt; class&gt;&gt;#goodPrimeAtLeast:.  Here&#39;s the source, with the issue in bold:<br>
&gt;&gt;&gt; &gt;&gt;<br>
&gt;&gt;&gt; &gt;&gt; goodPrimeAtLeast: lowerLimit<br>
&gt;&gt;&gt; &gt;&gt; &quot;Answer the next good prime &gt;= lowerlimit.<br>
&gt;&gt;&gt; &gt;&gt; If lowerLimit is larger than the largest known good prime,<br>
&gt;&gt;&gt; &gt;&gt; just make it odd.&quot;<br>
&gt;&gt;&gt; &gt;&gt; | primes low mid high prime |<br>
&gt;&gt;&gt; &gt;&gt; primes := self goodPrimes.<br>
&gt;&gt;&gt; &gt;&gt; low := 1.<br>
&gt;&gt;&gt; &gt;&gt; high := primes size.<br>
&gt;&gt;&gt; &gt;&gt; lowerLimit &gt; (primes at: high) ifTrue: [<br>
&gt;&gt;&gt; &gt;&gt; ^lowerLimit bitOr: 1 ].<br>
&gt;&gt;&gt; &gt;&gt; [ high - low &lt;= 1 ] whileFalse: [<br>
&gt;&gt;&gt; &gt;&gt; mid := high + low // 2.<br>
&gt;&gt;&gt; &gt;&gt; prime := primes at: mid.<br>
&gt;&gt;&gt; &gt;&gt; prime = lowerLimit ifTrue: [ ^prime ].<br>
&gt;&gt;&gt; &gt;&gt; prime &lt; lowerLimit<br>
&gt;&gt;&gt; &gt;&gt; ifTrue: [ low := mid ]<br>
&gt;&gt;&gt; &gt;&gt; ifFalse: [ high := mid ] ].<br>
&gt;&gt;&gt; &gt;&gt; (primes at: low) &gt;= lowerLimit ifTrue: [ ^primes at: low ].<br>
&gt;&gt;&gt; &gt;&gt; ^primes at: high<br>
&gt;&gt;&gt; &gt;&gt;<br>
&gt;&gt;&gt; &gt;&gt; The code for this sequence is<br>
&gt;&gt;&gt; &gt;&gt; 58 &lt;15&gt; pushTemp: 5<br>
&gt;&gt;&gt; &gt;&gt; 59 &lt;10&gt; pushTemp: 0<br>
&gt;&gt;&gt; &gt;&gt; 60 &lt;B2&gt; send: &lt;<br>
&gt;&gt;&gt; &gt;&gt; 61 &lt;9B&gt; jumpFalse: 66<br>
&gt;&gt;&gt; &gt;&gt; 62 &lt;13&gt; pushTemp: 3<br>
&gt;&gt;&gt; &gt;&gt; 63 &lt;81 42&gt; storeIntoTemp: 2<br>
&gt;&gt;&gt; &gt;&gt; 65 &lt;92&gt; jumpTo: 69<br>
&gt;&gt;&gt; &gt;&gt; 66 &lt;13&gt; pushTemp: 3<br>
&gt;&gt;&gt; &gt;&gt; 67 &lt;81 44&gt; storeIntoTemp: 4<br>
&gt;&gt;&gt; &gt;&gt; 69 &lt;87&gt; pop<br>
&gt;&gt;&gt; &gt;&gt;<br>
&gt;&gt;&gt; &gt;&gt; where-as the following would be better:<br>
&gt;&gt;&gt; &gt;&gt;<br>
&gt;&gt;&gt; &gt;&gt; 58 &lt;15&gt; pushTemp: 5<br>
&gt;&gt;&gt; &gt;&gt; 59 &lt;10&gt; pushTemp: 0<br>
&gt;&gt;&gt; &gt;&gt; 60 &lt;B2&gt; send: &lt;<br>
&gt;&gt;&gt; &gt;&gt; 61 &lt;9B&gt; jumpFalse: 66<br>
&gt;&gt;&gt; &gt;&gt; 62 &lt;13&gt; pushTemp: 3<br>
&gt;&gt;&gt; &gt;&gt; 63 &lt;82 42&gt; popIntoTemp: 2<br>
&gt;&gt;&gt; &gt;&gt; 65 &lt;92&gt; jumpTo: 69<br>
&gt;&gt;&gt; &gt;&gt; 66 &lt;13&gt; pushTemp: 3<br>
&gt;&gt;&gt; &gt;&gt; 67 &lt;82 44&gt; popIntoTemp: 4<br>
&gt;&gt;&gt; &gt;&gt;<br>
&gt;&gt;&gt; &gt;&gt; The reason is that the code generator favours using a single pop for<br>
&gt;&gt;&gt; &gt;&gt; both<br>
&gt;&gt;&gt; &gt;&gt; arms of the if:<br>
&gt;&gt;&gt; &gt;&gt;<br>
&gt;&gt;&gt; &gt;&gt; MessageNode&gt;&gt;sizeCodeForIf: encoder value: forValue<br>
&gt;&gt;&gt; &gt;&gt; | thenExpr elseExpr branchSize thenSize elseSize |<br>
&gt;&gt;&gt; &gt;&gt; thenExpr := arguments at: 1.<br>
&gt;&gt;&gt; &gt;&gt; elseExpr := arguments at: 2.<br>
&gt;&gt;&gt; &gt;&gt; (forValue<br>
&gt;&gt;&gt; &gt;&gt; or: [(thenExpr isJust: NodeNil)<br>
&gt;&gt;&gt; &gt;&gt; or: [elseExpr isJust: NodeNil]]) not<br>
&gt;&gt;&gt; &gt;&gt; &quot;(...not ifTrue: avoids using ifFalse: alone during this compile)&quot;<br>
&gt;&gt;&gt; &gt;&gt; ifTrue:  &quot;Two-armed IFs forEffect share a single pop&quot;<br>
&gt;&gt;&gt; &gt;&gt; [^super sizeCodeForEffect: encoder].<br>
&gt;&gt;&gt; &gt;&gt; ...<br>
&gt;&gt;&gt; &gt;&gt;<br>
&gt;&gt;&gt; &gt;&gt; MessageNode&gt;&gt;emitCodeForIf: stack encoder: encoder value: forValue<br>
&gt;&gt;&gt; &gt;&gt; | thenExpr thenSize elseExpr elseSize |<br>
&gt;&gt;&gt; &gt;&gt; thenSize := sizes at: 1.<br>
&gt;&gt;&gt; &gt;&gt; elseSize := sizes at: 2.<br>
&gt;&gt;&gt; &gt;&gt; (forValue not and: [elseSize * thenSize &gt; 0]) ifTrue:<br>
&gt;&gt;&gt; &gt;&gt; &quot;Two-armed IFs forEffect share a single pop&quot;<br>
&gt;&gt;&gt; &gt;&gt; [^super emitCodeForEffect: stack encoder: encoder].<br>
&gt;&gt;&gt; &gt;&gt;<br>
&gt;&gt;&gt; &gt;&gt; It would be nice if this only happened if doing so actually reduced the<br>
&gt;&gt;&gt; &gt;&gt; size of the generated code.<br>
&gt;&gt;&gt; &gt;&gt; --<br>
&gt;&gt;&gt; &gt;&gt; best,<br>
&gt;&gt;&gt; &gt;&gt; Eliot<br>
&gt;&gt;&gt; &gt;&gt;<br>
&gt;&gt;&gt; &gt;<br>
&gt;&gt;&gt; &gt;<br>
&gt;&gt;&gt; &gt;<br>
&gt;&gt;&gt; &gt; --<br>
&gt;&gt;&gt; &gt; best,<br>
&gt;&gt;&gt; &gt; Eliot<br>
&gt;&gt;&gt; &gt;<br>
&gt;&gt;&gt; &gt;<br>
&gt;&gt;&gt; &gt;<br>
&gt;&gt;&gt; &gt;<br>
&gt;&gt;&gt;<br>
&gt;&gt;<br>
&gt;&gt;<br>
&gt;&gt;<br>
&gt;&gt; --<br>
&gt;&gt; best,<br>
&gt;&gt; Eliot<br>
&gt;&gt;<br>
&gt;&gt;<br>
&gt;&gt;<br>
&gt;&gt;<br>
&gt;<br>
<br>
<br>
<br>
</div></div><div><div></div><div class="h5">--<br>
Best regards,<br>
Igor Stasenko.<br>
<br>
</div></div></blockquote></div><br><br clear="all"><div><br></div>-- <br>best,<div>Eliot</div><br>