[LLVMdev] Implementing devirtualization
Eli Friedman
eli.friedman at gmail.com
Thu Dec 8 16:26:06 PST 2011
On Thu, Dec 8, 2011 at 2:11 PM, Vitor Luis Menezes <vitor at utexas.edu> wrote:
> We've got the following test case:
>
>
> class A {
> public:
> int x;
> A(int x) : x(x) {}
> int hoo() {return 4;}
> virtual int foo() {return x;}
> virtual int goo() {return foo()+10;}
> virtual int operator+(A &a) {
> return x + a.x;
> }
> };
>
> class B : public A {
> public:
> B(int x) : A(x) {}
> int hoo() {return 2;}
> virtual int foo() {return A::foo()*2;}
> };
>
> int main() {
> A* a = new A(1);
> B* b = new B(2);
> int y = a->foo() + b->goo() + a->hoo() + b->hoo() + (*a + *b);
> delete a; delete b;
> return y;
> }
>
>
> Clang with -O4 -S -emit-llvm emits the following for main():
>
>
> define i32 @main() {
> %1 = tail call noalias i8* @_Znwm(i64 16), !dbg !70
> %2 = bitcast i8* %1 to %class.A*, !dbg !70
> tail call void @llvm.dbg.value(metadata !{%class.A* %2}, i64 0, metadata
> !68)
> tail call void @llvm.dbg.value(metadata !71, i64 0, metadata !69)
> tail call void @llvm.dbg.value(metadata !{%class.A* %2}, i64 0, metadata
> !66)
> tail call void @llvm.dbg.value(metadata !71, i64 0, metadata !67)
> %3 = bitcast i8* %1 to i32 (...)***
> store i32 (...)** bitcast (i8** getelementptr inbounds ([5 x i8*]*
> @_ZTV1A, i64 0, i64 2) to i32 (...)**), i32 (...)*** %3, align 8
> %4 = getelementptr inbounds i8* %1, i64 8
> %5 = bitcast i8* %4 to i32*
> store i32 1, i32* %5, align 4, !tbaa !72
> tail call void @llvm.dbg.value(metadata !{%class.A* %2}, i64 0, metadata
> !49), !dbg !70
> %6 = tail call noalias i8* @_Znwm(i64 16), !dbg !75
> tail call void @llvm.dbg.value(metadata !{null}, i64 0, metadata !57)
> tail call void @llvm.dbg.value(metadata !76, i64 0, metadata !58)
> tail call void @llvm.dbg.value(metadata !{null}, i64 0, metadata !59)
> tail call void @llvm.dbg.value(metadata !76, i64 0, metadata !60)
> tail call void @llvm.dbg.value(metadata !{null}, i64 0, metadata !66)
> tail call void @llvm.dbg.value(metadata !76, i64 0, metadata !67)
> %7 = getelementptr inbounds i8* %6, i64 8
> %8 = bitcast i8* %7 to i32*
> store i32 2, i32* %8, align 4, !tbaa !72
> %9 = bitcast i8* %6 to i8***
> store i8** getelementptr inbounds ([5 x i8*]* @_ZTV1B, i64 0, i64 2),
> i8*** %9, align 8
> tail call void @llvm.dbg.value(metadata !{null}, i64 0, metadata !52),
> !dbg !75
> %10 = bitcast i8* %1 to i32 (%class.A*)***, !dbg !77
> %11 = load i32 (%class.A*)*** %10, align 8, !dbg !77
> %12 = load i32 (%class.A*)** %11, align 8, !dbg !77
> %13 = tail call i32 %12(%class.A* %2), !dbg !77
> %14 = bitcast i8* %6 to %class.A*, !dbg !77
> %15 = bitcast i8* %6 to i32 (%class.A*)***, !dbg !77
> %16 = load i32 (%class.A*)*** %15, align 8, !dbg !77
> %17 = getelementptr inbounds i32 (%class.A*)** %16, i64 1, !dbg !77
> %18 = load i32 (%class.A*)** %17, align 8, !dbg !77
> %19 = tail call i32 %18(%class.A* %14), !dbg !77
> %20 = bitcast i8* %1 to i32 (%class.A*, %class.A*)***, !dbg !77
> %21 = load i32 (%class.A*, %class.A*)*** %20, align 8, !dbg !77
> %22 = getelementptr inbounds i32 (%class.A*, %class.A*)** %21, i64 2, !dbg
> !77
> %23 = load i32 (%class.A*, %class.A*)** %22, align 8, !dbg !77
> %24 = tail call i32 %23(%class.A* %2, %class.A* %14), !dbg !77
> %25 = add i32 %13, 6, !dbg !77
> %26 = add i32 %25, %19, !dbg !77
> %27 = add i32 %26, %24, !dbg !77
> tail call void @llvm.dbg.value(metadata !{i32 %27}, i64 0, metadata !54),
> !dbg !77
> %28 = icmp eq i8* %1, null, !dbg !78
> br i1 %28, label %30, label %29, !dbg !78
>
> ; <label>:29 ; preds = %0
> tail call void @_ZdlPv(i8* %1) nounwind, !dbg !78
> br label %30, !dbg !78
>
> ; <label>:30 ; preds = %29, %0
> %31 = icmp eq i8* %6, null, !dbg !78
> br i1 %31, label %33, label %32, !dbg !78
>
> ; <label>:32 ; preds = %30
> tail call void @_ZdlPv(i8* %6) nounwind, !dbg !78
> br label %33, !dbg !78
>
> ; <label>:33 ; preds = %32, %30
> ret i32 %27, !dbg !79
> }
>
>
> It's a bit long-winded, but from looking at the code it's clear that no
> virtual calls are actually necessary, yet Clang and LLVM generated both of
> them.
Try with LLVM trunk; with some recent changes, LLVM's GVN is now a bit
more powerful in situations like this.
-Eli
More information about the llvm-dev
mailing list