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 -- View this message in context: http://www.nabble.com/Instruction-Combining-Pass-*Breaking*-Struct-Reads--tp24253572p24253572.html Sent from the LLVM - Dev mailing list archive at Nabble.com.
Eli Friedman
2009-Jun-29 14:52 UTC
[LLVMdev] Instruction Combining Pass *Breaking* Struct Reads?
On Mon, Jun 29, 2009 at 5:54 AM, Nyx<mcheva at cs.mcgill.ca> wrote:> 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)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:> > On Mon, Jun 29, 2009 at 5:54 AM, Nyx<mcheva at cs.mcgill.ca> wrote: >> 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) > > 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 > _______________________________________________ > LLVM Developers mailing list > LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev > >-- View this message in context: http://www.nabble.com/Instruction-Combining-Pass-*Breaking*-Struct-Reads--tp24253572p24256244.html Sent from the LLVM - Dev mailing list archive at Nabble.com.