title: 'Correct' unsigned integer comparison
body: <p>So, we all know the C/C++ signed/unsigned comparison rules where <code>-1 &gt; 2u == true</code>, and I have a situation where I want to implement 'correct' comparisons efficiently.</p>
  
  <p>My question is, which is more efficient with considerations to as many architectures as people are familiar with. Obviously Intel and ARM have higher weight.</p>
  
  <p>Given:</p>
  
  <pre><code>int x;
  unsigned int y;
  if (x &lt; y) {}
  </code></pre>
  
  <p>Is it better to promote:</p>
  
  <pre><code>x &lt; y  =&gt;  (int64)x &lt; (int64)y
  </code></pre>
  
  <p>or is it better to perform 2 comparisons, ie:</p>
  
  <pre><code>x &lt; y  =&gt;  (x &lt; 0 || x &lt; y)
  </code></pre>
  
  <p>The former implies a zero-extend, sign-extend, and one comparison+branch, and latter requires no sign-extend operations, but 2 consecutive cmp+branches.<br>
  Traditional wisdom suggests that branches are more expensive than sign extends, which will both pipeline, but there is a stall between the extends and the single comparison in the first case, whereas in the second case I can imagine that some architectures might pipeline the 2 comparisons, but then followed by 2 conditional branches?  </p>
  
  <p>Another case exists, where the unsigned value is a smaller type than the signed type, which means it can be done with a single zero-extend to the signed type's length, and then a single comparison... in that case, is it preferable to use the extend+cmp version, or is the 2-comparison method still preferred?</p>
  
  <p>Intel? ARM? Others?
  I'm not sure if there's a right answer here, but I'd like to hear peoples take's. Low-level performance is hard to predict these days, especially on Intel and increasingly so on ARM.</p>
  
  <p>Edit:</p>
  
  <p>I should add, there is one obvious resolution, where the types are sized equal to the architecture int width; in that case it is obvious that the 2-comparison solution is preferred, since the promotion itself can't be performed efficiently. Clearly my <code>int</code> example meets this condition for 32-bit architectures, and you can transpose the thought experiment to <code>short</code> for the exercise applied to 32bit platforms.</p>
  
  <p>Edit 2:</p>
  
  <p>Sorry, I forgot the <code>u</code> in <code>-1 &gt; 2u</code>! >_&lt;</p>
  
  <p>Edit 3:</p>
  
  <p>I want to amend the situation to assume that the result of the comparison an actual branch, and the result is NOT returned as a boolean. This is how I'd prefer the structure look; although this does raise an interesting point that there is another set of permutations when the result is a bool vs a branch.</p>
  
  <pre><code>int g;
  void fun(int x, unsigned in y) { if((long long)x &lt; (long long)y) g = 10; }
  void gun(int x, unsigned in y) { if(x &lt; 0 || x &lt; y) g = 10; }
  </code></pre>
  
  <p>This produces the intended branch typically implied when you encounter an <code>if</code> ;)</p>