<div dir="ltr">As an <a href="https://gcc.gnu.org/wiki/JohnYates">erstwhile compiler writer</a> I was struck by the SPEC CPU 2006 example in <a href="http://blog.regehr.org/archives/1192">Souper Results 2</a>.  I thought I would jot down a few notes on how 20 years ago the Apollo Computer's compiler for the DN10K would have handle it.<div><br></div><div>That compiler represented dataflow using SSA.  As I mentioned in my gcc wiki page we employed a hybrid approach of SSA-values threaded through a classic CFG and bound to live-range containers.  In preparation for constant propagation we would examine values leading up to conditional branches.  When such a value was mentioned within the range affected by that branch flow we inserted pseudo definitions to capture facts derivable from the control expression.  That allowed derived facts to be exploited within the range of the control flow.  The phi-operator at the control flow join restored the original, less specific set of facts..<div><br></div><div>Constant propagation was via an extension of <a href="http://www.cs.ucr.edu/~gupta/teaching/201-08/Papers/const.pdf">Wegman and Zadeck's algorithm</a>.  Rather than propagate single constants through the graph we propagated "bundles".  These were compact descriptions of what we knew about the values flowing along an edge.  A bundle contianed 6 cells equal to the width of the machine resource being modeled (typically a register-width value):</div></div><div><ul><li>signed min</li><li>signed max</li><li>unsigned min</li><li>unsigned max</li><li>mask: bit is known</li><li>mask: bit actual value</li></ul><div>Symbolic execution of intermediate operators took bundles as operands and returned new bundles.  Implementing operators was a fun challenge.  Addition and subtraction went to the trouble of determining whether the carry in and out of each bit position was known, thereby preserving interesting facts about bits patterns.  We were not limited to equality comparisons to zero.  Given</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">if (x < 0)</blockquote><div><br></div><div>we could represent the fact that the sign bit was on the then side and off on the else side.  And given your example of</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">if ((x & 0xf) == 0)</blockquote><div><br></div><div>we would might know nothing more on the else branch, but on the then branch (at the very least) we would know</div><div><ul><li>bit is known mask = 0xf</li><li>bit value mask = 0</li></ul><div>When that bundle fed a subsequent</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">if ((x & 0x7) == 0)</blockquote><div><br></div><div>constant propagation we tell us that the else branch would never be taken.</div><div><br></div><div>/john</div><div><br></div></div>