[LLVMbugs] [Bug 5009] New: inliner missing opportunity with CPS style code

bugzilla-daemon at cs.uiuc.edu bugzilla-daemon at cs.uiuc.edu
Sat Sep 19 14:52:36 PDT 2009


http://llvm.org/bugs/show_bug.cgi?id=5009

           Summary: inliner missing opportunity with CPS style code
           Product: libraries
           Version: trunk
          Platform: PC
        OS/Version: All
            Status: NEW
          Severity: normal
          Priority: P2
         Component: Scalar Optimizations
        AssignedTo: unassignedbugs at nondot.org
        ReportedBy: idadesub at users.sourceforge.net
                CC: llvmbugs at cs.uiuc.edu


I'm experimenting with the explicitly managed stack frames from
http://nondot.org/sabre/LLVMNotes/ExplicitlyManagedStackFrames.txt, and I'm
running into a simple case where the inliner appears to be missing an
opportunity. Here's the CPS style code:

///////////////////////////////////
#include <stdlib.h>

struct cont_t {
    void (*f)(void*, int);
    void* sf;
};

static void bar(struct cont_t* c, int y) {
    return c->f(c->sf, y+5);
}

struct foo_sf_t {
    struct cont_t* c;
    int x;
};

static void foo2(struct foo_sf_t* sf, int y) {
    return sf->c->f(sf->c, sf->x * y);
}

static void foo(struct cont_t* c) {
    struct foo_sf_t sf = { c, 2 };
    struct cont_t next = { (void (*)(void*, int))foo2, &sf };
    return bar(&next, 14);
}

static void quit(struct cont_t* cont, int rcode) {
    return exit(rcode);
}

int main() {
    struct cont_t cont = { cont.f = (void (*)(void*, int))quit, NULL };
    foo(&cont);
    return 0;
}
///////////////////////////////////

compiled with clang -O3, it generates the following code. You'll notice that it
wasn't able to inline the function foo2:

///////////////////////////////////
; ModuleID = '<stdin>'
target datalayout =
"e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128"
target triple = "i386-apple-darwin9.0"

%struct.cont_t = type { void (i8*, i32)*, i8* }
%struct.foo_sf_t = type { %struct.cont_t*, i32 }

define i32 @main() nounwind {
entry:
  %sf.i = alloca %struct.foo_sf_t, align 4        ; <%struct.foo_sf_t*>
[#uses=3]
  %cont = alloca %struct.cont_t, align 4          ; <%struct.cont_t*> [#uses=3]
  %tmp = getelementptr inbounds %struct.cont_t* %cont, i32 0, i32 0 ; <void
(i8*, i32)**> [#uses=1]
  store void (i8*, i32)* bitcast (void (%struct.cont_t*, i32)* @quit to void
(i8*, i32)*), void (i8*, i32)** %tmp
  %tmp1 = getelementptr inbounds %struct.cont_t* %cont, i32 0, i32 1 ; <i8**>
[#uses=1]
  store i8* null, i8** %tmp1
  %tmp.i = getelementptr inbounds %struct.foo_sf_t* %sf.i, i32 0, i32 0 ;
<%struct.cont_t**> [#uses=1]
  store %struct.cont_t* %cont, %struct.cont_t** %tmp.i
  %tmp2.i = getelementptr inbounds %struct.foo_sf_t* %sf.i, i32 0, i32 1 ;
<i32*> [#uses=1]
  store i32 2, i32* %tmp2.i
  call void @foo2(%struct.foo_sf_t* %sf.i, i32 19) nounwind
  ret i32 0
}

define internal void @quit(%struct.cont_t* nocapture %cont, i32 %rcode)
nounwind {
entry:
  tail call void @exit(i32 %rcode) nounwind
  ret void
}

define internal void @foo2(%struct.foo_sf_t* nocapture %sf, i32 %y) nounwind {
entry:
  %tmp1 = getelementptr inbounds %struct.foo_sf_t* %sf, i32 0, i32 0 ;
<%struct.cont_t**> [#uses=1]
  %tmp2 = load %struct.cont_t** %tmp1             ; <%struct.cont_t*> [#uses=2]
  %tmp3 = getelementptr inbounds %struct.cont_t* %tmp2, i32 0, i32 0 ; <void
(i8*, i32)**> [#uses=1]
  %tmp4 = load void (i8*, i32)** %tmp3            ; <void (i8*, i32)*>
[#uses=1]
  %conv = bitcast %struct.cont_t* %tmp2 to i8*    ; <i8*> [#uses=1]
  %tmp9 = getelementptr inbounds %struct.foo_sf_t* %sf, i32 0, i32 1 ; <i32*>
[#uses=1]
  %tmp10 = load i32* %tmp9                        ; <i32> [#uses=1]
  %mul = mul i32 %tmp10, %y                       ; <i32> [#uses=1]
  tail call void %tmp4(i8* %conv, i32 %mul) nounwind
  ret void
}

declare void @exit(i32)
///////////////////////////////////

However, if you change the function foo to manually inline bar as the
following, the inliner then can fully evaluate the function:

///////////////////////////////////
static void foo(struct cont_t* c) {
    struct foo_sf_t sf = { c, 2 };
    struct cont_t next = { (void (*)(void*, int))foo2, &sf };
    struct cont_t* nextp = &next;
    int y = 14;
    return nextp->f(nextp->sf, y+5);
}
///////////////////////////////////

///////////////////////////////////
; ModuleID = '<stdin>'
target datalayout =
"e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128"
target triple = "i386-apple-darwin9.0"

%struct.cont_t = type { void (i8*, i32)*, i8* }

define i32 @main() nounwind {
entry:
  %cont = alloca %struct.cont_t, align 4          ; <%struct.cont_t*> [#uses=3]
  %tmp = getelementptr inbounds %struct.cont_t* %cont, i32 0, i32 0 ; <void
(i8*, i32)**> [#uses=1]
  store void (i8*, i32)* bitcast (void (%struct.cont_t*, i32)* @quit to void
(i8*, i32)*), void (i8*, i32)** %tmp
  %tmp1 = getelementptr inbounds %struct.cont_t* %cont, i32 0, i32 1 ; <i8**>
[#uses=1]
  store i8* null, i8** %tmp1
  call void @quit(%struct.cont_t* %cont, i32 38) nounwind
  ret i32 0
}

define internal void @quit(%struct.cont_t* nocapture %cont, i32 %rcode)
nounwind {
entry:
  tail call void @exit(i32 %rcode) nounwind
  ret void
}

declare void @exit(i32)
///////////////////////////////////


-- 
Configure bugmail: http://llvm.org/bugs/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are on the CC list for the bug.



More information about the llvm-bugs mailing list