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

Reply via email to