Monthly Archives: May 2011

After Updating: Finding Regressions

In my last post, I described how I sync up the ELLCC project with the LLVM project’s compiler, back-end, and run-time library. Today I’ll build the merged changes and look for problems that may have occurred as the result of the merge.

The first step is to build the newly merged files. I build the my modified LLVM stuff in a separate build directory called llvm-build. Full instructions for installing and building ELLCC are on the installation page. My regression build looks like this:

[~/ellcc] main% cd llvm-build/
[~/ellcc/llvm-build] main% make

I watch for compilation errors (of course!) as well as any warnings that may occur. After a successful build, install the new binaries:

[~/ellcc/llvm-build] main% make install

Now it’s time to see if anything got broken. The first step I use is to rebuild the ELLCC C run-time library, libecc. This is a good test because libecc uses a lot of language features and is compiled for all the targets:

[~/ellcc/llvm-build] main% cd ~/ellcc/libecc/obj/
[~/ellcc/libecc/obj] main% ls
arm/ i386/ Makefile microblaze/ mips/ nios2/ ppc/ ppc64/ sparc/ x86_64/
[~/ellcc/libecc/obj] main% make clean
[~/ellcc/libecc/obj] main% make

In this case, after updating to LLVM revision 132253, I got the following code generation error:

ecc: /home/rich/ellcc/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp:229: void llvm::AsmPrinter::EmitCFIFrameMove(const llvm::MachineMove&) const: Assertion `!Dst.isReg() && "Machine move not supported yet."' failed.

Time for a little investigation….

It turns out that in llvm/lib/Target/Mips/MipsMCAsmInfo.cpp the line

SupportsDebugInformation = true;

was added. Apparently this was a little premature. The libecc libraries are compiled with -g to enable debug information and the first file compiled chokes the code generator. I’ll comment that line out for now and see how much further I can get.

Now I’ve found something interesting. I get an assertion failure when libecc/src/c/stdlib/merge.c is compiled for Mips:

ecc: /home/rich/ellcc/llvm/lib/CodeGen/SplitKit.cpp:180: bool llvm::SplitAnalysis::calcLiveBlockInfo(): Assertion `BI.FirstUse >= Start' failed.
0 ecc 0x0000000001a6db1f
1 ecc 0x0000000001a6e65a
2 libpthread.so.0 0x00000037bea0eeb0
3 libc.so.6 0x00000037bde330c5 gsignal + 53
4 libc.so.6 0x00000037bde34a76 abort + 390
5 libc.so.6 0x00000037bde2b905 __assert_fail + 245
6 ecc 0x00000000015d7767
7 ecc 0x00000000015d7b10 llvm::SplitAnalysis::analyzeUses() + 512
...

Time to pull out LLVM’s trusty bugpoint. bugpoint is a tool that reduces a compilation failure to a smaller test case than can be attached to a bug report. The process is described here. In this case, I can guess this isn’t a front end problem because this code has been compiled for arm, i386, and microblaze targets prior to the mips build. I can also probably eliminate optimizer problems and assume it is a code generation problem.

Following the instructions here, I’ll make a reduced test case. The failing command line is:

../../../../../bin/mips-linux-ecc -c -g -Werror -MD -MP -O1 -fno-builtin -I../../../../src/c/include -I../../../../src/c/locale ../../../../src/c/stdlib/merge.c

so I’ll go into the appropriate build directory and run a slightly modified command (I added -emit-llvm -o merge.bc to get a bitcode intermediate file, I also removed the -g to reduce the size of the .bc file):

[~/ellcc] main% cd libecc/obj/mips/linux/c
[~/ellcc/libecc/obj/mips/linux/c] main% ../../../../../bin/mips-linux-ecc -c -Werror -MD -MP -O1 -fno-builtin -I../../../../src/c/include -I../../../../src/c/locale ../../../../src/c/stdlib/merge.c -emit-llvm -o merge.bc

First, I’ll try to generate code from the .bc file to verify that a code generation problem is occurring:

[~/ellcc/libecc/obj/mips/linux/c] main% ~/ellcc/bin/llc merge.bc
llc: /home/rich/ellcc/llvm/lib/CodeGen/SplitKit.cpp:180: bool llvm::SplitAnalysis::calcLiveBlockInfo(): Assertion `BI.FirstUse >= Start' failed.
0 llc 0x0000000000f49bef
1 llc 0x0000000000f4a72a
2 libpthread.so.0 0x00000037bea0eeb0
3 libc.so.6 0x00000037bde330c5 gsignal + 53
4 libc.so.6 0x00000037bde34a76 abort + 390
5 libc.so.6 0x00000037bde2b905 __assert_fail + 245
6 llc 0x0000000000bdec47
7 llc 0x0000000000bdeff0 llvm::SplitAnalysis::analyzeUses() + 512
8 llc 0x0000000000b7e1aa
9 llc 0x0000000000b67c8b llvm::RegAllocBase::allocatePhysRegs() + 267
10 llc 0x0000000000b7b31b
11 llc 0x0000000000e7919f llvm::FPPassManager::runOnFunction(llvm::Function&) + 655
12 llc 0x0000000000e7925b llvm::FPPassManager::runOnModule(llvm::Module&) + 75
13 llc 0x0000000000e78c97 llvm::MPPassManager::runOnModule(llvm::Module&) + 551
14 llc 0x0000000000e78dfb llvm::PassManagerImpl::run(llvm::Module&) + 187
15 llc 0x000000000055550a main + 4970
16 libc.so.6 0x00000037bde1ee5d __libc_start_main + 253
17 llc 0x0000000000553229
Stack dump:
0. Program arguments: /home/rich/ellcc/bin/llc merge.bc
1. Running pass 'Function Pass Manager' on module 'merge.bc'.
2. Running pass 'Greedy Register Allocator' on function '@mergesort'
Abort (core dumped)
[~/ellcc/libecc/obj/mips/linux/c] main%

Now we can use bugpoint to get a reduced test case:

[~/ellcc/libecc/obj/mips/linux/c] main% ~/ellcc/bin/bugpoint -run-llc merge.bc
...
[lots of output]
...
Checking instruction: %list2.1 = phi i8* [ undef, %if.then419 ], [ %list2.0.lcssa, %while.end415 ]
Checking instruction: tail call void @free(i8* %list2.1)

*** Attempting to perform final cleanups:
Emitted bitcode to 'bugpoint-reduced-simplified.bc'
[~/ellcc/libecc/obj/mips/linux/c] main%

I can get a readable version of the .bc file using llvm-dis and, just for fun, verify that it too fails:

[~/ellcc/libecc/obj/mips/linux/c] main% ~/ellcc/bin/llvm-dis bugpoint-reduced-simplified.bc
[~/ellcc/libecc/obj/mips/linux/c] main% ~/ellcc/bin/llc bugpoint-reduced-simplified.ll
llc: /home/rich/ellcc/llvm/lib/CodeGen/SplitKit.cpp:180: bool llvm::SplitAnalysis::calcLiveBlockInfo(): Assertion `BI.FirstUse >= Start' failed.
0 llc 0x0000000000f49bef
1 llc 0x0000000000f4a72a
2 libpthread.so.0 0x00000037bea0eeb0
3 libc.so.6 0x00000037bde330c5 gsignal + 53
4 libc.so.6 0x00000037bde34a76 abort + 390
5 libc.so.6 0x00000037bde2b905 __assert_fail + 245
6 llc 0x0000000000bdec47
7 llc 0x0000000000bdeff0 llvm::SplitAnalysis::analyzeUses() + 512
8 llc 0x0000000000b7e1aa
9 llc 0x0000000000b67c8b llvm::RegAllocBase::allocatePhysRegs() + 267
10 llc 0x0000000000b7b31b
11 llc 0x0000000000e7919f llvm::FPPassManager::runOnFunction(llvm::Function&) + 655
12 llc 0x0000000000e7925b llvm::FPPassManager::runOnModule(llvm::Module&) + 75
13 llc 0x0000000000e78c97 llvm::MPPassManager::runOnModule(llvm::Module&) + 551
14 llc 0x0000000000e78dfb llvm::PassManagerImpl::run(llvm::Module&) + 187
15 llc 0x000000000055550a main + 4970
16 libc.so.6 0x00000037bde1ee5d __libc_start_main + 253
17 llc 0x0000000000553229
Stack dump:
0. Program arguments: /home/rich/ellcc/bin/llc bugpoint-reduced-simplified.ll
1. Running pass 'Function Pass Manager' on module 'bugpoint-reduced-simplified.ll'.
2. Running pass 'Greedy Register Allocator' on function '@mergesort'
Abort (core dumped)
[~/ellcc/libecc/obj/mips/linux/c] main%

I keep a non-modified copy of the LLVM/clang sources for comparison purposes.
I’ll try the test case with the stock top of tree LLVM as a sanity check before I file a bug report:

[~] main% cd ~/vendor/llvm-build/llvm
[~/vendor/llvm-build/llvm] main% svn update
At revision 132287.
[~/vendor/llvm-build/llvm] main% cd tools/clang/
[~/vendor/llvm-build/llvm/tools/clang] main% svn update
At revision 132287.
[~/vendor/llvm-build/llvm/tools/clang] main% cd ../../../llvm
llvm/ llvm-build/
[~/vendor/llvm-build/llvm/tools/clang] main% cd ../../../llvm-build/
[~/vendor/llvm-build/llvm-build] main% make install

This build places binaries in my ~/vendor/llvm-build/bin directory. To verify the bug, I’ll use the new llc:

[~/ellcc/libecc/obj/mips/linux/c] main% ~/vendor/llvm-build/bin/llc bugpoint-reduced-simplified.ll
llc: /home/rich/vendor/llvm-build/llvm/lib/CodeGen/SplitKit.cpp:180: bool llvm::SplitAnalysis::calcLiveBlockInfo(): Assertion `BI.FirstUse >= Start' failed.
0 llc 0x0000000000f4b6cf
1 llc 0x0000000000f4c20a
2 libpthread.so.0 0x00000037bea0eeb0
3 libc.so.6 0x00000037bde330c5 gsignal + 53
4 libc.so.6 0x00000037bde34a76 abort + 390
5 libc.so.6 0x00000037bde2b905 __assert_fail + 245
6 llc 0x0000000000be0777
7 llc 0x0000000000be0b20 llvm::SplitAnalysis::analyzeUses() + 512
8 llc 0x0000000000b7fcda
9 llc 0x0000000000b697bb llvm::RegAllocBase::allocatePhysRegs() + 267
10 llc 0x0000000000b7ce4b
11 llc 0x0000000000e7ac1f llvm::FPPassManager::runOnFunction(llvm::Function&) + 655
12 llc 0x0000000000e7acdb llvm::FPPassManager::runOnModule(llvm::Module&) + 75
13 llc 0x0000000000e7a717 llvm::MPPassManager::runOnModule(llvm::Module&) + 551
14 llc 0x0000000000e7a87b llvm::PassManagerImpl::run(llvm::Module&) + 187
15 llc 0x000000000055524a main + 4970
16 libc.so.6 0x00000037bde1ee5d __libc_start_main + 253
17 llc 0x0000000000552f69
Stack dump:
0. Program arguments: /home/rich/vendor/llvm-build/bin/llc bugpoint-reduced-simplified.ll
1. Running pass 'Function Pass Manager' on module 'bugpoint-reduced-simplified.ll'.
2. Running pass 'Greedy Register Allocator' on function '@mergesort'
Abort (core dumped)
[~/ellcc/libecc/obj/mips/linux/c] main%

After renaming the test case to MipsGRAassert.ll, I submitted the bug to the LLVM project here.

Updating From Outside Sources

The ELLCC project uses several open source projects together to make a cross development environment. These projects include:

  • binutils – Assemblers, linkers, and various utilities for manipulating object files.
  • clang – The LLVM based C/C++/Objective-C/Objective-C++ compiler front end.
  • compiler-rt – The low level support library for handling of things, like floating point numbers, that a particular target may not support in hardware.
  • gdb – The source level debugger.
  • llvm – The compiler back end.
  • qemu – The target emulator.

One of the problems with a project like this is that you’d like to stay up to date with changes to outside projects. I’ll describe how I do this for the LLVM relates projects clang, compiler-rt, and llvm. Subversion is used as the source code control system for ELLCC, so the following procedures are subversion specific.

For all the outside projects that I use or reference I keep a copy of the sources that I never edit. I keep them in my ~/vendor directory:

[~/vendor] main% ls
binutils/ clang/ gdb/ glibc-2.12.2/ linux-2.6.36.1/ ptmalloc3/ src/ u-boot/
bzip2-1.0.6/ compiler-rt/ getvendor* lastrev llvm/ qemu/ tcsh-6.17.00/
[~/vendor] main%

I’ll go ahead and get the latest stuff from llvm, etc.:

[~/vendor] main% cd llvm
[~/vendor/llvm] main% svn update
...
U examples/Kaleidoscope/Chapter6/toy.cpp
U examples/Kaleidoscope/Chapter7/toy.cpp
U examples/ExceptionDemo/ExceptionDemo.cpp
Updated to revision 131667.
[~/vendor/llvm] main% cd ../clang/
[~/vendor/clang] main% svn update
...
U lib/Parse/ParseDeclCXX.cpp
U lib/Parse/ParseExprCXX.cpp
Updated to revision 131667.
[~/vendor/clang] main% cd ../compiler-rt/
[~/vendor/compiler-rt] main% svn update
...
U make/platform/darwin_bni.mk
U make/platform/clang_darwin.mk
Updated to revision 131667.
[~/vendor/compiler-rt] main%

At this point I make a note of the version number I’ve updated to (131667) so I can use it for labeling the updated code in my repository.

The next step is to import the changes into the ELLCC repository’s copy of the vendor code. I have a short script that does it for the llvm stuff:

#! /bin/sh
if [ $# -ne 2 ] ; then
echo "$0: <revision> <password>"
exit 1
fi
/usr/share/doc/subversion-1.6.16/svn_load_dirs.pl -svn_username rich -svn_password $2 -t svn-$1 http://ellcc.org/svn/vendor/llvm current llvm
/usr/share/doc/subversion-1.6.16/svn_load_dirs.pl -svn_username rich -svn_password $2 -t svn-$1 http://ellcc.org/svn/vendor/clang current clang
/usr/share/doc/subversion-1.6.16/svn_load_dirs.pl -svn_username rich -svn_password $2 -t svn-$1 http://ellcc.org/svn/vendor/compiler-rt current compiler-rt
echo $1 >lastrev

This script takes two arguments, the vendor version number that was just picked up, and the password for the subversion repository.
In this case I’d use:

[~/vendor] main% ./getvendor 131667 XXXXXXXX

Where XXXXXXXX is the real repository password.

The ELLCC project keeps the vendor code tagged by revision, so for llvm, the repository looks like this:

svn - Revision 2434: /vendor/llvm
* ..
* current/
* svn-119910/
* svn-121798/
* svn-122630/
* svn-122785/
* svn-122854/
* svn-122855/
* svn-122942/
* svn-122956/
* svn-124532/
* svn-126041/
* svn-126579/
* svn-127082/
* svn-127564/
* svn-127949/
* svn-131667/

Note that we now have a tag called svn-131667. The previous tagged version was svn-127949, The next steps will update the actual code in the ELLCC source code with the differences between these two versions. The next commands should be executed in a checkout of the latest trunk ellcc. I usually checkout the latest ellcc trunk in ~/ellcc, so the commands I use to merge are:

[~/vendor] main% cd ~/ellcc
[~/ellcc] main% ./mergellvm 127949


The mergellvm script looks like this:

#! /bin/sh
if [ $# -ne 1 ] ; then
echo "$0: <revision>"
exit 1
fi
svn merge --accept edit http://ellcc.org/svn/vendor/llvm/svn-$1 http://ellcc.org/svn/vendor/llvm/current llvm
cd libecc/src
svn merge --accept edit http://ellcc.org/svn/vendor/compiler-rt/svn-$1 http://ellcc.org/svn/vendor/compiler-rt/current compiler-rt
cd ../../llvm/tools
svn merge --accept edit http://ellcc.org/svn/vendor/clang/svn-$1 http://ellcc.org/svn/vendor/clang/current clang

If you encounter any merge conflicts the offending file will be opened in an editor.
Search for the merge conflicts, with e.g. (in vi) “/<<<<<":

<<<<<<< .working
case llvm::Triple::ppc64:
return *(TheTargetCodeGenInfo = new PPC64TargetCodeGenInfo(Types));
=======
case llvm::Triple::ptx32:
case llvm::Triple::ptx64:
return *(TheTargetCodeGenInfo = new PTXTargetCodeGenInfo(Types));
>>>>>>> .merge-right.r2434

In this case the resolved merge becomes:

case llvm::Triple::ppc64:
return *(TheTargetCodeGenInfo = new PPC64TargetCodeGenInfo(Types));
case llvm::Triple::ptx32:
case llvm::Triple::ptx64:
return *(TheTargetCodeGenInfo = new PTXTargetCodeGenInfo(Types));

After you finish editing, subversion will ask if the conflict has been resolved. Answer yes.

Hello world!

Last weekend I upgraded my Linux server from Fedora 12 to 14. This got me thinking about the sorry state of my web infrastructure. The Wiki was non-functional, Bugzilla didn’t work, and several links were broken. Not a great face to present to the outside world. So I decided to spent the weekend updating the ELLCC site and decided it was time to add a blog.

I decided to dump the Wiki entirely because it was too much of a pain to keep it spam free. Bugzilla is up and ready to go, and it was very easy to bring up the WordPress blog software.