opt -instcombine interesting behavior

Hi all,

I've been playing around with the llvm optimizer and stumbled upon an
interesting behavior with respect
to the "instcombine" option. I tried to optimize the following small
program (see also attachment small.ll)
(only with "instcombine"):

clang -v
clang version 4.0.0 (trunk 288238)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /usr/local/bin
Found candidate GCC installation: /usr/lib/gcc/i686-linux-gnu/5
Found candidate GCC installation: /usr/lib/gcc/i686-linux-gnu/5.4.0
Found candidate GCC installation: /usr/lib/gcc/i686-linux-gnu/6
Found candidate GCC installation: /usr/lib/gcc/i686-linux-gnu/6.0.0
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/5
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/5.4.0
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/6
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/6.0.0
Selected GCC installation: /usr/lib/gcc/x86_64-linux-gnu/5.4.0
Candidate multilib: .;@m64
Candidate multilib: 32;@m32
Candidate multilib: x32;@mx32
Selected multilib: .;@m64

llvm-as small.ll -o small.bc
opt -instcombine small.bc -o smallOpt.bc

define i32 @main() {
  %reg = alloca i32, i32 0
  store i32 1, i32* %reg
  %1 = getelementptr i32, i32* %reg, i32 0
  %2 = bitcast i32* %1 to [4 x i8]*
  %3 = getelementptr [4 x i8], [4 x i8]* %2, i32 0, i32 1
  store i8 1, i8* %3
  %4 = load i32, i32* %reg
  ret i32 %4
}

The program in pseudo code would/should simplified look something like this:

int main(){
    reg = 1;
    [reg+1] = 1; //Second byte of reg is set to 1
    return reg;
}

I assumed it would be optimized to - again pseudo code -:

int main(){
    return 257;
}

Instead, the program is optimized to(see also attachment
smallOpt.ll/smallOpt.bc):

define i32 @main() {
  ret i32 1
}

So i verified my assumption by printing '%4' of the original program
(smallPrint.ll/smallPrint.bc) and the output was 257.
I also optimized smallPrint.ll/smallPrint.bc , again only with
instcombine, but the output is changed to 1 (smallPrintOpt.bc).

I also tested it with clang 3.8.0.

What am i missing?

Best regards,
Stephan

smallPrintOpt.bc (868 Bytes)

smallPrint.bc (912 Bytes)

smallPrint.ll (486 Bytes)

smallOpt.ll (92 Bytes)

smallOpt.bc (736 Bytes)

small.bc (796 Bytes)

small.ll (273 Bytes)

Hi Stephan,

  %reg = alloca i32, i32 0

Allocating 0 bytes is legal but it's an undefined behavior, please refer:
http://llvm.org/docs/LangRef.html#id184

You need to correct allocation to get the desired output, i.e.:

  %reg = alloca i32, i32 1

Regards,
Ashutosh

%reg = alloca i32, i32 0

Allocating 0 bytes is legal but it’s an undefined behavior, please refer:
http://llvm.org/docs/LangRef.html#id184

Nit: I believe that when LangRef says “the result is undefined”, it does not mean “undefined behavior”.
See http://llvm.org/docs/LangRef.html#undefined-values for more details.

You need to correct allocation to get the desired output, i.e.:

%reg = alloca i32, i32 1

The “, i32 1” is optional though (default is 1).

Thanks for correcting Mehdi, its “the result is undefined” not “undefined behavior”.

Regards,

Ashutosh