Skip to content

Missing optimization for dynamic_cast to/from final class #10013

@zygoloid

Description

@zygoloid
mannequin
Bugzilla Link 9641
Version trunk
OS Linux
CC @DougGregor

Extended Description

Consider this:

class A { virtual ~A(); };
class B final : public A {};

extern struct A *p;

int main() {
  return dynamic_cast<B*>(p) != 0;
}

This produces the following IR:

; ModuleID = '-'
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
target triple = "x86_64-unknown-linux-gnu"

%0 = type { i8*, i8*, i8* }
%class.A = type { i32 (...)** }
%class.B = type { [8 x i8] }

@&#8203;p = external global %class.A*
@&#8203;_ZTI1A = external constant i8*
@&#8203;_ZTVN10__cxxabiv120__si_class_type_infoE = external global i8*
@&#8203;_ZTS1B = linkonce_odr constant [3 x i8] c"1B\00"
@&#8203;_ZTI1B = linkonce_odr unnamed_addr constant %0 { i8* bitcast (i8** getelementptr inbounds (i8** @&#8203;_ZTVN10__cxxabiv120__si_class_type_infoE, i64 2) to i8*), i8* getelementptr inbounds ([3 x i8]* @&#8203;_ZTS1B, i32 0, i32 0), i8* bitcast (i8** @&#8203;_ZTI1A to i8*) }

define i32 @&#8203;main() nounwind {
entry:
  %retval = alloca i32, align 4
  store i32 0, i32* %retval
  %tmp = load %class.A** @&#8203;p, align 8
  %0 = icmp ne %class.A* %tmp, null
  br i1 %0, label %1, label %5

; <label>:1                                       ; preds = %entry
  %2 = bitcast %class.A* %tmp to i8*
  %3 = call i8* @&#8203;__dynamic_cast(i8* %2, i8* bitcast (i8** @&#8203;_ZTI1A to i8*), i8* bitcast (%0* @&#8203;_ZTI1B to i8*), i64 -1)
  %4 = bitcast i8* %3 to %class.B*
  br label %6

; <label>:5                                       ; preds = %entry
  br label %6

; <label>:6                                       ; preds = %5, %1
  %7 = phi %class.B* [ %4, %1 ], [ null, %5 ]
  %cmp = icmp ne %class.B* %7, null
  %conv = zext i1 %cmp to i32
  ret i32 %conv
}

declare i8* @&#8203;__dynamic_cast(i8*, i8*, i8*, i64)

Since 'B' is final, the call to __dynamic_cast is unnecessary: we can just directly compare p's vptr against B's vptr.

When dynamic_cast<>ing /from/ a final type, the situation is even better: all dynamic_cast<>s can be directly resolved at compile time.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions