This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
[Bug target/58735] New: X86_64 sign extend on unsigned values
- From: "steffen-schmidt at siemens dot com" <gcc-bugzilla at gcc dot gnu dot org>
- To: gcc-bugs at gcc dot gnu dot org
- Date: Tue, 15 Oct 2013 09:33:19 +0000
- Subject: [Bug target/58735] New: X86_64 sign extend on unsigned values
- Auto-submitted: auto-generated
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