8

For a short homework assignment in CS Architecture, we were made to translate the following IA-32 assembly into C. I've translated it properly (as far as I know) but the code doesn't appear to do anything particularly useful. My professor typically gives us problems like this which end up doing something: our last assignment like this was a bit pop_count. Looking at the C code below, does this function do anything useful? Some algorithm maybe?

The code appears below (I've added comments to each ASM line).

// The following variables x, y, z are located at (%ebp) +8, +12, +16 respectively
// x, y, and z, are scanned from the terminal and passed into the function

   movl 12(%ebp), %edx                  // moves long y to register %edx
   subl 16(%ebp), %edx                  // subtracts longs: y = y - z
   movl %edx, %eax                      // moves long y to register %eax
   sall $31, %eax                       // left shift all bits in long y by 31 places 
   sarl $31, %eax                       // arithmetic right shift long y by 31 places
   imull 8(%ebp), %edx                  // multiply longs: unshifted y = y * x
   xorl %edx, %eax                      // XOR operation: shifted y = shifted y ^ unshifted y

// The returned value is stored in register %eax

The effective takeaway is we subtract z from y, then populate every bit with the least significant bit to form either zero or MAX_UINT. This is XOR'd with the product of (y - z) * x and returned.

My translation into C:

return (((y - z) << 31) >> 31) ^ ((y - z) * x);

// In more words:
    int f;
    y -= z;
    f = y << 31;                        // These two lines populate all bits with the lsb
    f = f >> 31;                        // Effectively, if y-z is odd: f is ~0; else f is 0
    y *= x;
    return y ^ f;

// Or, using people logic:
    y -= z;
    if (y % 2 == 0) return y * x;
    return -(y * x) - 1;

// If the y-z is odd, the result will be:    -1 * ((y - z) * x) - 1
// If the y-z is even, the result will be:              (y - z) * x

For clarification, this is not part of the HW assignment; I've completed the assignment by translating the code, but I'm interested in knowing why he gave us this code to begin with.

SeniorShizzle
  • 984
  • 1
  • 11
  • 27

1 Answers1

3

My guess is that your professor was trying to illustrate how you can use bit-shifting/masking operations to avoid branches. If you were to naively translate

y -= z;
if (y % 2 == 0) return y * x;
return -(y * x) - 1;

into machine code, you would use a branch instruction for the conditional. Branches can dramatically slow down your code, especially if they're inside a tight loop*. The assembly code and your preceding C code have the effect of using a conditional on whether or not y - z is even, but only using arithmetic instructions.

*If you're not already familiar with this fact, this SO answer has one of my favorite illustrations of it.

Community
  • 1
  • 1
Daniel Shapero
  • 1,869
  • 17
  • 30
  • That's an interesting point you've made. Indeed, my professor stated that it is partially to demonstrate the ability to perform logic without conditional branching. Thanks for the answer! – SeniorShizzle Mar 31 '15 at 01:47