Search code examples
assemblybit-manipulationx86-64instructionsinstruction-set

why use 32-bit register when the data type is 64-bit?


I was reading a textbook that has an exercise that generates assembly code based on C code:

C code:

long arith(long x, long y, long z)
{
   long t1 = x ^ y;
   long t2 = z * 48;
   long t3 = t1 & 0x0F0F0F0F;
   long t4 = t2 - t3;
   return t4;
}

Assembly code:

//x in %rdi, y in %rsi, z in %rdx
arith:
   xorq %rsi, %rdi               //t1 = x ^ y
   leaq (%rdx,%rdx,2), %rax      //3*z
   salq $4, %rax                 //t2 = 16 * (3*z) = 48*z
   andl $252645135, %edi         //t3 = t1 & 0x0F0F0F0F
   subq %rdi, %rax               //Return t2 - t3
   ret

I'm confused with this assembly code:

andl $252645135, %edi         //t3 = t1 & 0x0F0F0F0F

why we don't use:

andq $252645135, %rdi

The probmen is, let's say all bits of t1 is 1, so for original C code long t3 = t1 & 0x0F0F0F0F;, the upper 32 bits of t3 will be 0s. But if we use andl instruction, and only operates on %edi, the upper 32 bits of %rdi will still be 1s,so this really change the value of t4 in long t4 = t2 - t3; where t3's upper 32 bits are all 1s but they are supposed to be 0s?


Solution

  • The answer lies in Section 3.4.1.1 of the Intel 64 and IA-32 Architectures Software Developer’s Manual Volume 1 (Basic Architecture) which states:

    When in 64-bit mode, operand size determines the number of valid bits in the destination general-purpose register:

    • 64-bit operands generate a 64-bit result in the destination general-purpose register.
    • 32-bit operands generate a 32-bit result, zero-extended to a 64-bit result in the destination general-purpose register.
    • 8-bit and 16-bit operands generate an 8-bit or 16-bit result. The upper 56 bits or 48 bits (respectively) of the destination general-purpose register are not modified by the operation. If the result of an 8-bit or 16-bit operation is intended for 64-bit address calculation, explicitly sign-extend the register to the full 64-bits.

    See the second bullet.

    You can gain some insight as to why this is so by reading: Why do x86-64 instructions on 32-bit registers zero the upper part of the full 64-bit register?