{"id":99455,"date":"2018-08-09T07:00:00","date_gmt":"2018-08-09T21:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/?p=99455"},"modified":"2019-03-13T00:38:12","modified_gmt":"2019-03-13T07:38:12","slug":"20180809-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20180809-00\/?p=99455\/","title":{"rendered":"The PowerPC 600 series, part 4: Bitwise operations and constants"},"content":{"rendered":"<p>The PowerPC 600 series includes the following bitwise logical operations: <\/p>\n<pre>\n    and     rd, ra, rb      ; rd =   ra &amp;  rb\n    or      rd, ra, rb      ; rd =   ra |  rb\n    xor     rd, ra, rb      ; rd =   ra ^  rb\n    nand    rd, ra, rb      ; rd = ~(ra &amp;  rb)\n    nor     rd, ra, rb      ; rd = ~(ra |  rb)\n    eqv     rd, ra, rb      ; rd = ~(ra ^  rb)\n    andc    rd, ra, rb      ; rd =   ra &amp; ~rb \"and complement\"\n    orc     rd, ra, rb      ; rd =   ra | ~rb \"or complement\"\n    ; also \".\" versions\n<\/pre>\n<p>Each of these instructions also comes with a dot variant that updates <var>cr0<\/var> based on the result. <\/p>\n<p>There are also versions that take immediates or sometimes shifted immediates, and sometimes they update flags, and sometimes they don&#8217;t. There isn&#8217;t much orthogonality here. It&#8217;s all case-by-case. <\/p>\n<pre>\n    andi.   rd, ra, imm16   ; rd =   ra &amp;  (uint16_t)imm16, update cr0\n    andis.  rd, ra, imm16   ; rd =   ra &amp; ((uint16_t)imm16 &lt;&lt; 16), update cr0\n    ori     rd, ra, imm16   ; rd =   ra |  (uint16_t)imm16\n    oris    rd, ra, imm16   ; rd =   ra | ((uint16_t)imm16 &lt;&lt; 16)\n    xori    rd, ra, imm16   ; rd =   ra ^  (uint16_t)imm16\n    xoris   rd, ra, imm16   ; rd =   ra ^ ((uint16_t)imm16 &lt;&lt; 16)\n<\/pre>\n<p>Immediates are allowed only on three of the bitwise operations, and the <code>and<\/code> version always updates flags, whereas the <code>or<\/code> and <code>xor<\/code> versions never update flags. <\/p>\n<p>For some reason, sign extension is placed in the logical operations group. <\/p>\n<pre>\n    extsb   rd, ra          ; rd = (int8_t)ra\n    extsb.  rd, ra          ; rd = (int8_t)ra, update cr0\n    extsh   rd, ra          ; rd = (int16_t)ra\n    extsh.  rd, ra          ; rd = (int16_t)ra, update cr0\n<\/pre>\n<p>We now have enough instructions to load constants. <\/p>\n<p>If the constant is in the range <code>0xFFFF8000<\/code> to <code>0x00007FFF<\/code>, it can be loaded in one instruction:<\/p>\n<pre>\n    ; load immediate: rd = (int16_t)imm16\n    addi    rd, 0, imm16     ; li   rd, imm16\n<\/pre>\n<p>It can also be done in one instruction if the constant is an exact multiple of 65536. <\/p>\n<pre>\n    ; load immediate shifted: rd = imm16 &lt;&lt; 16\n    addis   rd, 0, imm16     ; lis  rd, imm16\n<\/pre>\n<p>These take advantage of the fact that the <code>addi<\/code> and <code>addis<\/code> instructions treat <var>r0<\/var> as if it were zero. They are the only non-memory instructions that have this special behavior with respect to <var>r0<\/var>. <\/p>\n<p>If the constant you want to load doesn&#8217;t fall into either of the two categories above, then you&#8217;ll have to load it in two steps: <\/p>\n<pre>\n    addis   rd, 0, imm16a    ; rd =  imm16a &lt;&lt; 16\n    ori     rd, rd, imm16b   ; rd = (imm16a &lt;&lt; 16) | (uint16_t)imm16b\n<\/pre>\n<p>This sequence takes advantage of the fact that the <code>ori<\/code> instruction treats its 16-bit immediate as an unsigned value. That way, we don&#8217;t have to play funny games with the most significant 16 bits if the least-significant 16 bits happen to form a negative integer when interpreted as a signed 16-bit value. <\/p>\n<p>While I&#8217;m here I may as well mention a third synthetic instruction based on <code>addi<\/code>: <\/p>\n<pre>\n    ; load address: rd = effective address of imm16(ra)\n    addi    rd, ra, imm16    ; la   rd, imm16(ra)\n<\/pre>\n<p>A commonly-used synthetic instruction is &#8220;move register&#8221;: <\/p>\n<pre>\n    or      rd, ra, ra       ; mr  rd, ra\n    or.     rd, ra, ra       ; mr. rd, ra\n<\/pre>\n<p>Moving a register to itself is functionally a nop, but the processor overloads it  to signal information about priority. <\/p>\n<pre>\n    or      r1, r1, r1       ; low priority\n    or      r6, r6, r6       ; medium-low priority\n    or      r2, r2, r2       ; normal priority\n<\/pre>\n<p>A program can voluntarily set itself to low priority if it is waiting for a spin lock. There are other priority levels which are available only to kernel mode and are ignored in user mode. <\/p>\n<p>Finally, everybody&#8217;s favorite instruction: <\/p>\n<pre>\n    ori     r0, r0, 0        ; nop\n<\/pre>\n<p>This is the official <code>nop<\/code> instruction recognized by the processor. There are other instructions that have no visible effect, but they might not be optimized efficiently. For example, <code>rlwinm ra, ra, 0, 0, 31<\/code> has no visible effect, but it will probably introduce a register dependency. And as we saw above, sometimes instructions with no visible effect become overloaded as signals to the processor, so your best bet is to avoid them. <\/p>\n<p>Wait, you don&#8217;t know what the <code>rlwinm<\/code> instruction does? We&#8217;ll dig into that <a HREF=\"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/20180810-00\/?p=99465\">next time<\/a>, when we enter the crazy world of rotating and shifting, and you&#8217;ll be formally introduced to the <code>rlwinm<\/code> instruction, the Swiss army knife instruction of the PowerPC instruction set. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>Twiddling around.<\/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-99455","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-history"],"acf":[],"blog_post_summary":"<p>Twiddling around.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/99455","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=99455"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/99455\/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=99455"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=99455"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=99455"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}