{"id":105288,"date":"2021-06-07T07:00:00","date_gmt":"2021-06-07T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=105288"},"modified":"2021-06-07T07:19:57","modified_gmt":"2021-06-07T14:19:57","slug":"20210607-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20210607-00\/?p=105288","title":{"rendered":"The ARM processor (Thumb-2), part 6: The lie hiding inside the CMN instruction"},"content":{"rendered":"<p>Last time, we learned that <a title=\"The ARM processor (Thumb-2), part 5: Arithmetic\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20210604-00\/?p=105280\"> the <code>CMN<\/code> instruction stands for <i>compare negative<\/i><\/a>, and it compares its first argument with the negative of the second argument:<\/p>\n<pre>    ; compare negative (compare Rn with -op2)\r\n    cmn     Rn, op2             ; Set flags for Rn + op2\r\n<\/pre>\n<p>We noted that the <code>N<\/code> in the name is misleading, because it stands for <i>negative<\/i>, even though in the seemingly-analogous <code>MVN<\/code> instruction, the <code>N<\/code> stands for <i>not<\/i>.<\/p>\n<p>But that&#8217;s not the most misleading part of the <code>CMN<\/code> instruction.<\/p>\n<p>The big lie about the <i>compare negative<\/i> instruction is that <i>it doesn&#8217;t even compare the negative<\/i>.<\/p>\n<p>You had one job!<\/p>\n<p>The <i>compare negative<\/i> instruction is defined in terms of addition, rather than subtraction of the negative. Mathematically, the operations are identical: Subtracting a negative is the same as adding the positive.<\/p>\n<p>But computers aren&#8217;t operating on mathematical integers.<\/p>\n<p>Let&#8217;s look more closely at the difference between subtraction of the negative and addition of the positive. Recall that subtraction in a true-carry system is rewritten as addition, using the identity <code>-x = ~x + 1<\/code>. Therefore, <code>a - b<\/code> becomes <code>a + ~b + 1<\/code>. And the carry for this operation is the combined carry from <i>both<\/i> additions.<\/p>\n<p>On the other hand, the <code>CMN<\/code> instruction is implemented as a straight addition, not a subtraction of the negative.<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse;\" border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td>Expression<\/td>\n<td>Evaluated as<\/td>\n<\/tr>\n<tr>\n<td><code>a - (-b)<\/code><\/td>\n<td>let <code>c = ~b + 1<\/code><br \/>\nresult <code>= a + ~c + 1<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>a + b<\/code><\/td>\n<td>result <code>= a + b<\/code><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>One difference between the two is that in the &#8220;subtract the negative&#8221; version, the carry that occurs in the calculation of <code>~c + 1<\/code> contributes to the final carry, whereas that extra carry disappears in the &#8220;add the positive&#8221; version.<\/p>\n<p>When would <code>~c + 1<\/code> generate a carry?<\/p>\n<p>Answer: When <code>c<\/code> is zero, because we have <code>~c + 1 = ~0 + 1 = 0xFFFFFFFF + 1<\/code>, and that sum generates a carry. And <code>c<\/code> is zero when <code>b<\/code> is zero.<\/p>\n<p>On the other hand, if <code>b<\/code> is zero, then <code>a + b<\/code> never generates a carry because you&#8217;re just adding zero, which does nothing.<\/p>\n<p>Conclusion: If the second parameter to <code>CMN<\/code> is zero, then <code>CMN<\/code> results in no carry, even though &#8220;subtracting the negative of zero&#8221; would have produced a carry.<\/p>\n<p>In other words, these two sequences do not generate the same flags:<\/p>\n<pre>    ; compare r0 against negative r1 using single instruction\r\n    cmn     r0, r1          ; set flags for (r0 + r1)\r\n\r\n    ; compare r0 against negative r1 using two instructions\r\n    rsb     r12, r1, #0     ; r12 = negative r1\r\n    cmp     r0, r12         ; set flags for (r0 - r12)\r\n<\/pre>\n<p>In the case where <var>r1<\/var> is zero, the first version clears carry, but the second version sets carry. This means that if you follow the <code>CMN<\/code> with a conditional branch that consumes carry, you will get the wrong answer if the second parameter happens to be zero.<\/p>\n<p>We haven&#8217;t learned about ARM conditionals yet, but when we do, you&#8217;ll discover that it is the unsigned relative comparison conditionals\u00b9 that are based on the carry flag. Therefore, don&#8217;t use the <code>CMN<\/code> instruction to make unsigned relative comparisons against values which might be zero, because the carry flag may be set incorrectly.<\/p>\n<p>Fortunately, this problem is relatively easy to avoid:<\/p>\n<p>First rule: Don&#8217;t use<\/p>\n<pre>    cmn     Rd, #0\r\n<\/pre>\n<p>Don&#8217;t hard-code zero as the second parameter because the carry won&#8217;t be set properly.\u00b2 Just write it as the positive comparison:<\/p>\n<pre>    cmp     Rd, #0\r\n<\/pre>\n<p>This is even easier to write, and it doesn&#8217;t have the carry flag problem.<\/p>\n<p>Second rule: If you use a register or shifted register as the second parameter to <code>CMN<\/code>, don&#8217;t follow it with a condition that relies on the carry flag. In practice, this means that you should use signed conditions to test the result rather than unsigned conditions. (We haven&#8217;t learned about conditions yet.)<\/p>\n<p>Fortunately, this second rule is not that much of a problem, because the fact that you are &#8220;comparing against the negative&#8221; strongly implies that you are interpreting the comparison as between two signed integers, so you are unlikely to follow up with an unsigned relative comparison conditional.<\/p>\n<p>Okay, so that takes care of carry. The other troublesome bit is the overflow bit, which is just the carry from bit 30 into 31.<\/p>\n<p>What are the cases in which a carry from bit 30 to bit 31 would be lost? We already identified zero as one of those cases. The other case is where the value is <code>0x80000000<\/code>.<\/p>\n<p>Ah, the curse of the most negative integer.<\/p>\n<p>Ignoring the overflow from bit 30 to bit 31 means that the negative of <code>0x80000000<\/code> is treated as the positive number <code>+0x80000000<\/code>. Since every two&#8217;s complement 32-bit integer is less than <code>+0x80000000<\/code> (viewed as a large positive number), the result of the comparison is pretty much foregone. It will always say &#8220;less than&#8221;.<\/p>\n<p>In a way, though, the curse of the most negative integer isn&#8217;t so much of a problem here. After all, you did ask to compare against the negative of the most negative integer, and that&#8217;s a positive number that&#8217;s so positive it can&#8217;t even be represented!<\/p>\n<p>Wow, what a complicated, messed-up instruction <code>CMN<\/code> turned out to be.<\/p>\n<p>Next time, we&#8217;ll return to our exploration of the ARM Thumb-2 instruction set by looking at bitwise operations.<\/p>\n<p>\u00b9 The unsigned relative comparison conditionals are &#8220;unsigned less than&#8221;, &#8220;unsigned less than or equal&#8221;, &#8220;unsigned greater than&#8221;, and &#8220;unsigned greater than or equal&#8221;.<\/p>\n<p>\u00b2 Note that everything is fine if the second argument is not zero.<\/p>\n<pre>    ; compare against 0xFFFFFFFE.\r\n    ; this works properly even for unsigned comparison.\r\n    cmn     r1, #2\r\n<\/pre>\n<p>The problematic case for unsigned comparisons occurs only when the second argument is zero.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Don&#8217;t let the name fool you.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[2],"class_list":["post-105288","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-history"],"acf":[],"blog_post_summary":"<p>Don&#8217;t let the name fool you.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/105288","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=105288"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/105288\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=105288"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=105288"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=105288"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}