Author Archives: rich

ELLCC is an easy to use Cross Compiler

One thing that I probably haven’t made clear enough is that ELLCC is designed to be an easy to use cross development environment. Let’s say you need to generate code that runs on various Linux targets. In the gcc world, you’d have to either build multiple copies of the gcc tool chain or find pre-built binary packages that support each of the targets individually. Life is much simpler in the ELLCC world.

Let’s say you have a program you want to build:

#include 

int main()
{
    printf("hello world\n");
}

On a Linux host you can use ecc to build in the normal way:

~] main% ecc hello.c
[~] main% ./a.out 
hello world
[~] main% file a.out
a.out: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, not stripped
[~] main%

Now, let’s say you want to target an ARM processor. The only difference is that you can specify the target on the command line:

[~] main% ecc -target arm-ellcc-linux hello.c
[~] main% qemu-arm a.out
hello world
[~] main% file a.out
a.out: ELF 32-bit LSB executable, ARM, version 1, statically linked, not stripped
[~] main%

Same for the Power PC:

[~] main% ecc -target ppc-ellcc-linux hello.c
[~] main% qemu-ppc a.out
hello world
[~] main% file a.out
a.out: ELF 32-bit MSB executable, PowerPC or cisco 4500, version 1 (SYSV), statically linked, not stripped
[~] main%

Note that I’m using QEMU’s Linux user mode emulation to run the programs for non-native targets. The results would be the same if you were to download the executables to your favorite smart phone.

ELLCC and the musl Standard C Library

ELLCC, my clang/LLVM based cross development tool chain for ARM, Microblaze, Mips, Power PC, and X86, now incorporates musl as its standard C library for Linux. musl is a MIT licensed, highly POSIX compliant library offering high performance and a small foot print. I spent several weeks evaluating musl before deciding to use it in ELLCC. The clarity and consistency of its code base and the quality of its design convinced me that musl would be an ideal addition to ELLCC. If you’re looking for a non-GPL library solution, I highly recommend musl.

Using ELLCC to Cross Debug an ARM Application

I’m looking at replacing my Linux port of the NetBSD standard library with musl, another library with a BSD-like license. For the past couple of days I’ve been doing a feasibility study on musl, running it through my regression tests for x86_64 and things look very good.

Today, I decided to test the ARM and the first regression test failed. If you’re not familiar with ELLCC, it is a cross development tool chain that uses ecc (based on clang/LLVM) as the compiler. As part of my regression testing, I compile some of the NetBSD user-land utilities and run them using QEMU. When I ran the test of the program cat it failed:

cat ../../../../../src/bin/cat/testinput | ./cat | cmp ../../../../../src/bin/cat/testinput || exit 1
stdout: Bad file number
cmp: EOF on -

Strange. How could stdout have a bad file number? I simplified the test case and found that

~/ellcc/bin/qemu-arm cat < ../../../../../src/bin/cat/testinput

also failed.

I decided to fire up gdb on the simplified test. To do this, I started QEMU with the option to listen for the debugger on port 1234.

~/ellcc/bin/qemu-arm -g 1234 cat < ../../../../../src/bin/cat/testinput

In another window, I started the debugger:

[~/ellcc/test/obj/musl/linux/bin/cat] main% ~/ellcc/bin/ecc-gdb cat
GNU gdb (GDB) 7.4
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-unknown-linux-gnu".
For bug reporting instructions, please see:
...
Reading symbols from /home/rich/ellcc/test/obj/musl/linux/bin/cat/cat...done.
(gdb) set arch arm
The target architecture is assumed to be arm
(gdb) target remote :1234
Remote debugging using :1234
[New Remote target]
[Switching to Remote target]
0x0000807c in _start ()
(gdb) break cat.c:294
(gdb) break cat.c:310
Breakpoint 2 at 0x8cec: file ../../../../../src/bin/cat/cat.c, line 310.
(gdb) c
Continuing.

Breakpoint 1, raw_cat (rfd=0) at ../../../../../src/bin/cat/cat.c:294
294 wfd = fileno(stdout);
(gdb) next
295 if (buf == NULL) {
(gdb) print wfd
$1 = 1
(gdb) c
Continuing.

Breakpoint 2, raw_cat (rfd=0) at ../../../../../src/bin/cat/cat.c:310
310 if ((nw = write(wfd, buf + off, (size_t)nr)) < 0)
(gdb) print wfd
$2 = 0
(gdb)

Well, that is certainly a puzzling result! What could have changed wfd? Looking at the source of cat, it looks like the only thing that could have is the call to fstat(). What if the struct stat definition doesn't match what QEMU (or even ARM Linux) thinks it should be? It turns out that it is very possible that the struct stat used is right beneath the wfd variable on the stack.

Lets check that hypothesis. I'll set a breakpoint right at the fstat() call:

(gdb) set arch arm
The target architecture is assumed to be arm
(gdb) target remote :1234
Remote debugging using :1234
[New Remote target]
[Switching to Remote target]
0x0000807c in _start ()
(gdb) break cat.c:298
Breakpoint 1 at 0x8c40: file ../../../../../src/bin/cat/cat.c, line 298.
(gdb) c
Continuing.

Breakpoint 1, raw_cat (rfd=0) at ../../../../../src/bin/cat/cat.c:298
298 if (fstat(wfd, &sbuf) == 0 &&
(gdb) print wfd
$1 = 1
(gdb) next
303 if (buf == NULL) {
(gdb) print wfd
$2 = 0
(gdb) print sbuf
$3 = {st_dev = 10, __st_dev_padding = 0, __st_ino_truncated = 8, st_mode = 8576, st_nlink = 1, st_uid = 500,
st_gid = 5, st_rdev = 34821, __st_rdev_padding = 0, st_size = 0, st_blksize = 0, st_blocks = 1024,
st_atim = {tv_sec = 0, tv_nsec = 0}, st_mtim = {tv_sec = 1338126579, tv_nsec = 0}, st_ctim = {
tv_sec = 1338126579, tv_nsec = 0}, st_ino = 1336216504}
(gdb)

This is interesting. The sbuf structure looks like it incorrectly set. st_nlink is 1, which is good for stdout. st_uid is 500, which is my user id. st_blksize should be 1024, but that value got moved to st_blocks. st_atime (the file access time) is empty and st_ino should be 8 like __st_ino_truncated. It looks like the struct stat definition used by musl for the ARM is incorrect.

I snooped around a little bit and found the problem. The stat struct was defined as:

struct stat
{
dev_t st_dev;
int __st_dev_padding;
long __st_ino_truncated;
mode_t st_mode;
nlink_t st_nlink;
uid_t st_uid;
gid_t st_gid;
dev_t st_rdev;
int __st_rdev_padding;
off_t st_size;
blksize_t st_blksize;

blkcnt_t st_blocks;
struct timespec st_atim;
struct timespec st_mtim;
struct timespec st_ctim;
ino_t st_ino;
};

It turned out that some padding was missing. I modified it to be

struct stat
{
dev_t st_dev;
int __st_dev_padding;
long __st_ino_truncated;
mode_t st_mode;
nlink_t st_nlink;
uid_t st_uid;
gid_t st_gid;
dev_t st_rdev;
int __st_rdev_padding[2];
off_t st_size;
blksize_t st_blksize;
int __st_rdev_padding2[1];
blkcnt_t st_blocks;
struct timespec st_atim;
struct timespec st_mtim;
struct timespec st_ctim;
ino_t st_ino;
};

and voila! The cat was happy again.

Breakpoint 1, raw_cat (rfd=0) at ../../../../../src/bin/cat/cat.c:298
298 if (fstat(wfd, &sbuf) == 0 &&
(gdb) next
303 if (buf == NULL) {
(gdb) print sbuf
$1 = {st_dev = 10, __st_dev_padding = 0, __st_ino_truncated = 8, st_mode = 8576, st_nlink = 1, st_uid = 500,
st_gid = 5, st_rdev = 34821, __st_rdev_padding = {0, 0}, st_size = 0, st_blksize = 1024,
__st_rdev_padding2 = {0}, st_blocks = 0, st_atim = {tv_sec = 1338132494, tv_nsec = 0}, st_mtim = {
tv_sec = 1338132494, tv_nsec = 0}, st_ctim = {tv_sec = 1336216504, tv_nsec = 0}, st_ino = 8}

Augmenting the Test Suite

ELLCC has a few simple (for now) regression tests that are run after every new build. See this page for more information. A primary goal of ELLCC is to support a POSIX environment for both Linux and standalone (bare metal) embedded systems. To that end, I’ve recently started looking at open source test suites that check for POSIX compliance. One that I’ve found is the Open POSIX Test Suite.

I’ve looked at it a bit and it seems to be a good starting point for testing the ELLCC libraries. Unfortunately, it hasn’t been updated since 2005 so it is a little out of date.

I’ve worked on it a little bit to play better with a more modern Linux release (Fedora 16). I’m currently building the test suite against GCC and plan to build against the ecc compiler as a next step. (ecc uses the host header files and libraries to build programs. In other words, it is pretty similar to using clang/LLVM.) After that, I plan to build and test using libecc, the ELLCC standard libraries based on the NetBSD sources. If you’d like to follow the progress, I’m keeping the updated source in the ELLCC source repository.

Using ELLCC For Mips Standalone With QEMU

NOTE: This is a very preliminary post which will be updated as I work through adding standalone support to ELLCC.

Build a simple program:

~/ellcc/bin/mips32r2sf-sa-ecc write.c

Make a bios image:

~/ellcc/bin/ecc-objcopy -S -j .reset --output-target binary a.out mips_bios.bin

The qemu command line:

~/ellcc/bin/qemu-system-mips -machine mips -bios ./mips_bios.bin -nographic -s -S

Starting gdb:

~/ellcc/bin/ecc-gdb
GNU gdb (GDB) 7.3.1
Copyright (C) 2011 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later 
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-unknown-linux-gnu".
For bug reporting instructions, please see:
.
(gdb) target remote :1234
Remote debugging using :1234
0x00000000 in ?? ()
(gdb) set arch mips
The target architecture is assumed to be mips
(gdb) set endian big
The target is assumed to be big endian
(gdb) info regi
          zero       at       v0       v1       a0       a1       a2       a3
 R0   00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 
            t0       t1       t2       t3       t4       t5       t6       t7
 R8   00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 
            s0       s1       s2       s3       s4       s5       s6       s7
 R16  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 
            t8       t9       k0       k1       gp       sp       s8       ra
 R24  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 
            sr       lo       hi      bad    cause       pc
      00400004 00000000 00000000 00000000 00000400 bfc00000 
           fsr      fir
      00000000 00000000 
(gdb) disas 0xbfc00000, 0xbfc00024
Dump of assembler code from 0xbfc00000 to 0xbfc00024:
=> 0xbfc00000:  lui     k0,0xbfc0
   0xbfc00004:  addiu   k0,k0,16
   0xbfc00008:  jr      k0
   0xbfc0000c:  nop
   0xbfc00010:  mfc0    k0,$12
   0xbfc00014:  0x7f5a04c0
   0xbfc00018:  beqz    k0,0xbfc00030
   0xbfc0001c:  nop
   0xbfc00020:  lui     k0,0x9d00
End of assembler dump.
(gdb)

The gdb commands (for cut and paste):

target remote :1234
set arch mips
set endian big
info regi
disas 0xbfc00000, 0xbfc00024

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.