Reputation: 31
Consider the following C function prototype, where num_t
is a data type declared using typedef:
void store_prod(num_t *dest, unsigned x, num_t y) {
*dest = x*y;
}
gcc generates the following assembly code implementing the body of the computation:
What data type is num_t
?
The correct answer is that num_t
is unsigned long long
but I really don't understand why, any help will be greatly appreciated!!
# dest at %ebp +8, x at %ebp +12, y at %ebp +16
movl 12(%ebp), %eax
movl 20(%ebp), %ecx
imull %eax, %ecx
mull 16(%ebp)
leal (%ecx,%edx), %edx
movl 8(%ebp), %ecx
movl %eax, (%ecx)
movl %edx, 4(%ecx)
Upvotes: 2
Views: 261
Reputation: 364997
We can tell from the use of (%ebp)
addressing modes that this is 32-bit code, not x86-64.
In 32-bit mode, unsigned long long
is the only 64-bit unsigned integer type, in any of the common ABIs. (e.g. the i386 System V ABI, used on Linux). long
is 32-bit.
We can tell that num_t
is a 64-bit integer type because it's stored in two 32-bit halves from the result of integer multiply and addition.
We can tell that it's an unsigned
integer type because gcc used mul
instead of imul
between the x
and the low half of y
. (2-operand imul %eax, %ecx
to multiply x
with the upper half of y
is the same binary operation for signed or unsigned: only full-multiply (N x N => 2N bits) cares about signedness.)
IDK why gcc would use leal (%ecx,%edx), %edx
instead of add %ecx, %edx
. Maybe you compiled with -mtune=atom
or something? Preserving flags isn't necessary.
Anyway, it's an ordinary 64 x 32 => 64 bit extended-precision multiplication.
This is C, not C++, so a class wrapping a 64-bit integer with an overloaded *
operator can be ruled out, too.
We can rule out FP types because that would have used an FP multiply.
Upvotes: 4