{"id":96897,"date":"2017-08-29T07:00:00","date_gmt":"2017-08-29T21:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/?p=96897"},"modified":"2019-03-13T01:16:08","modified_gmt":"2019-03-13T08:16:08","slug":"20170829-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20170829-00\/?p=96897","title":{"rendered":"The Alpha AXP, part 16: What are the dire consequences of having 32-bit values in non-canonical form?"},"content":{"rendered":"<p>On the Alpha AXP, 32-bit values are typically represented in so-called canonical form. But what happens if you use a non-canonical representation? <\/p>\n<p>Well, it depends on what instruction consumes the non-canonical representation. <\/p>\n<p>If the consuming instruction is an explicit 32-bit instruction, such as <code>ADDL<\/code> or <code>STL<\/code>, then the upper 32 bits are ignored, and the operation proceeds with the lower 32 bits. In that case, the non-canonical representation causes no harm. For example, consider this calculation: <\/p>\n<pre>\n    ; Calculate Rc = Ra + Rb + 0x1234 (32-bit result)\n    LDA     Rc, 0x1234(zero)    ; Rc = 0x00000000`00001234\n    ADDL    Rc, Rb, Rc          ; Rc = Rb + 0x1234\n    ADDL    Rc, Ra, Rc          ; Rc = Ra + Rb + 0x1234\n<\/pre>\n<p>If we are willing to use a non-canonical form temporarily, we could simplify this to <\/p>\n<pre>\n    ; Calculate Rc = Ra + Rb + 0x1234 (32-bit result)\n    LDA     Rc, 0x1234(Rb)      ; Rc = Rb + 0x1234 (64-bit intermediate)\n    ADDL    Rc, Ra, Rc          ; Rc = Ra + Rb + 0x1234 (32-bit result)\n<\/pre>\n<p>The <code>LDA<\/code> will put <var>Rc<\/var> into non-canonical 32-bit form if <var>Rb<\/var> is in the range <code>0x7FFFEDCC<\/code> to <code>0x7FFFFFFF<\/code> because the <code>LDA<\/code> instruction is 64-bit only, and the result would be in the range <code>0x00000000`80000000<\/code> through <code>0x00000000`80001233<\/code>, which are non-canonical. But all is forgiven at the <code>ADDL<\/code> instruction, since it considers only the 32-bit portion of the  addends (ignoring the non-canonical part) and generates a 32-bit result in canonical form. <\/p>\n<p>On the other hand, if the instruction that consumes the non-canonical 32-bit value is a 64-bit instruction, then the non-canonical value will cause trouble. <\/p>\n<p>Consider this simple function: <\/p>\n<pre>\nvoid f(int x)\n{\n    if (x == 0) DoSomething();\n}\n<\/pre>\n<p>The Windows ABI for Alpha AXP requires that all 32-bit values be passed and returned in canonical form. You are welcome to use non-canonical values inside your function, but all communication with the outside world must use canonical form for 32-bit values. <\/p>\n<p>This function might assemble to something like this: <\/p>\n<pre>\n    BEQ     a0, DoSomething ; tail call optimization\n    RET     zero, (ra), 1   ; return without doing anything\n<\/pre>\n<p>The first instruction checks whether <var>x<\/var> is zero. If so, then it jumps directly to the <code>Do&shy;Something<\/code> function, leaving the return address unchanged, so that when <code>Do&shy;Something<\/code> returns, it returns to the caller of <code>f<\/code>. (This is a tail call optimization.) <\/p>\n<p>If the value is not zero, then it returns to the caller. <\/p>\n<p>There is no 32-bit version of the <code>BEQ<\/code> instruction; it always tests the full 64 bits. <\/p>\n<p>If the value of <var>x<\/var> were not canonical, then the branch instruction could suffer false negatives: Even though the lower 32 bits are zero, there may be nonzero bits set in the upper half. That cause the <code>BEQ<\/code> to report &#8220;sorry, not zero&#8221; even though the 32-bit part of <var>a0<\/var> was zero. <\/p>\n<p>There are a number of instructions which do not have a 32-bit version and which always operate on the full 64-bit register value. Another example: <\/p>\n<pre>\nvoid f(int x, int y)\n{\n    if (x &lt; y) DoSomething();\n}\n<\/pre>\n<p>This function might assemble to something like this: <\/p>\n<pre>\n    CMPLT   a0, a1, t0      ; t0 = 1 if a0 &lt; a1\n    BNE     t0, DoSomething ; tail call optimization\n    RET     zero, (ra), 1   ; return without doing anything\n<\/pre>\n<p>In this version, the compiler performs a signed less-than operation and branches based on the result. The <code>CMPLT<\/code> instruction always operates on the full 64-bit register value; there is no 32-bit version. Consequently, passing a non-canonical value can result in the debugger reporting strange things like &#8220;Well, even though you passed <var>x<\/var> = 1 and <var>y<\/var> = 2, the less-than comparison returned false because <var>x<\/var> was passed in the non-canonical form of <code>0xFFFFFFFF`00000001<\/code>. <\/p>\n<p>Using sign-extended values for canonical form for 32-bit values has the nice property that signed and unsigned comparisons of 32-bit values have the same results as signed and unsigned comparisons of their corresponding canonical forms. <\/p>\n<p>If zero-extension had been used for canonical form, then unsigned comparisons would be preserved, but signed comparisons would not agree: The 32-bit signed comparison of <code>0x00000000<\/code> with <code>0xFFFFFFFF<\/code> would report that the first value is larger (0 &gt; &minus;1) but the 64-bit signed comparison <code>0x00000000`00000000<\/code> with <code>0x00000000`FFFFFFFF<\/code> of the corresponding zero-extended values would report that the second value is larger (0 &lt; 4,294,967,295). <\/p>\n<p> I&#8217;m pretty sure this was not a coincidence. <\/p>\n<p><b>Bonus chatter<\/b>: Non-canonical values introduce another case where <a HREF=\"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/20040119-00\/?p=41003\">uninitialized variables can result in strange behavior<\/a>. Consider: <\/p>\n<pre>\nint f()\n{\n    int v;\n    ... a bunch of code that somehow forgot to set v ...\n    ... but in a complicated way that eluded code flow analysis ...\n    return (v &lt; 0) ? -1 : 0;\n}\n<\/pre>\n<p>This might get compiled to the following: <\/p>\n<pre>\n    ; compiler chooses t0 to represent v\n    ...\n    SRA     t0, #32, v0     ; v0 = 0xFFFFFFFF`FFFFFFFF if t0 was negative\n                            ; v0 = 0x00000000`00000000 if t0 was nonnegative\n    RET     zero, (ra), 1   ; return the result\n<\/pre>\n<p>If the code forgets to assign a value to <var>v<\/var>, then it will have the value left over from whatever code ran earlier. Suppose that leftover value happened to be the non-canonical value <code>0x12345678`12345678<\/code>. In that case, the result of the <code>SRA<\/code> would be <code>0x00000000`12345678<\/code>, and the function <code>f<\/code> ends up returning some value that seems to be impossible from reading the code: According to the code, the function always returns either <code>-1<\/code> or <code>0<\/code>, yet sometimes we crash because it returned the crazy value <code>0x12345678<\/code>! <\/p>\n","protected":false},"excerpt":{"rendered":"<p>It depends on what the next calculation is.<\/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":[25],"class_list":["post-96897","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>It depends on what the next calculation is.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/96897","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=96897"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/96897\/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=96897"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=96897"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=96897"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}