<div style="font-family: arial, helvetica, sans-serif"><font size="2"><div class="gmail_quote">On Wed, Jun 20, 2012 at 11:57 PM, Sean Silva <span dir="ltr"><<a href="mailto:silvas@purdue.edu" target="_blank">silvas@purdue.edu</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">The Records already have a member `unsigned ID` which is unique. Specializing the less/hash traits classes to perform the less/hashing on that `unsigned` will result in deterministic behavior (since the nondeterminism arises entirely from the pointer values; both "<" and the hash functions are deterministic (although the hash table order might change more than comfortable with small changes to the .td files or the backend)).</blockquote>
<div><br></div><div>The hash function should never be relied on to be deterministic. One of these days I'm going to have the stones to flip a switch and the hash function will produce different values on each execution with high probability.</div>
<div><br></div><div>Even without this, the bucket resizing alone can produce highly surprising artifacts here. If you want deterministic output, sort them.</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
 My question is mostly looking for ideas about how to perform the migration. There are numerous places in the backends where this nondeterminism is attacked in various "ad-hoc" ways, and it seems like a more coherent "right by design" approach is needed.<div>

<br></div><div>For example, I ran into all of the following:</div><div><br></div><div>* Places where a custom comparator is passed to map/set (there are no fewer than 3 custom comparators across the backends). With these, it is not usually clear without really understanding the code whether the actual order is actually important for the emission, or whether it is "just" to avoid the nondeterminism.</div>

<div>* Don't use a custom comparator, but sort afterwards. Like the above, with these its not usually clear without really understanding the code whether the sort is actually an important part of what is being emitted, or a band-aid for the nondeterministic container order.</div>

<div>* Just use nondeterministic order (AsmMatcherEmitter.cpp is particularly nasty). These are usually littered with bare std::map/set, with no typedefs to show what the types are semantically, so without fully understanding the code it is not possible to perform any maintenance that would result in any appreciable unification/simplification of the handling of the nondeterminism.</div>
</blockquote><div><br></div><div>I think you're muddying the waters here a bit.</div><div><br></div><div>There are two sources of non-deterministic output that seem to be at issue:</div><div><br></div><div>1) Non-deterministic order of iteration data structures. All of these in the codebase to my knowledge are some variant of a hash table.</div>
<div>2) Not-deterministic "ID" used as the key to a data structure or algorithm.</div><div><br></div><div>These are orthogonal, and can overlap.</div><div><br></div><div>The solutions to #1 seem straight forward, but which one is best depend upon the context so it is hard to make blanket rules. Sometimes, build up a vector and sort it. Sometimes, use a SetVector. Sometimes, switch entirely from a hashing-based container to a sorted container. There are a lot of options here. We can make it harder to get wrong by using a wrapper around the hash table which does not support direct iteration, forcing the use of a sorted output buffer.</div>
<div><br></div><div>The solutions to #2 are often a bit trickier to come up with. Record has a good one, but do other entities? How do we establish them? What is the right technique to use to establish stable keys?</div><div>
<br></div><div>An interesting benefit of SetVector is that it tends to solve both #1 and #2 simultaneously. However, it has a high cost associated with it.</div><div><br></div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

<div>Maybe a good first step would be to instrument TableGen to force the pointer values to be "really nondeterministic" so that problems will crop up if they exist?</div></blockquote><div><br></div><div>Just repeatedly generate the output on a system with ASLR?</div>
<div><br></div><div>How about we add a mode to the build system which re-generates each tablegen entry on each build, and asserts that it matches the one used for that build? Then the build bots will go red if we mess this up.</div>
</div></font></div>