Why clang inlines with -O3 flag and opt doesn't?

When I compile my C fibonacci example fib.c with 'clang -O3 -c -emit-llvm -o fib-clang.bc fib.c&& llvm-dis fib-clang.bc' I get fib-clang.ll that has some degree of inlining in it.

But when I get an equivalent to fib.c file fib.ll and run it through opt with the command 'llvm-as fib.ll&& opt -O3 fib.bc -o fib-opt.bc&& llvm-dis fib-opt.bc' resulting fib-opt.ll doesn't have any degree of inlining despite the flag -O3.

Why clang with the flag -O3 inlines code and opt with the same -O3 doesn't?
How can I make opt inline my .ll code the same way?

Yuri

--- fiobonacci fib.c example ---
#include<stdlib.h>
#include<stdio.h>

int fib(int AnArg) {
  if (AnArg<= 2) return (1);
  return (fib(AnArg-1)+fib(AnArg-2));
}

int main(int argc, char* argv[]) {
  int n = atoi(argv[1]);
  printf("fib(%i)=%i\n", n, fib(n));
}

--- my handcrafted fib.ll ---
define i32 @fib(i32) nounwind readnone {
fib.top:
   %xcmp1 = icmp ugt i32 %0, 1
   br i1 %xcmp1, label %maj, label %spec

maj:
   %m1 = add i32 %0, -1
   %1 = tail call i32 @fib(i32 %m1)
   %m2 = add i32 %0, -2
   %2 = tail call i32 @fib(i32 %m2)
   %res = add i32 %2, %1
   ret i32 %res

spec:
   %xcmp = icmp eq i32 %0, 1
   %mres = zext i1 %xcmp to i32
   ret i32 %mres
}

@.str = private constant [12 x i8] c"fib(%i)=%i\0A\00" ;<[12 x i8]*> [#uses=1]

define i32 @main(i32 %argc, i8** nocapture %argv) nounwind {
entry:
   %arrayidx = getelementptr inbounds i8** %argv, i64 1 ;<i8**> [#uses=1]
   %tmp1 = load i8** %arrayidx, align 8 ;<i8*> [#uses=1]
   %call = tail call i32 @atoi(i8* %tmp1) nounwind ;<i32> [#uses=2]
   %call4 = tail call i32 @fib(i32 %call) ;<i32> [#uses=1]
   %call5 = tail call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([12 x i8]* @.str, i64 0, i64 0), i32 %call, i32 %call4) nounwind ;<i32> [#uses=0]
   ret i32 0
}

declare i32 @atoi(i8* nocapture) nounwind readonly

declare i32 @printf(i8* nocapture, ...) nounwind

Hi Yuri,

But when I get an equivalent to fib.c file fib.ll and run it through opt with the command 'llvm-as fib.ll&& opt -O3 fib.bc -o fib-opt.bc&& llvm-dis fib-opt.bc' resulting fib-opt.ll doesn't have any degree of inlining despite the flag -O3.

perhaps because your hand written .ll has no target information in it.
I'm not sure why that would effect inlining, but in general it vastly
reduces the number of optimizations that can be performed.

Ciao,

Duncan.

Trunk clang and opt appear to completely refuse to inline the function
in question because it is recursive. If you're using an earlier
version, I think opt might not be using exactly the same inlining
thresholds as clang...

-Eli

I use rev.112342 from few days ago.

Yuri

I tried to copy target information from .ll file generated by clang but result after opt is the same.

Yuri

Hi Eli,

Trunk clang and opt appear to completely refuse to inline the function
in question because it is recursive. If you're using an earlier
version, I think opt might not be using exactly the same inlining
thresholds as clang...

that brings up the question of why tailcallopt didn't turn it into a loop...

Ciao,

Duncan.

Hi Yuri,

When I compile my C fibonacci example fib.c with 'clang -O3 -c -emit-llvm -o fib-clang.bc fib.c&& llvm-dis fib-clang.bc' I get fib-clang.ll that has some degree of inlining in it.

this is not exactly inlining, it is tail recursion elimination.

But when I get an equivalent to fib.c file fib.ll and run it through opt with the command 'llvm-as fib.ll&& opt -O3 fib.bc -o fib-opt.bc&& llvm-dis fib-opt.bc' resulting fib-opt.ll doesn't have any degree of inlining despite the flag -O3.

It is not equivalent, because your C program returns 1 for the first Fibonacci
number, while the .ll returns 0. If you change this

spec:
    %xcmp = icmp eq i32 %0, 1
    %mres = zext i1 %xcmp to i32
    ret i32 %mres

to

spec:
   return i32 1

then you get tail recursion elimination for the .ll too.

Ciao,

Duncan.