Instruction Combining Pass *Breaking* Struct Reads?

I'm in a situation where I have code that works fine if I don't run the
instruction combining optimization pass, but breaks when I do. The code in
question is meant to allocate space for two structs on the stack using
alloca, and then pass pointers to these to a callee function. One struct
serves to store the input to the function, the other serves for the callee
function to write its output. This is part of my calling mechanism. Once the
call is terminated, the caller will read from the output struct. The twist
is that I am not allocating the structs directly, I am allocating buffers of
bytes and casting the pointers into struct pointers.

The following snipper is without instruction combining being run:

  %2 = alloca i8, i32 16 ; <i8*> [#uses=1]
  %3 = alloca i8, i32 12 ; <i8*> [#uses=1]
  %4 = call i8* @"Environment::extend"(i8* inttoptr (i32 173374432 to i8*))
; <i8*> [#uses=3]
  %5 = call i8* @"ArrayObj::create"(i32 0) ; <i8*> [#uses=1]
  %6 = call i8* @"Interpreter::callFunction"(i8* inttoptr (i32 147457088 to
i8*), i8* %5, i32 0) ; <i8*> [#uses=0]
  %7 = bitcast i8* %2 to { i64, i64 }* ; <{ i64, i64 }*> [#uses=3]
  %8 = bitcast i8* %3 to { i8*, i64 }* ; <{ i8*, i64 }*> [#uses=3]
  %9 = getelementptr { i64, i64 }* %7, i32 0, i32 0 ; <i64*> [#uses=1]
  store i64 25, i64* %9
  %10 = getelementptr { i64, i64 }* %7, i32 0, i32 1 ; <i64*> [#uses=1]
  store i64 1, i64* %10
  call void @fibonacci_0xa566d80({ i64, i64 }* %7, { i8*, i64 }* %8)
  %11 = getelementptr { i8*, i64 }* %8, i32 0, i32 1 ; <i64*> [#uses=1]
  %12 = load i64* %11 ; <i64> [#uses=1]
  %13 = icmp slt i64 %12, 1 ; <i1> [#uses=1]
  br i1 %13, label %21, label %14

As you can see, I allocate two structs, one taking 16 bytes (containing two
i64 values), and one taking 12 bytes (containing a pointer and an i64 value,
this is on a 32-bit machine). I then cast those pointers to the proper
struct types (see values %7 and %8). I then call the fibonacci function, and
after that, I read the i64 value of the second struct (see values %11, %12)
and branch based on its value. This code works just fine when I run it.

Now, if I run the instruction combining pass, the above code gets turned
into this:

  %2 = alloca { i64, i64 }, align 8 ; <{ i64, i64 }*> [#uses=3]
  %3 = alloca [12 x i8], align 1 ; <[12 x i8]*> [#uses=3]
  %4 = call i8* @"Environment::extend"(i8* inttoptr (i32 148577248 to i8*))
; <i8*> [#uses=3]
  %5 = call i8* @"ArrayObj::create"(i32 0) ; <i8*> [#uses=1]
  %6 = call i8* @"Interpreter::callFunction"(i8* inttoptr (i32 147883136 to
i8*), i8* %5, i32 0) ; <i8*> [#uses=0]
  %7 = bitcast [12 x i8]* %3 to { i8*, i64 }* ; <{ i8*, i64 }*> [#uses=1]
  %8 = getelementptr { i64, i64 }* %2, i64 0, i32 0 ; <i64*> [#uses=1]
  store i64 25, i64* %8, align 8
  %9 = getelementptr { i64, i64 }* %2, i64 0, i32 1 ; <i64*> [#uses=1]
  store i64 1, i64* %9, align 8
  call void @fibonacci_0x8dc0d80({ i64, i64 }* %2, { i8*, i64 }* %7)
  %10 = getelementptr [12 x i8]* %3, i64 0, i64 8 ; <i8*> [#uses=1]
  %11 = bitcast i8* %10 to i64* ; <i64*> [#uses=1]
  %12 = load i64* %11 ; <i64> [#uses=1]
  %13 = icmp slt i64 %12, 1 ; <i1> [#uses=1]
  br i1 %13, label %21, label %14

This code does not work properly. If we take a look at value %10, we can see
that it tries to read a value at offset 8! This is obviously wrong, as the
value is an i64, and the size of the output struct is 12! Thus, the value
should be read at offset 4, not 8!

And here I find myself puzzled. I know the second struct really has size 12.
I know the alignment is 4. Why is it that the instruction combining pass
tries to read a value at offset 8, as if the pointer inside the output
struct took 8 bytes? Furthermore, why does it allocate one struct as a
struct, and one as a byte array? Is there a bug in this optimization pass,
or am I doing something wrong? Note that I am using LLVM version 2.5.

Any help would be appreciated!

- Max

Are you sure that's right? If the target data specifies that a
pointer is 64 bits or that i64 has an alignment of 64 bits, this code
is isn't allocating enough space for the struct.

-Eli

I just found what the problem was. I was using a different target data for
the optimization passes (creating a new one for the optimization passes) Not
the target data from the execution engine... So the instruction combining
pass was working with erroneous information, since by default it seems to
assume pointers are 64 bits. Problem fixed!

- Max

Eli Friedman-2 wrote: