llvm-gcc: code generated for pre- and post-increment

I'm relatively new to LLVM so apologies in advance if this is a dumb question. I've been experimenting with re-targeting LLVM onto a 16-bit micro which has pre and post increment and decrement addressing modes. I've been using llvm-gcc to generate llvm bitcode and llvm 2.7 to go from here to my target assembly code.

I've got the Combine pass to deal with post-increment/decrement modes without any difficulty but I can't seem to get pre-increment/decrement modes to work. If I examine the bitcode for:

char c, *p;

void func(void)
{
   c = *++p;
}

then I get (with llvm-gcc 4.2.1):

%0 = load i8** @p, align 4
%1 = getelementptr inbounds i8* %0, i32 1
store i8* %1, i8** @p, align 4
%2 = load i8*, %1, align 1
store i* %2m i8* @c, align 1

I think the position of the first store is preventing DAGCombiner::CombineToPreIndexedLoadStore from folding the base pointer (test #3 out of the 4 tests it makes). If I move that store into p to the end of the code then it's happy to fold it.

Why does llvm-gcc emit llvm code that seems to preclude the combiner from ever being able to combine a pre-increment/decrement? Given that the order of side-effects between sequence points is unspecified and the behaviour undefined if any object is modified more than once between sequence points it seems to me to be perfectly legal to move that first load to the end.

In passing, I note that the clang front-end seems to emit code that will never be a candidate for folding into either pre or post increment/decrement operations.

Steve Montgomery

I'm relatively new to LLVM so apologies in advance if this is a dumb
question. I've been experimenting with re-targeting LLVM onto a 16-bit
micro which has pre and post increment and decrement addressing modes.
I've been using llvm-gcc to generate llvm bitcode and llvm 2.7 to go
from here to my target assembly code.

I've got the Combine pass to deal with post-increment/decrement modes
without any difficulty but I can't seem to get pre-increment/decrement
modes to work. If I examine the bitcode for:

char c, *p;

void func(void)
{
c = *++p;
}

then I get (with llvm-gcc 4.2.1):

%0 = load i8** @p, align 4
%1 = getelementptr inbounds i8* %0, i32 1
store i8* %1, i8** @p, align 4
%2 = load i8*, %1, align 1
store i* %2m i8* @c, align 1

I think the position of the first store is preventing
DAGCombiner::CombineToPreIndexedLoadStore from folding the base
pointer (test #3 out of the 4 tests it makes). If I move that store
into p to the end of the code then it's happy to fold it.

Why does llvm-gcc emit llvm code that seems to preclude the combiner
from ever being able to combine a pre-increment/decrement? Given that
the order of side-effects between sequence points is unspecified and
the behaviour undefined if any object is modified more than once
between sequence points it seems to me to be perfectly legal to move
that first load to the end.

Note that pre-increment is only precluded in cases where you're
incrementing something which both can't be eliminated by mem2reg and
can't be LICM'ed out of a loop. Yes, it's not ideal, but your
testcase isn't representative of many places where pre-increments are
used.

In passing, I note that the clang front-end seems to emit code that
will never be a candidate for folding into either pre or post
increment/decrement operations.

I don't really know llvm-gcc that well, but the clang code generator
is completely naive here: it generates the complete increment, then
loads from the address. If you're interested, though, it wouldn't be
too hard to change clang to detect constructs like this and shuffle
around the generated code.

-Eli