<div dir="ltr"><div class="gmail_extra"><br><div class="gmail_quote">On Tue, May 23, 2017 at 7:10 AM, James Molloy <span dir="ltr"><<a href="mailto:James.Molloy@arm.com" target="_blank">James.Molloy@arm.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">



<div style="word-wrap:break-word">
<div>Hi,</div>
<div><br>
</div>
<div>Firstly, overall I think perfection shouldn't stand in the way of progress and that GVNSink is a good improvement on the really bad bisimulation algorithm in SimplifyCFG. Do you have any objections to it going in-tree and I can work on improving/rewriting
 the algorithm there, after I remove the old SimplifyCFG algorithm?</div>
<div><br></div></div></blockquote><div>Sure, i have no objection, i'm just trying to understand the set of problems you face. I'm happy to accept it and continue this discussion.</div><div><br></div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word"><div>
</div>
<div>I'm afraid I don't fully follow you. What compounds this is that you've referred to this (inverted or post value numbering) being in the literature somewhere, but I've totally failed to find it. Do you have any starting pointers?</div></div></blockquote><div><br></div><div>No, it does not exist in literature that i'm aware of, at least under that name :)</div><div>There are "predictive commoning" algorithms, but most are loop based.</div><div><br></div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word">
<div><br>
</div>
<div>Consider the following example, which is one of the simple motivating testcases for the creation of GVNSink (it doesn't show all the features of GVNSink by a long way, but it does illustrate a problem):</div>
<div><br>
</div>
<div><font face="Menlo">bb1:</font></div>
<div><font face="Menlo">  x1 = load %p</font></div>
<div><font face="Menlo">  x2 = add x1, %g</font></div>
<div><font face="Menlo">  x3 = add x2, 5</font></div>
<div><font face="Menlo">  x4 = add x3, %g2</font></div>
<div><font face="Menlo">  store x4, %p</font></div>
<div><font face="Menlo">  goto bb3</font></div>
<div><font face="Menlo"><br>
</font></div>
<div><font face="Menlo">bb2:</font></div>
<div><font face="Menlo">  y1 = load %p</font></div>
<div><font face="Menlo">  y2 = add y1, %g</font></div>
<div><font face="Menlo">  y3 = add y2, 42</font></div>
<div><font face="Menlo">  y4 = add y3, %g2</font></div>
<div><font face="Menlo">  store y4, %p</font></div>
<div><font face="Menlo">  goto bb3</font></div><span class="gmail-">
<div><br>
</div>
<div>In this example all instructions can be sunk to bb3 with just one phi(5, 42). I'm trying to understand how your suggestion would work. </div></span></div></blockquote><div><br></div><div>Sure.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word"><span class="gmail-"><div>You said:</div>
<div><br>
</div>
<div>"(in particular, you will create a phi for any value with two different leaders at a join point you must pass to sink it. If you calculate this properly, and in topo order of expressions, such that you process operands before things that use them,
 you can calculate the number of phis you would insert in O(N) time overall)"</div>
<div><br>
</div>
</span><div>My difficulty is that I can't think of a value numbering function that wouldn't diverge at {x3, y3}. Consider a "normal" value numbering in which VN[x] == VN[y] iff congruent(x, y):</div>
<div><br></div></div></blockquote><div><br></div><div>Let me try to phrase it another way that may be easier to understand.</div><div>Let's start with regular GVN because it's a bit easier to understand, and then i'll transform it into your problem.</div><div><br></div><div>In either full redundancy elimination or partial redundancy elimination, the possible insertion points of the expression (represented by phis) is directly related to the availability of operands of a given expression.</div><div>You are only eliminating things that have the same value, and thus, you only need to be able to create that value at a given point.</div><div><br></div><div>Whether you need a phi node to eliminate an expression to do so is dictated by the following:</div><div><br></div><div>If the operands are available in a dominator, you do not need a phi.</div><div>If they are only available in predecessors, you need a phi.  </div><div><br></div><div>What does the second mean?</div><div>Well, in a value based world it means you are merging two non-dominating operands into a single one with the same value.</div><div>The only case that can occur where it is available in all predecessors and not dominate you is for there to be different leaders for the same value number in some set of predecessors.<br></div><div><br></div><div>Proof:<br></div><div>The definition of dominance means that all paths from a entry to a given node go through a certain block.  For the same operand to be available in all predecessors and not dominate you, it implies there is a path around the dominator to your block through one of these predecessors, so that it doessn't dominate you.  Which implies the dominator doesn't dominate you, since that path can be used as a path from entry to your block without going through the dominator :)</div><div><br></div><div>What does all of this imply?</div><div>It means for FRE/PRE, the set of phi nodes you could ever insert for an expression, no matter where you move it, is the iterated dominance frontier of all of the definition blocks of the leaders for each operand (recursively computed), plus the IDF of the blocks the expression currently occurs).  The first is because that is where the expression may change, and thus, may need a phi of the old and new leaders for it. The second is because those are the places where you may eliminate redundancies due to being able to merge existing copies.</div><div><br></div><div>IE given VN1+VN2, the set of phis you could ever insert is:</div><div><br></div><div>IDF(definition blocks of leaders of VN1 U definition blocks of leaders of VN2 U blocks that have an occurrence of VN1 + VN2)</div><div>It actually is completely and totally irrelevant *what* notion of congruence you use for VN1 or VN2. The only relevant part is the location of the things you are calling leaders.</div><div><br></div><div>This is the complete set of phis you could ever insert to move a "value expression" somewhere valid.</div><div>It is a superset of the valid insertion points. (I'm going to use insertion point to mean ' a place you could recreate the expression', whether that is by merging two existing copies, or by actually placing a new instruction)</div><div><br></div><div>(SSAPRE and others prune the set a bit when dealing with lexical identity. Such pruning is not optimal or valid in some cases when dealing with value numbers)</div><div><br></div><div>Not every insertion point is valid, and the rest of the computation is determining which are valid, and which eliminate redundancies safely (where "safe" here is defined as not inserting new computations along paths they don't already get computed on).</div><div><br></div><div>This is also true of your value numbering - not all points are really safe.  That does not change the superset, it only changes which ones end up being valid points in the end :)</div><div><br></div><div>Now let's see how this applies to your problem:</div><div><br></div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word"><div>
</div>
<div><br>
</div>
<div><font face="Menlo">bb1:</font></div>
<div><font face="Menlo">  x1 = load %p     [VN=1]</font></div>
<div><font face="Menlo">  x2 = add x1, %g  [VN=2]</font></div>
<div><font face="Menlo">  x3 = add x2, 5   [VN=3]</font></div>
<div><font face="Menlo">  x4 = add x3, %g2 [VN=4]</font></div>
<div><font face="Menlo">  store x4, %p     [VN=5]</font></div>
<div><font face="Menlo">  goto bb3</font></div>
<div><font face="Menlo"><br>
</font></div>
<div><font face="Menlo">bb2:</font></div>
<div><font face="Menlo">  y1 = load %p     [VN=1]</font></div>
<div><font face="Menlo">  y2 = add y1, %g  [VN=2]</font></div>
<div><font face="Menlo">  y3 = add y2, 42  [VN=6]  <-- 42 != 5, so VN[y3] != VN[x3]</font></div>
<div><font face="Menlo">  y4 = add y3, %g2 [VN=7]</font></div>
<div><font face="Menlo">  store y4, %p     [VN=8]  <-- value numbers have diverged</font></div>
<div><font face="Menlo">  goto bb3</font></div>
<div><br>
</div>
<div>Now consider an inverse value numbering in which VN[x] == VN[y] => x or y's uses can be replaced with phi(x, y):</div>
<div><br>
</div>
<div><font face="Menlo">bb1:</font></div>
<div><font face="Menlo">  x1 = load %p     [VN=7]  <-- value numbers have diverged</font></div>
<div><font face="Menlo">  x2 = add x1, %g  [VN=6]  <-- x2 cannot be used the same as y2; different constants get added</font></div>
<div><font face="Menlo">  x3 = add x2, 5   [VN=3]  <-- x3 is used the same as y3</font></div>
<div><font face="Menlo">  x4 = add x3, %g2 [VN=2]</font></div>
<div><font face="Menlo">  store x4, %p     [VN=1]</font></div>
<div><font face="Menlo">  goto bb3</font></div>
<div><font face="Menlo"><br>
</font></div>
<div><font face="Menlo">bb2:</font></div>
<div><font face="Menlo">  y1 = load %p     [VN=5]</font></div>
<div><font face="Menlo">  y2 = add y1, %g  [VN=4]</font></div>
<div><font face="Menlo">  y3 = add y2, 42  [VN=3]</font></div>
<div><font face="Menlo">  y4 = add y3, %g2 [VN=2]</font></div>
<div><font face="Menlo">  store y4, %p     [VN=1]</font></div>
<div><font face="Menlo">  goto bb3</font></div>
<div><br>
</div>
<div>Both value numberings notice the similarity of only half the sinkable instructions.</div>
<div><br>
</div>
<div>The way I get around this in GVNSink is to define VN[x] as an *optimistic* function that only takes into account the opcodes and number of uses. This allows it to number x2 and y2 the same, even though they could not actually replace each other.
 The value numbering is used purely as a tool to narrow the search space - bisimulation (or n-simulation!) takes over after that to ensure validity.</div>
<div><br>
</div>
<div>The way I'm thinking about this problem, there is surely no such value numbering function that will indicate when a PHI is needed and will not diverge at that point. Therefore, I must be thinking about the problem differently (wrongly) to you.</div></div></blockquote><div><br></div><div>The set of phis you may ever need to sink such expressions still has not changed from above. Only your definition of congruence.</div><div>The possible insertion point for your expression is bb3.</div><div>Recursively, it turns out to recreate VN3, you need a phi to merge 42, 5 because there are different leaders for the operands of VN3 in your predecessors (for 42 and 5)[1]. You need a phi to merge x2, y2 for the same reason.  </div><div>Once that is done, you will have<br></div><div>op1 = phi(x2, y2)</div><div>op2 = phi(42, 5)</div><div>newval = op1 + op2 (VN3)</div><div><br></div><div><br></div><div>Whether you now need a phi for VN3, depends on the locations of the other occurrences of VN3 other than newval.</div><div>As i said, it is easier to process expressions in topo order to be able to compute the possible phis  ahead of time.</div><div>Because once you've done the above, and go to process VN2, the answer to whether you *need* phis requires knowing that newval will exist.</div><div>It's infinitely easier to just require that newval be inserted already at that point, and a leader of the right value number, if you can.</div><div><br></div><div>In your world, things are easier because you do not perform new insertions (that i remember!)</div><div>Only merges.</div><div>Thus,  you would process them in reverse topo order, such that you would sink store phi(x4, y4)</div><div>then sink add phi(y3, x3), g2, etc.</div><div><br></div><div>You can still use the computation i gave. it just may require more iterations.</div><div>There is a more exact computation you could use, but it's complicated.</div><div><br></div><div>So, yes, i understand that  the problem you are solving is this:</div><div><br></div><div>Given a hypothetical expression X op Y placed in block BB, are there things i can fill in for X and Y that would make this expression valid an enable me to eliminate existing copies.</div><div>The answer to where this hypothetical expression could ever be placed, and eliminate existing copies, is still the same as i gave above, even if you change the definition of congruence.</div><div><br></div><div>Those are the possible (but maybe not valid or useful)  insertion/move points, and the set of places a given *expression* may need a phi node.</div><div>Having an over-inclusive definition of congruence just means the space of phis you search is larger than you want.</div><div><br></div><div><br></div><div>(i could also show you how you could actually do this as a true inverse PRE problem, and sparsely solve it, but i wouldn't bother if what you hvae works for you :P)</div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word"><div><br>
</div>
<div>Could you please enlighten me or maybe point me at papers?</div>
<div><br>
</div>
<div>Cheers, and apologies for the slowness in picking this up.</div><span class="gmail-HOEnZb"><font color="#888888">
<div><br>
</div>
<div>James</div></font></span><div><div class="gmail-h5">
<div>
<blockquote type="cite">
<div>On 22 May 2017, at 17:46, Daniel Berlin <<a href="mailto:dberlin@dberlin.org" target="_blank">dberlin@dberlin.org</a>> wrote:</div>
<br class="gmail-m_1436080240826007692Apple-interchange-newline">
<div>
<div dir="ltr"><br>
<div class="gmail_extra"><br>
<div class="gmail_quote">On Mon, May 22, 2017 at 8:41 AM, James Molloy <span dir="ltr">
<<a href="mailto:James.Molloy@arm.com" target="_blank">James.Molloy@arm.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
Hi,<br>
<br>
Thanks for the quick reply; this is a very helpful and constructive discussion :)<br>
</blockquote>
<div><br>
</div>
<div>Happy to help :)</div>
<div> </div>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
The oversimplification and repetition below is for my own understanding and so that I can better understand your replies, as you know this subject far better than I.<br>
<span><br>
A: store 1<br>
B: store 2<br>
C: store 3<br>
</span>D:<br>
<br>
I understand that in a classical sinking algorithm we'd want to walk backwards:<br>
  1) Sink 'store 3' from C to D<br>
  2) Sink 'store 2' from B to D<br>
  3) Sink 'store 1' from A to D<br>
<br>
A key to this working is that each instruction, when considered, was sunk as far as it could be. If we had added the restriction that an instruction could only be sunk to its immediate successor block, that algorithm would have taken three iterations to reach
 a fixpoint.<br>
</blockquote>
<div>Yes</div>
<div> <br>
</div>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
GVNSink can (at the moment at least) only sink instructions from a block into its immediate successor. This is what allows it to model accurately enough how many PHIs it is going to create and whether sinking is actually worthwhile (and how much sinking)</blockquote>
<div><br>
</div>
<div>How much is the former, and how much is the later?</div>
<div><br>
</div>
<div>The number of phis you can create is calculable ahead of time in O(N) time for all operands, and related the availability of values</div>
<div>(in particular, you will create a phi for any value with two different leaders at a join point you must pass to sink it. If you calculate this properly, and in topo order of expressions, such that you process operands before things that use them,
 you can calculate the number of phis you would insert in O(N) time overall)</div>
<div><br>
</div>
<div><br>
</div>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
. I don't believe it would be able to handle all the cases it currently does if it didn't have this restriction (but would be able to handle other cases that it currently can't, so I see that very much as an enhancement I'd like to add later).<br>
</blockquote>
<div><br>
</div>
<div>I actually don't buy this, fwiw.</div>
<div>It's entirely possible to calculate all the hypothetical insertion points ahead of time, and figure out which make sense from a cost perspective.</div>
<div>There are sinking (and PRE) algorithms that do this.<br>
You could do exactly the same cases you do now.</div>
<div><br>
</div>
<div><br>
</div>
<div>Now, whether you want that complexity is a different question :)</div>
<div><br>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</div>
<br></div></div><span class="gmail-">
IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose,
 or store or copy the information in any medium. Thank you.
</span></div>

</blockquote></div><br></div></div>