LLVM Bugzilla is read-only and represents the historical archive of all LLVM issues filled before November 26, 2021. Use github to submit LLVM bugs

Bug 1144 - bad codegen of memmove
Summary: bad codegen of memmove
Status: RESOLVED FIXED
Alias: None
Product: libraries
Classification: Unclassified
Component: Backend: X86 (show other bugs)
Version: trunk
Hardware: PC Linux
: P normal
Assignee: Evan Cheng
URL:
Keywords: miscompilation
Depends on:
Blocks:
 
Reported: 2007-01-29 17:38 PST by Nick Lewycky
Modified: 2010-02-22 12:42 PST (History)
2 users (show)

See Also:
Fixed By Commit(s):


Attachments
testcase (6.34 KB, text/plain)
2007-01-29 17:38 PST, Nick Lewycky
Details
the half cleared by bugpoint (143.49 KB, text/plain)
2007-01-29 17:42 PST, Nick Lewycky
Details
bad assembly from llc (2.23 KB, text/plain)
2007-01-30 18:36 PST, Nick Lewycky
Details
good asm from gcc (1.72 KB, text/plain)
2007-01-30 18:36 PST, Nick Lewycky
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Nick Lewycky 2007-01-29 17:38:33 PST
bugpoint reduced this out of Shootout-C++/hash2. It works if I compile it with
the CBE, but fails if I compile it with the x86 backend.
Comment 1 Nick Lewycky 2007-01-29 17:38:57 PST
Created attachment 600 [details]
testcase
Comment 2 Nick Lewycky 2007-01-29 17:42:49 PST
Created attachment 601 [details]
the half cleared by bugpoint

Compile this to bugpoint.safe.bc.cbe.c.so.
Comment 3 Nick Lewycky 2007-01-29 17:43:59 PST
Reproduce with:
gcc ./bugpoint.safe.bc.cbe.c.so bugpoint.test.bc.c -o bugpoint.test.bc.exe -Wl,-R.
Comment 4 Anton Korobeynikov 2007-01-30 03:47:52 PST
Nick, I wasn't able to reproduce the bug: 

1. CBE-compiled version fails for me in the early and (calling ostream::operator<<).
2. If I compile both chunks separately with llc to .s and then compile and link
with gcc it crashes in the end (ostream)
3 If I link modules together and than compile to .s - it crashes in the early
beginning.
3. If I link modules together and compile to .s with llc --disable-fp-elim - it
crashes in the end...

Could you please:
1. Attach .s files
2. Tell, where it segfaults for you (just gdb + backtrace + disassembly)
3. How can I reproduce stuff from the "clean" hash2 (afaik, you're testing new
predsimplify?)
Comment 5 Nick Lewycky 2007-01-30 18:36:16 PST
Created attachment 603 [details]
bad assembly from llc
Comment 6 Nick Lewycky 2007-01-30 18:36:46 PST
Created attachment 604 [details]
good asm from gcc
Comment 7 Nick Lewycky 2007-01-30 18:37:34 PST
GDB proves uninformative, which is unsurprising as the input is asm files:

Program received signal SIGSEGV, Segmentation fault.
__gnu_cxx::hashtable<std::pair<char const* const, int>, char const*,
__gnu_cxx::hash<char const*>, std::_Select1st<std::pair<char const* const, int>
>, eqstr, std::allocator<int> >::_M_initialize_buckets () at bugpoint.test.bc.s:48
48              movl (%esi), %esi
Current language:  auto; currently asm
(gdb) bt
#0  __gnu_cxx::hashtable<std::pair<char const* const, int>, char const*,
__gnu_cxx::hash<char const*>, std::_Select1st<std::pair<char const* const, int>
>, eqstr, std::allocator<int> >::_M_initialize_buckets () at bugpoint.test.bc.s:48
Comment 8 Nick Lewycky 2007-01-30 18:46:51 PST
To reproduce:

$ cd projects/llvm-test/SingleSource/Benchmarks/Shootout-C++
$ make Output/hash2.linked.rbc
$ opt -idom -etforest -verify -lowersetjmp -funcresolve -raiseallocs
-simplifycfg -idom -domtree -domfrontier -mem2reg -globalopt -globaldce
-ipconstprop -deadargelim -instcombine -simplifycfg -basiccg -prune-eh -inline
-argpromotion -raise -tailduplicate -instcombine -simplifycfg -idom -domtree
-domfrontier -scalarrepl -instcombine -break-crit-edges -etforest -predsimplify
-tailcallelim -simplifycfg -reassociate -idom -etforest -loops -domset -domtree
-loopsimplify -domfrontier -licm -lcssa -loop-unswitch -instcombine
-scalar-evolution -indvars -loop-unroll -instcombine -idom -domset -load-vn
-etforest -domtree -gcse -sccp -instcombine -break-crit-edges -condprop -dse
-mergereturn -postidom -postdomtree -postdomfrontier -adce -simplifycfg
-simplify-libcalls -printusedtypes -deadtypeelim -constmerge -idom -etforest
-verify Output/hash2.linked.rbc -o hash2.bc
$ llc hash2.bc -o hash2.s
$ g++ hash2.s -o hash2.exe
$ ./hash2.exe
Segmentation fault

If you want to bugpoint the error, run this:
$ bugpoint hash2.bc -run-llc -append-exit-code -rel-tolerance 0.00000001
-Xlinker=-lm -Xlinker=-lstdc++  -input=/dev/null -timeout=500 --tool-args 
-enable-correct-eh-support --args --
Comment 9 Anton Korobeynikov 2007-01-31 04:39:39 PST
Well. The crash at my side is the same (mov (%esi), %esi). It seems, that
something wrong was on stack, since %esi doesn't contain "good" address. Will
investigate...
Comment 10 Anton Korobeynikov 2007-01-31 05:16:21 PST
Well. Seems to be something wrong with fp elimination.

If I extract failed function and compile it separately - everything is ok. Even
more, the assembler for extracted function is the same as the assembler of
functions "inside" big assembler.

So, the problem is somewhere outside of the crashed function... Looking
further... I've removed extracted function from "bad" assembler and diffed the
output. Diff was prety nice (- = "good", + = "bad"):
@@ -2959,6 +2959,7 @@
        subl %eax, %edi
        movl %edi, 8(%esp)
        call memmove
+       subl $12, %esp
        movl %edi, %eax
        sarl $31, %eax
        shrl $30, %eax
@@ -3021,7 +3022,6 @@
        subl %eax, %edi
        movl %edi, 8(%esp)
        call memmove
-       subl $12, %esp
        movl %edi, %eax
        sarl $31, %eax
        shrl $30, %eax
@@ -3053,6 +3053,7 @@
        subl %eax, %edi
        movl %edi, 8(%esp)
        call memmove
+       subl $12, %esp
        movl %edi, %eax
        sarl $31, %eax
        shrl $30, %eax

And so on. Actually files differ only on that "subl $12, %esp" lines. Cool.
Comment 11 Anton Korobeynikov 2007-01-31 05:23:56 PST
Afaik, there shouldn't be any stack-manipulation at all here. 
Comment 12 Anton Korobeynikov 2007-01-31 06:15:32 PST
And finally:

1. before FP elimination:
entry (0x8754fa0, LLVM BB @0x87569c8, ID#0):
        ADJCALLSTACKDOWN 12, %ESP<imp-def>, %ESP<imp-use>
        %EAX = MOV32rm <fi#-1>, 1, %NOREG, 0
        MOV32mr %ESP, 1, %NOREG, 4, %EAX
        %ECX = MOV32rm <fi#-2>, 1, %NOREG, 0
        %ECX = SUB32rr %ECX<kill>, %EAX<kill>
        %EAX = MOV32rr %ECX
        %EAX = SAR32ri %EAX<kill>, 31
        %EAX = SHR32ri %EAX<kill>, 30
        %ECX = ADD32rr %ECX<kill>, %EAX<kill>
        %EAX = MOV32rr %ECX
        %EAX = AND32ri8 %EAX<kill>, 4294967292
        MOV32mr %ESP, 1, %NOREG, 8, %EAX<kill>
        %ECX = SAR32ri %ECX<kill>, 2
        %ECX = NEG32r %ECX<kill>
        %ESI = LEA32r %NOREG, 4, %ECX<kill>, 0
        %ESI = ADD32rm %ESI<kill>, <fi#-3>, 1, %NOREG, 0
        MOV32mr %ESP, 1, %NOREG, 0, %ESI
        CALLpcrel32 <es:memmove>, %EAX<imp-def,dead>, %ECX<imp-def,dead>,
%EDX<imp-def,dead>, %FP0<imp-def,dead>, %FP1<imp-d$
        ADJCALLSTACKUP 12, 12, %ESP<imp-def>, %ESP<imp-use>
        %EAX = MOV32rr %ESI<kill>
        RET %EAX<imp-use,kill>, %EAX<imp-use>

Note, there are 2 adjcall* calls for memmove call

2. After FP elimination we have:

entry (0x8754fa0, LLVM BB @0x87569c8, ID#0):
        %ESP = SUB32ri8 %ESP, 20
        MOV32mr %ESP, 1, %NOREG, 16, %ESI
        %EAX = MOV32rm %ESP, 1, %NOREG, 24
        MOV32mr %ESP, 1, %NOREG, 4, %EAX
        %ECX = MOV32rm %ESP, 1, %NOREG, 28
        %ECX = SUB32rr %ECX<kill>, %EAX<kill>
        %EAX = MOV32rr %ECX
        %EAX = SAR32ri %EAX<kill>, 31
        %EAX = SHR32ri %EAX<kill>, 30
        %ECX = ADD32rr %ECX<kill>, %EAX<kill>
        %EAX = MOV32rr %ECX
        %EAX = AND32ri8 %EAX<kill>, 4294967292
        MOV32mr %ESP, 1, %NOREG, 8, %EAX<kill>
        %ECX = SAR32ri %ECX<kill>, 2
        %ECX = NEG32r %ECX<kill>
        %ESI = LEA32r %NOREG, 4, %ECX<kill>, 0
        %ESI = ADD32rm %ESI<kill>, %ESP, 1, %NOREG, 32
        MOV32mr %ESP, 1, %NOREG, 0, %ESI
        CALLpcrel32 <es:memmove>, %EAX<imp-def,dead>, %ECX<imp-def,dead>,
%EDX<imp-def,dead>, %FP0<imp-def,dead>, %FP1<imp-d$
        %ESP = SUB32ri8 %ESP, 12
        %EAX = MOV32rr %ESI<kill>
        %ESI = MOV32rm %ESP, 1, %NOREG, 16
        %ESP = ADD32ri8 %ESP, 20
        RET %EAX<imp-use,kill>, %EAX<imp-use>

Note, we've dropped adjcallstackdown (seems to be ok), but turned adjcallstackup
to sub esp, 12. Is it correct?
Comment 13 Nick Lewycky 2007-01-31 20:33:21 PST
If I follow Anton's instructions and remove any %esp manipulation instruction
that follows a call memmove, the program runs fine. That's on the whole program,
not the bugpoint halves.
Comment 14 Anton Korobeynikov 2007-02-01 02:44:40 PST
This was the result of "sret" patch. Codegen really thought, that memmove is
struct return function :) This was due to uninitialized stuff inside
LegalizedDAG.cpp. Fortunately, the only affected part is memmove call inside x86
backend (since memcpy & memset are custom lowered and X86ISelLowering.cpp was ok).

Sorry for the breakage.

Fixed with these patches:

http://lists.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon-20070129/043666.html
http://lists.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon-20070129/043667.html
http://lists.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon-20070129/043668.html