This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Bug target/58735] New: X86_64 sign extend on unsigned values


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=58735

            Bug ID: 58735
           Summary: X86_64 sign extend on unsigned values
           Product: gcc
           Version: 4.8.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: target
          Assignee: unassigned at gcc dot gnu.org
          Reporter: steffen-schmidt at siemens dot com

Created attachment 31009
  --> http://gcc.gnu.org/bugzilla/attachment.cgi?id=31009&action=edit
Example functions

The target is x86_64-pc-elf or x86_64-pc-linux-gnu (for both -m64 or -mx32)

This example function defines some unsigned global variables of different size.
During the bit shift operation the compiler needs to extend the small size
unsigned values of 8bit and 32bit into a 64bit unsiged.

When specifying an explicit cast to 64bit unsigned, the resulting code is
correct (see shift_and_cast()). Without the explicit cast, however, the
compiler sign-extends from 32bit to 64bit, which generates the wrong result
(see shift()) .

#if (LONG_BIT == 64)
  typedef unsigned long int     uint64_t;
#else
  typedef unsigned long long    uint64_t;
#endif
typedef unsigned int  uint32_t;
typedef unsigned char uint8_t;

volatile uint64_t sres;
volatile uint8_t  sval;
volatile uint32_t scnt;

void shift()
{
  sres = 0;
  sval = 0xaa;
  scnt = 24;
  sres |= sval << scnt;
}

void shift_and_cast()
{
  sres = 0;
  sval = 0xaa;
  scnt = 24;
  sres |= (uint64_t)sval << scnt;
}

Here is the assembly:
shift:
.LFB0:
    .cfi_startproc
    pushq    %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    movq    $0, sres(%rip)
    movb    $-86, sval(%rip)
    movl    $24, scnt(%rip)
    movzbl    sval(%rip), %eax
    movzbl    %al, %edx
    movl    scnt(%rip), %eax
    movl    %eax, %ecx
    sall    %cl, %edx
    movl    %edx, %eax
# Here the sign extension happens:
    movslq    %eax, %rdx
    movq    sres(%rip), %rax
    orq    %rdx, %rax
    movq    %rax, sres(%rip)
    popq    %rbp
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc

shift_and_cast:
.LFB1:
    .cfi_startproc
    pushq    %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    movq    $0, sres(%rip)
    movb    $-86, sval(%rip)
    movl    $24, scnt(%rip)
    movzbl    sval(%rip), %eax
    movzbl    %al, %edx
    movl    scnt(%rip), %eax
    movl    %eax, %ecx
    salq    %cl, %rdx
# no sign extension:
    movq    sres(%rip), %rax
    orq    %rdx, %rax
    movq    %rax, sres(%rip)
    popq    %rbp
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc

We're always handling unsigned variables, so it's not quite clear, why an
explicit cast should be necessary to produce the correct code.

Example was comiled with:
x86_64_gcc_pc_elf_4.8.1\bin\x86_64-pc-elf-gcc.exe -r -c -nostdlib test.c -o
test.o -save-temps -O0


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]