[cfe-dev] Devirtualization of calls
Matthieu Monrocq
matthieu.monrocq at gmail.com
Sat Sep 3 06:30:54 PDT 2011
Hello,
Following a question on SO about how MSVC handled the devirtualization of
calls, I tried the following in Clang to check its behavior:
struct A { virtual void foo(); };
struct C { A a; };
C& GetRef();
void devirtualizeDirect() {
A a;
a.foo();
C c;
c.a.foo();
}
void devirtualizeRef() {
A a;
A& ar = a;
ar.foo();
C c;
C& cr = c;
cr.a.foo();
}
void nodevirtualize() {
C& cr = GetRef();
cr.a.foo();
}
Here is the IR emitted by the Try Out LLVM page (for the 3 functions of
interest):
define void @devirtualizeDirect()() {
%a = alloca %struct.A, align 8
%c = alloca %struct.C, align 8
%1 = getelementptr inbounds %struct.A* %a, i64 0, i32 0
store i32 (...)** bitcast (i8** getelementptr inbounds ([3 x i8*]*
@vtable for A, i64 0, i64 2) to i32 (...)**), i32 (...)*** %1, align 8
call void @A::foo()(%struct.A* %a)
%2 = getelementptr inbounds %struct.C* %c, i64 0, i32 0, i32 0
store i32 (...)** bitcast (i8** getelementptr inbounds ([3 x i8*]*
@vtable for A, i64 0, i64 2) to i32 (...)**), i32 (...)*** %2, align 8
%3 = getelementptr inbounds %struct.C* %c, i64 0, i32 0
call void @A::foo()(%struct.A* %3)
ret void
}
define void @devirtualizeRef()() {
%a = alloca %struct.A, align 8
%c = alloca %struct.C, align 8
%1 = getelementptr inbounds %struct.A* %a, i64 0, i32 0
store i32 (...)** bitcast (i8** getelementptr inbounds ([3 x i8*]*
@vtable for A, i64 0, i64 2) to i32 (...)**), i32 (...)*** %1, align 8
call void @A::foo()(%struct.A* %a)
%2 = getelementptr inbounds %struct.C* %c, i64 0, i32 0, i32 0
store i32 (...)** bitcast (i8** getelementptr inbounds ([3 x i8*]*
@vtable for A, i64 0, i64 2) to i32 (...)**), i32 (...)*** %2, align 8
%3 = getelementptr inbounds %struct.C* %c, i64 0, i32 0
call void @A::foo()(%struct.A* %3)
ret void
}
define void @nodevirtualize()() {
%1 = tail call %struct.C* @GetRef()()
%2 = getelementptr inbounds %struct.C* %1, i64 0, i32 0
%3 = bitcast %struct.C* %1 to void (%struct.A*)***
%4 = load void (%struct.A*)*** %3, align 8
%5 = load void (%struct.A*)** %4, align 8
tail call void %5(%struct.A* %2)
ret void
}
As expected Clang successfully devirtualize the call in the first example,
and even succeeds in the second which MSVC didn't.
However it fails to handle the 3rd case (or so I assume from the pointer
meddling), which seems very much like the second (`cr.a` is necessarily a
`A` whatever the dynamic type of `cr`).
I therefore have 2 questions:
1/ I tried unsuccesfully to obtain the LLVM IR on my own PC (using MSYS),
however clang refuses to emit it:
$ clang -emit-llvm devirtualize.cpp -o devirtualize.o
clang: error: 'i686-pc-mingw32': unable to pass LLVM bit-code files to
linker
How could I get the LLVM IR ? (under textual representation, but I can use
llvm-dis if I get bytecode I think)
2/ Does anyone have any inkling as to where the devirtualization occur in
Clang ? I'd like to have a look but for now I never explored past Sema and
this seems something more like CodeGen.
Thanks :)
-- Matthieu
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20110903/b2965723/attachment.html>
More information about the cfe-dev
mailing list