[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