The stuff below applies to the CVS head revision as well as 3.4.*.
Maybe there is a bug w.r.t. sign promotion of the results of signed/unsigned
mixed multiplication from 32 to 64 bits. IMHO the result should be signed
(shouldn't it?).
I'm a little bit confused w.r.t. to signed/unsigned multiplication on x86_64:
Assume multiplying (signed <some integer type)-1 by (unsigned <same integer
type)20 and cast that value to a larger integer. With gcc-3.4.3 as well as the
CVS head revision I get the following:
1.
(signed long) = (signed int) = (signed short) = (signed char) x (unsigned char)
This yields proper (?) sign extension to every integer type. In hex notation:
if (signed long)a = (signed char)-1 * (unsigned char)20,
then a = 0xffff ffff ffff ffec
2.
(signed long) = (signed int) = (signed short) x (unsigned short)
Dito (with char replaced by short):
if a = -1 * 20, then a = 0xffff ffff ffff ffec
3.
(signed long) = (signed int) x (unsigned int)
Surprisingly the sign is not promoted in this case:
a = -1 * 20, then a = 0x0000 0000 ffff ffec
IMHO, this is a bug. Below is a short test program which tries to execute the
three scenarios. But maybe there is some thinko on my side.
The output from the test program below (on my host) is:
################################################
Char : 0xffffffffffffffec | 0xffffffec | 0xffec
Short: 0xffffffffffffffec | 0xffffffec
Int : 0x00000000ffffffec
################################################
Best regards
Claus
############################ snip ####################################
#include <stdio.h>
short char_mix(signed char sign, unsigned char val)
{
return sign * val;
}
int short_mix(signed short sign, unsigned short val)
{
return sign * val;
}
long int int_mix(int sign, unsigned int val)
{
return sign * val;
}
int main(int argc, const char *argv[])
{
short short_res;
int int_res;
long int long_int_res;
short_res = char_mix(-1, 20);
int_res = short_mix(-1, 20);
long_int_res = int_mix(-1, 20);
printf("Char : 0x%016lx | 0x%08x | 0x%04x\n",
(unsigned long)short_res, (unsigned int)short_res, (unsigned
short)short_res);
printf("Short: 0x%016lx | 0x%08x\n",
(unsigned long)int_res, (unsigned int)int_res);
printf("Int : 0x%016lx\n", (unsigned long)long_int_res);
}
############################ snap ####################################
--
Summary: signed/unsigned multiplication + sign extension broken
32->64 bit sign promotion?
Product: gcc
Version: 4.0.0
Status: UNCONFIRMED
Severity: critical
Priority: P2
Component: c
AssignedTo: unassigned at gcc dot gnu dot org
ReportedBy: ch at dot-heine dot de
CC: gcc-bugs at gcc dot gnu dot org
GCC build triplet: x86_64-unknown-linux-gnu
GCC host triplet: x86_64-unknown-linux-gnu
GCC target triplet: x86_64-unknown-linux-gnu
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=20238