clang bug? Miscompilation of array of unsigned long long

Hi all,

I was toying around with the compiler-rt library and looking into why the udivmoddi4_test fails on FreeBSD and on MinGW when compiled with clang.

I narrowed it down to the initalization of the test array:

-- arrTest.c
#include <stdio.h>

unsigned long long globalArray[4] =
{0x078644FA00000000uLL, 0xFFFFFFFD00000000uLL, 0x0000000000000000uLL, 0x078644FA00000000uLL};

int main()
{
     unsigned long long t1 = 0xFFFFFFFD00000000uLL;
     unsigned long long t2 = 0xFFFFFFFFFFFFFFFFuLL;
     unsigned long long localArray[4] =
     {0xEFFFFFFD00000000uLL, 0xFFFFFFFD00000000uLL, 18446744060824649728uLL, 0xFFFFFFFFFFFFFFFFuLL};

     printf("0x%016llX, %016llu\n", t1, t1);
     printf("0x%016llX, %016llu\n", t2, t2);
     printf("globalArray: 0x%016llX, 0x%016llX, 0x%016llX, 0x%016llX\n",
             globalArray[0], globalArray[1], globalArray[2], globalArray[3]);
     printf("localArray: 0x%016llX, 0x%016llX, %16llu, 0x%016llX\n",
             localArray[0], localArray[1], localArray[2], localArray[3]);

     return 0;
}
--- clang -o arrTest arrTest.c

./arrTest
0xFFFFFFFD00000000, 18446744060824649728
0xFFFFFFFFFFFFFFFF, 18446744073709551615
globalArray: 0x078644FA00000000, 0x0000FFFD00000000, 0x0000000000000000, 0x078644FA00000000
localArray: 0xEFFFFFFD00000000, 0x0000FFFD00000000, 281462091808768, 0xFFFFFFFFFFFFFFFF

No idea, and I'm not able to reproduce it on my platform (Darwin). Could you give me the output of clang -v arrTest.c
  and clang -### arrTest.c , so I can get all of the version/triple information?

  - Doug

Hi Doug,

Thanks for your reply. Answers below.

Regards, Ed.

No idea, and I'm not able to reproduce it on my platform (Darwin). Could you give me the output of clang -v arrTest.c
   and clang -### arrTest.c , so I can get all of the version/triple information?

  - Doug

[emeewis@jazzed]~>clang -v arrTest.c
clang version 2.8 (trunk 109367)
Target: i386-unknown-freebsd8.0
Thread model: posix
  "/usr/local/bin/clang" -cc1 -triple i386-unknown-freebsd8.0 -S -disable-free -main-file-name arrTest.c -mrelocation-model static -mdisable-fp-elim -mconstructor-aliases -target-cpu pentium4 -v -resource-dir /usr/local/lib/clang/2.8 -ferror-limit 19 -fmessage-length 80 -fgnu-runtime -fdiagnostics-show-option -fcolor-diagnostics -o /home/emeewis/tmp/cc-z0moJd.s -x c arrTest.c
clang -cc1 version 2.8 based upon llvm 2.8svn hosted on i386-unknown-freebsd8.0
#include "..." search starts here:
#include <...> search starts here:
  /usr/local/include
  /usr/local/lib/clang/2.8/include
  /usr/include
End of search list.
  "/usr/local/bin/as" --32 -o /home/emeewis/tmp/cc-CNRQpM.o /home/emeewis/tmp/cc-z0moJd.s
  "/usr/local/bin/ld" --eh-frame-hdr -dynamic-linker /libexec/ld-elf.so.1 -m elf_i386_fbsd -o a.out /usr/lib/crt1.o /usr/lib/crti.o /usr/lib/crtbegin.o /home/emeewis/tmp/cc-CNRQpM.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/crtend.o /usr/lib/crtn.o

[emeewis@jazzed]~>clang -### arrTest.c
clang version 2.8 (trunk 109367)
Target: i386-unknown-freebsd8.0
Thread model: posix
  "/usr/local/bin/clang" "-cc1" "-triple" "i386-unknown-freebsd8.0" "-S" "-disable-free" "-main-file-name" "arrTest.c" "-mrelocation-model" "static" "-mdisable-fp-elim" "-mconstructor-aliases" "-target-cpu" "pentium4" "-resource-dir" "/usr/local/lib/clang/2.8" "-ferror-limit" "19" "-fmessage-length" "80" "-fgnu-runtime" "-fdiagnostics-show-option" "-fcolor-diagnostics" "-o" "/home/emeewis/tmp/cc-7YPMan.s" "-x" "c" "arrTest.c"
  "/usr/local/bin/as" "--32" "-o" "/home/emeewis/tmp/cc-8TH0sM.o" "/home/emeewis/tmp/cc-7YPMan.s"
  "/usr/local/bin/ld" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld-elf.so.1" "-m" "elf_i386_fbsd" "-o" "a.out" "/usr/lib/crt1.o" "/usr/lib/crti.o" "/usr/lib/crtbegin.o" "/home/emeewis/tmp/cc-8TH0sM.o" "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed" "-lc" "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed" "/usr/lib/crtend.o" "/usr/lib/crtn.o"

This still annoyed me, so today I dug a little deeper and tried to explore different compilation paths. Turns out the clang driver is likely at fault:

Simplified test case:

Are you 100% sure that it's the assembler call at fault? I don't see
how passing --32 to a 32-bit assembler could possibly break
anything...

-Eli

FWIW, I don't see the error on OS X. Did you check the assembly file, to
make sure it's not LLVM CodeGen's fault? Mine accesses both words of
globalArray.

This still annoyed me, so today I dug a little deeper and tried to
explore different compilation paths. Turns out the clang driver is
likely at fault:

Simplified test case:
---
#include <stdio.h>

unsigned long long globalArray = {0xFFFFFFFD00000000uLL};

int main()
{
unsigned long long t = 0xFFFFFFFD00000000uLL;

    printf\(&quot;%016llX, %016llu\\n&quot;, t, t\);
    printf\(&quot;%016llX, %016llu\\n&quot;,
            globalArray\[0\], globalArray\[0\]\);

return 0;

}
---

Compile to bitcode and execute:
> clang -emit-llvm -o arrTest.bc -c arrTest.c
> lli arrTest.bc
FFFFFFFD00000000, 18446744060824649728
FFFFFFFD00000000, 18446744060824649728

Huh? That correct...

Compile to assembly and execute:

>clang -o arrTest.asm -S arrTest.c
>clang -x assembler -o arrTest-clang arrTest.asm
>./arrTest-clang
FFFFFFFD00000000, 18446744060824649728
0000FFFD00000000, 0281462091808768

Incorrect. Let's try gcc...

> gcc -x assembler -o arrTest-gcc arrTest.asm
>./arrTest-gcc
FFFFFFFD00000000, 18446744060824649728
FFFFFFFD00000000, 18446744060824649728

Huh? That's correct again. How does the driver call subsequent steps?
> clang -x assembler -o arrTest-clang arrTest.asm -###
clang version 2.8 (trunk 109857)
Target: i386-unknown-freebsd8.0
Thread model: posix
"/usr/local/bin/as" "--32" "-o" "/home/emeewis/tmp/cc-hOA1tQ.o"
"arrTest.asm"
"/usr/local/bin/ld" "--eh-frame-hdr" "-dynamic-linker"
"/libexec/ld-elf.so.1" "-m" "elf_i386_fbsd" "-o" "arrTest-clang"
"/usr/lib/crt1.o" "/usr/lib/crti.o" "/usr/lib/crtbegin.o"
"/home/emeewis/tmp/cc-hOA1tQ.o" "-lgcc" "--as-needed" "-lgcc_s"
"--no-as-needed" "-lc" "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed"
"/usr/lib/crtend.o" "/usr/lib/crtn.o"

>gcc -x assembler -o arrTest-clang arrTest.asm -###
Using built-in specs.
Target: i386-undermydesk-freebsd
Configured with: FreeBSD/i386 system compiler
Thread model: posix
gcc version 4.2.1 20070719 [FreeBSD]
"/usr/bin/as" "-o" "/home/emeewis/tmp/cciyh8y1.o" "arrTest.asm"
"/usr/bin/ld" "--eh-frame-hdr" "-dynamic-linker"
"/libexec/ld-elf.so.1" "-o" "arrTest-clang" "/usr/lib/crt1.o"
"/usr/lib/crti.o" "/usr/lib/crtbegin.o" "-L/usr/lib" "-L/usr/lib"
"/home/emeewis/tmp/cciyh8y1.o" "-lgcc" "--as-needed" "-lgcc_s"
"--no-as-needed" "-lc" "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed"
"/usr/lib/crtend.o" "/usr/lib/crtn.o"

The difference is in the --32 option that clang adds, but gcc doesn't.

I'm guessing this is a platform detection problem. My initial
observation was that the compiler-rt tests fails both on FreeBSD-8.0

and

MinGW. Both are 32-bit environments running on 64 bit processors. (BSD
is custom build 32 bit running on a 64-bit Atom processor). I suppose
that's unusual, so I'm wondering whether it is worth filing a bug

report?

Hello Eli,

No, but this is what I see.

If you can help me narrow it down, I'd appreciate it.

-- Ed.

Could you attach the generated .o file with and without the --32 option?

-Eli

Hi Jordy,

Actually I did, but quickly give up. From what I remember gcc's and clang's were different. Both seemed to construct the local variable, but reference the array.

Anyway, It's too late now, I'll look into it tomorrow.

-- Ed.

Turns out the --32 doesn't matter.

However, my system has two versions of binutils and gcc uses the one delivered with FreeBSD-8.0 and clang uses the one installed through ports. clang somehow produces asm that the newer version of as doesn't like. gcc produces something that works correctly in both cases:

old as: /usr/bin/as --version
GNU assembler 2.15 [FreeBSD] 2004-05-23
Copyright 2002 Free Software Foundation, Inc.

new as: /usr/local/bin/as --version
GNU assembler (GNU Binutils) 2.20.1.20100303

clang direct:
clang -o arrTest-clang arrTest.c
./arrTest-clang
FFFFFFFD00000000, 18446744060824649728
0000FFFD00000000, 0281462091808768

gcc direct:
gcc -o arrTest-gcc arrTest.c
./arrTest-gcc
FFFFFFFD00000000, 18446744060824649728

LINKOPTS="--eh-frame-hdr -dynamic-linker /libexec/ld-elf.so.1 -m elf_i386_fbsd /usr/lib/crt1.o /usr/lib/crti.o /usr/lib/crtbegin.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/crtend.o /usr/lib/crtn.o"

clang asm with old as:
clang -o arrTest-clang.asm -S arrTest.c
/usr/bin/ld -o arrTest-clang-oldas arrTest-clang-oldas.o ${LINKOPTS}
./arrTest-clang-oldas
FFFFFFFD00000000, 18446744060824649728

clang asm with new as:
/usr/local/bin/as -o arrTest-clang-newas.o arrTest-clang.asm
/usr/local/bin/ld -o arrTest-clang-newas arrTest-clang-newas.o ${LINKOPTS}
./arrTest-clang-newas
FFFFFFFD00000000, 18446744060824649728
0000FFFD00000000, 0281462091808768

gcc asm with old as:
gcc -o arrTest-gcc.asm -S arrTest.c
/usr/bin/as -o arrTest-gcc-oldas.o arrTest-gcc.asm
/usr/bin/ld \-o arrTest-gcc-oldas arrTest-gcc-oldas.o ${LINKOPTS}
./arrTest-gcc-oldas
FFFFFFFD00000000, 18446744060824649728

gcc asm with new as:
gcc -o arrTest-gcc.asm -S arrTest.c
/usr/bin/as -o arrTest-gcc-newas.o arrTest-gcc.asm
/usr/bin/ld -o arrTest-gcc-newas arrTest-gcc-newas.o ${LINKOPTS}
./arrTest-gcc-newas
FFFFFFFD00000000, 18446744060824649728

Weird. Any ideas what's going on? I've attached test script, source file and both asm's.

Is there a way to force which assembler the clang driver is using?

-- Ed.

arrTest.c (267 Bytes)

arrTest-clang.asm (1.05 KB)

arrTest-gcc.asm (993 Bytes)

test.sh (1.72 KB)

Random guess: does the following patch help?

Index: lib/Target/X86/X86MCAsmInfo.cpp

This looks like a bug in GNU as 2.20.1, at least on FreeBSD. If I
assemble this simple fragment of the assembly produced by clang:

  .file "quadtest.s"
  .type globalArray,@object
  .data
  .globl globalArray
  .align 16
globalArray:
  .quad 542196645677236224
  .quad -12884901888
  .quad 0
  .quad 542196645677236224
  .size globalArray, 32

with as 2.20.1, the resulting .o file looks like this:

Contents of section .data:
0000 00000000 fa448607 00000000 fdff0000 .....D..........
0010 00000000 00000000 00000000 fa448607 .............D..

You can clearly see the faulty 64-bit constant at offset 0x8. If you
assemble the same file with as 2.15 (the FreeBSD system as), you get an
.o file that looks like this:

Contents of section .data:
0000 00000000 fa448607 00000000 fdffffff .....D..........
0010 00000000 00000000 00000000 fa448607 .............D..

and there the constant is fine.

I am not sure if this is a binutils bug on FreeBSD, or in general. Can
someone please try the above assembly fragment on e.g. Linux or Mac OS?

The reason that all this does not go wrong with gcc, is that it does not
produce ".quad" statements in the assembly; the globalArray declaration
is done as follows, in 32-bit chunks:

globalArray:
  .long 0
  .long 126239994
  .long 0
  .long -3
  .long 0
  .long 0
  .long 0
  .long 126239994

Eli - (Not so) Randomly guessed right!
Dimitry - Nail on the head - binutils on FreeBSD (and OpenBSD) is at fault.

Here's the output for the various cases:
clang direct:
FFFFFFFD00000000, 18446744060824649728
0000FFFD00000000, 0281462091808768

Eli's clang direct:
FFFFFFFD00000000, 18446744060824649728

clang asm with new as:
FFFFFFFD00000000, 18446744060824649728
0000FFFD00000000, 0281462091808768

Eli's clang asm - arrTest-clang-newas-eli
FFFFFFFD00000000, 18446744060824649728

The compiler-rt tests also pass with 100%.

So, obviously I need to file a binutils bug (couldn't find one), but how do we handle the clang case.Working around bugs in external programs doesn't seem the way to go. Any ideas?

I guess we could add Triple::FreeBSD to the test, if it is available.

-- Ed

Hi all,

Bugs filed:

http://sourceware.org/bugzilla/show_bug.cgi?id=11867
http://llvm.org/bugs/show_bug.cgi?id=7784

Many thanks to Eli and Dimitry.

-- Ed.

PS. More bugs is better, yes?

...

I hand-compiled binutils CVS HEAD checkouts on Linux and FreeBSD, and
these also gave the same problematic results. It's simply a binutils
bug.

Hey Dimitry,

Thanks very much for your effort. I've filed a bug against it. Let's see what happens.

I am impressed with yours and Eli's support, with your help I've learned a lot digging into this.

-- Ed.

FYI,

binutils/gas .quad bug has been fixed:

http://sourceware.org/bugzilla/show_bug.cgi?id=11867

-- Ed.