[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