Revert r211402 (and r211408,r211410), "CodeGen: Refactor dynamic_cast and typeid" It crashes msvc codegen in clang/test/SemaCXX/undefined-internal.cpp.

It is reproducible with:

  $ clang -cc1 -triple i686-win32 -emit-llvm-only clang/test/SemaCXX/undefined-internal.cpp

llvm-svn: 211467
diff --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp
index 47dc9fb..0b5a415 100644
--- a/clang/lib/CodeGen/CGExprCXX.cpp
+++ b/clang/lib/CodeGen/CGExprCXX.cpp
@@ -1615,36 +1615,98 @@
   EmitBlock(DeleteEnd);
 }
 
+static llvm::Constant *getBadTypeidFn(CodeGenFunction &CGF) {
+  // void __cxa_bad_typeid();
+  llvm::FunctionType *FTy = llvm::FunctionType::get(CGF.VoidTy, false);
+  
+  return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_bad_typeid");
+}
+
+static void EmitBadTypeidCall(CodeGenFunction &CGF) {
+  llvm::Value *Fn = getBadTypeidFn(CGF);
+  CGF.EmitRuntimeCallOrInvoke(Fn).setDoesNotReturn();
+  CGF.Builder.CreateUnreachable();
+}
+
+/// \brief Gets the offset to the virtual base that contains the vfptr for
+/// MS-ABI polymorphic types.
+static llvm::Value *getPolymorphicOffset(CodeGenFunction &CGF,
+                                         const CXXRecordDecl *RD,
+                                         llvm::Value *Value) {
+  const ASTContext &Context = RD->getASTContext();
+  for (const CXXBaseSpecifier &Base : RD->vbases())
+    if (Context.getASTRecordLayout(Base.getType()->getAsCXXRecordDecl())
+            .hasExtendableVFPtr())
+      return CGF.CGM.getCXXABI().GetVirtualBaseClassOffset(
+          CGF, Value, RD, Base.getType()->getAsCXXRecordDecl());
+  llvm_unreachable("One of our vbases should be polymorphic.");
+}
+
+static llvm::Value *emitRTtypeidCall(CodeGenFunction &CGF,
+                                     llvm::Value *Argument) {
+  llvm::Type *ArgTypes[] = {CGF.Int8PtrTy};
+  llvm::Constant *Function = CGF.CGM.CreateRuntimeFunction(
+      llvm::FunctionType::get(CGF.Int8PtrTy, ArgTypes, false), "__RTtypeid");
+  llvm::Value *Args[] = {Argument};
+  return CGF.EmitRuntimeCall(Function, Args);
+}
+
 static llvm::Value *EmitTypeidFromVTable(CodeGenFunction &CGF, const Expr *E,
                                          llvm::Type *StdTypeInfoPtrTy) {
   // Get the vtable pointer.
   llvm::Value *ThisPtr = CGF.EmitLValue(E).getAddress();
 
+  if (CGF.getTarget().getCXXABI().isMicrosoft()) {
+    llvm::Value *CastPtr = CGF.Builder.CreateBitCast(ThisPtr, CGF.Int8PtrTy);
+    const CXXRecordDecl *RD = E->getType()->getAsCXXRecordDecl();
+    if (CGF.getContext().getASTRecordLayout(RD).hasExtendableVFPtr())
+      return CGF.Builder.CreateBitCast(emitRTtypeidCall(CGF, CastPtr),
+                                       StdTypeInfoPtrTy);
+    llvm::BasicBlock *EntryBlock = CGF.Builder.GetInsertBlock();
+    llvm::BasicBlock *AdjustBlock = CGF.createBasicBlock("type_id.valid");
+    llvm::BasicBlock *ExitBlock = CGF.createBasicBlock("type_id.call");
+    CGF.Builder.CreateCondBr(CGF.Builder.CreateIsNull(CastPtr), ExitBlock,
+                             AdjustBlock);
+    // Emit the call block and code for it.
+    CGF.EmitBlock(AdjustBlock);
+    llvm::Value *AdjustedThisPtr = CGF.Builder.CreateInBoundsGEP(
+        CastPtr, getPolymorphicOffset(CGF, RD, CastPtr));
+    // Emit the call block and the phi nodes for it.
+    CGF.EmitBlock(ExitBlock);
+    llvm::PHINode *ValuePHI = CGF.Builder.CreatePHI(CGF.Int8PtrTy, 2);
+    ValuePHI->addIncoming(AdjustedThisPtr, AdjustBlock);
+    ValuePHI->addIncoming(llvm::Constant::getNullValue(CGF.Int8PtrTy),
+                          EntryBlock);
+    return CGF.Builder.CreateBitCast(emitRTtypeidCall(CGF, ValuePHI),
+                                     StdTypeInfoPtrTy);
+  }
+
   // C++ [expr.typeid]p2:
   //   If the glvalue expression is obtained by applying the unary * operator to
   //   a pointer and the pointer is a null pointer value, the typeid expression
   //   throws the std::bad_typeid exception.
-  bool IsDeref = false;
-  if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(E->IgnoreParens()))
-    if (UO->getOpcode() == UO_Deref)
-      IsDeref = true;
-
-  QualType SrcRecordTy = E->getType();
-  if (CGF.CGM.getCXXABI().shouldTypeidBeNullChecked(IsDeref, SrcRecordTy)) {
-    llvm::BasicBlock *BadTypeidBlock =
+  if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(E->IgnoreParens())) {
+    if (UO->getOpcode() == UO_Deref) {
+      llvm::BasicBlock *BadTypeidBlock = 
         CGF.createBasicBlock("typeid.bad_typeid");
-    llvm::BasicBlock *EndBlock = CGF.createBasicBlock("typeid.end");
+      llvm::BasicBlock *EndBlock =
+        CGF.createBasicBlock("typeid.end");
 
-    llvm::Value *IsNull = CGF.Builder.CreateIsNull(ThisPtr);
-    CGF.Builder.CreateCondBr(IsNull, BadTypeidBlock, EndBlock);
+      llvm::Value *IsNull = CGF.Builder.CreateIsNull(ThisPtr);
+      CGF.Builder.CreateCondBr(IsNull, BadTypeidBlock, EndBlock);
 
-    CGF.EmitBlock(BadTypeidBlock);
-    CGF.CGM.getCXXABI().EmitBadTypeidCall(CGF);
-    CGF.EmitBlock(EndBlock);
+      CGF.EmitBlock(BadTypeidBlock);
+      EmitBadTypeidCall(CGF);
+      CGF.EmitBlock(EndBlock);
+    }
   }
 
-  return CGF.CGM.getCXXABI().EmitTypeid(CGF, SrcRecordTy, ThisPtr,
-                                        StdTypeInfoPtrTy);
+  llvm::Value *Value = CGF.GetVTablePtr(ThisPtr, 
+                                        StdTypeInfoPtrTy->getPointerTo());
+
+  // Load the type info.
+  Value = CGF.Builder.CreateConstInBoundsGEP1_64(Value, -1ULL);
+  return CGF.Builder.CreateLoad(Value);
 }
 
 llvm::Value *CodeGenFunction::EmitCXXTypeidExpr(const CXXTypeidExpr *E) {
@@ -1671,6 +1733,173 @@
                                StdTypeInfoPtrTy);
 }
 
+static llvm::Constant *getItaniumDynamicCastFn(CodeGenFunction &CGF) {
+  // void *__dynamic_cast(const void *sub,
+  //                      const abi::__class_type_info *src,
+  //                      const abi::__class_type_info *dst,
+  //                      std::ptrdiff_t src2dst_offset);
+  
+  llvm::Type *Int8PtrTy = CGF.Int8PtrTy;
+  llvm::Type *PtrDiffTy = 
+    CGF.ConvertType(CGF.getContext().getPointerDiffType());
+
+  llvm::Type *Args[4] = { Int8PtrTy, Int8PtrTy, Int8PtrTy, PtrDiffTy };
+
+  llvm::FunctionType *FTy = llvm::FunctionType::get(Int8PtrTy, Args, false);
+
+  // Mark the function as nounwind readonly.
+  llvm::Attribute::AttrKind FuncAttrs[] = { llvm::Attribute::NoUnwind,
+                                            llvm::Attribute::ReadOnly };
+  llvm::AttributeSet Attrs = llvm::AttributeSet::get(
+      CGF.getLLVMContext(), llvm::AttributeSet::FunctionIndex, FuncAttrs);
+
+  return CGF.CGM.CreateRuntimeFunction(FTy, "__dynamic_cast", Attrs);
+}
+
+static llvm::Constant *getBadCastFn(CodeGenFunction &CGF) {
+  // void __cxa_bad_cast();
+  llvm::FunctionType *FTy = llvm::FunctionType::get(CGF.VoidTy, false);
+  return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_bad_cast");
+}
+
+static void EmitBadCastCall(CodeGenFunction &CGF) {
+  llvm::Value *Fn = getBadCastFn(CGF);
+  CGF.EmitRuntimeCallOrInvoke(Fn).setDoesNotReturn();
+  CGF.Builder.CreateUnreachable();
+}
+
+/// \brief Compute the src2dst_offset hint as described in the
+/// Itanium C++ ABI [2.9.7]
+static CharUnits computeOffsetHint(ASTContext &Context,
+                                   const CXXRecordDecl *Src,
+                                   const CXXRecordDecl *Dst) {
+  CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
+                     /*DetectVirtual=*/false);
+
+  // If Dst is not derived from Src we can skip the whole computation below and
+  // return that Src is not a public base of Dst.  Record all inheritance paths.
+  if (!Dst->isDerivedFrom(Src, Paths))
+    return CharUnits::fromQuantity(-2ULL);
+
+  unsigned NumPublicPaths = 0;
+  CharUnits Offset;
+
+  // Now walk all possible inheritance paths.
+  for (CXXBasePaths::paths_iterator I = Paths.begin(), E = Paths.end();
+       I != E; ++I) {
+    if (I->Access != AS_public) // Ignore non-public inheritance.
+      continue;
+
+    ++NumPublicPaths;
+
+    for (CXXBasePath::iterator J = I->begin(), JE = I->end(); J != JE; ++J) {
+      // If the path contains a virtual base class we can't give any hint.
+      // -1: no hint.
+      if (J->Base->isVirtual())
+        return CharUnits::fromQuantity(-1ULL);
+
+      if (NumPublicPaths > 1) // Won't use offsets, skip computation.
+        continue;
+
+      // Accumulate the base class offsets.
+      const ASTRecordLayout &L = Context.getASTRecordLayout(J->Class);
+      Offset += L.getBaseClassOffset(J->Base->getType()->getAsCXXRecordDecl());
+    }
+  }
+
+  // -2: Src is not a public base of Dst.
+  if (NumPublicPaths == 0)
+    return CharUnits::fromQuantity(-2ULL);
+
+  // -3: Src is a multiple public base type but never a virtual base type.
+  if (NumPublicPaths > 1)
+    return CharUnits::fromQuantity(-3ULL);
+
+  // Otherwise, the Src type is a unique public nonvirtual base type of Dst.
+  // Return the offset of Src from the origin of Dst.
+  return Offset;
+}
+
+static llvm::Value *
+EmitItaniumDynamicCastCall(CodeGenFunction &CGF, llvm::Value *Value,
+                    QualType SrcTy, QualType DestTy,
+                    llvm::BasicBlock *CastEnd) {
+  llvm::Type *PtrDiffLTy = 
+    CGF.ConvertType(CGF.getContext().getPointerDiffType());
+  llvm::Type *DestLTy = CGF.ConvertType(DestTy);
+
+  if (const PointerType *PTy = DestTy->getAs<PointerType>()) {
+    if (PTy->getPointeeType()->isVoidType()) {
+      // C++ [expr.dynamic.cast]p7:
+      //   If T is "pointer to cv void," then the result is a pointer to the
+      //   most derived object pointed to by v.
+
+      // Get the vtable pointer.
+      llvm::Value *VTable = CGF.GetVTablePtr(Value, PtrDiffLTy->getPointerTo());
+
+      // Get the offset-to-top from the vtable.
+      llvm::Value *OffsetToTop = 
+        CGF.Builder.CreateConstInBoundsGEP1_64(VTable, -2ULL);
+      OffsetToTop = CGF.Builder.CreateLoad(OffsetToTop, "offset.to.top");
+
+      // Finally, add the offset to the pointer.
+      Value = CGF.EmitCastToVoidPtr(Value);
+      Value = CGF.Builder.CreateInBoundsGEP(Value, OffsetToTop);
+
+      return CGF.Builder.CreateBitCast(Value, DestLTy);
+    }
+  }
+
+  QualType SrcRecordTy;
+  QualType DestRecordTy;
+  
+  if (const PointerType *DestPTy = DestTy->getAs<PointerType>()) {
+    SrcRecordTy = SrcTy->castAs<PointerType>()->getPointeeType();
+    DestRecordTy = DestPTy->getPointeeType();
+  } else {
+    SrcRecordTy = SrcTy;
+    DestRecordTy = DestTy->castAs<ReferenceType>()->getPointeeType();
+  }
+
+  assert(SrcRecordTy->isRecordType() && "source type must be a record type!");
+  assert(DestRecordTy->isRecordType() && "dest type must be a record type!");
+
+  llvm::Value *SrcRTTI =
+    CGF.CGM.GetAddrOfRTTIDescriptor(SrcRecordTy.getUnqualifiedType());
+  llvm::Value *DestRTTI =
+    CGF.CGM.GetAddrOfRTTIDescriptor(DestRecordTy.getUnqualifiedType());
+
+  // Compute the offset hint.
+  const CXXRecordDecl *SrcDecl = SrcRecordTy->getAsCXXRecordDecl();
+  const CXXRecordDecl *DestDecl = DestRecordTy->getAsCXXRecordDecl();
+  llvm::Value *OffsetHint =
+    llvm::ConstantInt::get(PtrDiffLTy,
+                           computeOffsetHint(CGF.getContext(), SrcDecl,
+                                             DestDecl).getQuantity());
+
+  // Emit the call to __dynamic_cast.
+  Value = CGF.EmitCastToVoidPtr(Value);
+
+  llvm::Value *args[] = { Value, SrcRTTI, DestRTTI, OffsetHint };
+  Value = CGF.EmitNounwindRuntimeCall(getItaniumDynamicCastFn(CGF), args);
+  Value = CGF.Builder.CreateBitCast(Value, DestLTy);
+
+  /// C++ [expr.dynamic.cast]p9:
+  ///   A failed cast to reference type throws std::bad_cast
+  if (DestTy->isReferenceType()) {
+    llvm::BasicBlock *BadCastBlock = 
+      CGF.createBasicBlock("dynamic_cast.bad_cast");
+
+    llvm::Value *IsNull = CGF.Builder.CreateIsNull(Value);
+    CGF.Builder.CreateCondBr(IsNull, BadCastBlock, CastEnd);
+
+    CGF.EmitBlock(BadCastBlock);
+    EmitBadCastCall(CGF);
+  }
+
+  return Value;
+}
+
 static llvm::Value *EmitDynamicCastToNull(CodeGenFunction &CGF,
                                           QualType DestTy) {
   llvm::Type *DestLTy = CGF.ConvertType(DestTy);
@@ -1679,49 +1908,142 @@
 
   /// C++ [expr.dynamic.cast]p9:
   ///   A failed cast to reference type throws std::bad_cast
-  if (!CGF.CGM.getCXXABI().EmitBadCastCall(CGF))
-    return nullptr;
+  EmitBadCastCall(CGF);
 
   CGF.EmitBlock(CGF.createBasicBlock("dynamic_cast.end"));
   return llvm::UndefValue::get(DestLTy);
 }
 
+namespace {
+struct MSDynamicCastBuilder {
+  MSDynamicCastBuilder(CodeGenFunction &CGF, const CXXDynamicCastExpr *DCE);
+  llvm::Value *emitDynamicCastCall(llvm::Value *Value);
+  llvm::Value *emitDynamicCast(llvm::Value *Value);
+
+  CodeGenFunction &CGF;
+  CGBuilderTy &Builder;
+  llvm::PointerType *Int8PtrTy;
+  QualType SrcTy, DstTy;
+  const CXXRecordDecl *SrcDecl;
+  bool IsPtrCast, IsCastToVoid, IsCastOfNull;
+};
+} // namespace
+
+MSDynamicCastBuilder::MSDynamicCastBuilder(CodeGenFunction &CGF,
+                                           const CXXDynamicCastExpr *DCE)
+    : CGF(CGF), Builder(CGF.Builder), Int8PtrTy(CGF.Int8PtrTy),
+      SrcDecl(nullptr) {
+  DstTy = DCE->getTypeAsWritten();
+  IsPtrCast = DstTy->isPointerType();
+  // Get the PointeeTypes.  After this point the original types are not used.
+  DstTy = IsPtrCast ? DstTy->castAs<PointerType>()->getPointeeType()
+                    : DstTy->castAs<ReferenceType>()->getPointeeType();
+  IsCastToVoid = DstTy->isVoidType();
+  IsCastOfNull = DCE->isAlwaysNull();
+  if (IsCastOfNull)
+    return;
+  SrcTy = DCE->getSubExpr()->getType();
+  SrcTy = IsPtrCast ? SrcTy->castAs<PointerType>()->getPointeeType() : SrcTy;
+  SrcDecl = SrcTy->getAsCXXRecordDecl();
+  // If we don't need a base adjustment, we don't need a SrcDecl so clear it
+  // here.  Later we use the existence of the SrcDecl to determine the need for
+  // a base adjustment.
+  if (CGF.getContext().getASTRecordLayout(SrcDecl).hasExtendableVFPtr())
+    SrcDecl = nullptr;
+}
+
+llvm::Value *MSDynamicCastBuilder::emitDynamicCastCall(llvm::Value *Value) {
+  llvm::IntegerType *Int32Ty = CGF.Int32Ty;
+  llvm::Value *Offset = llvm::ConstantInt::get(Int32Ty, 0);
+  Value = Builder.CreateBitCast(Value, Int8PtrTy);
+  // If we need to perform a base adjustment, do it here.
+  if (SrcDecl) {
+    Offset = getPolymorphicOffset(CGF, SrcDecl, Value);
+    Value = Builder.CreateInBoundsGEP(Value, Offset);
+    Offset = Builder.CreateTrunc(Offset, Int32Ty);
+  }
+  if (IsCastToVoid) {
+    // PVOID __RTCastToVoid(
+    //   PVOID inptr)
+    llvm::Type *ArgTypes[] = {Int8PtrTy};
+    llvm::Constant *Function = CGF.CGM.CreateRuntimeFunction(
+        llvm::FunctionType::get(Int8PtrTy, ArgTypes, false), "__RTCastToVoid");
+    llvm::Value *Args[] = {Value};
+    return CGF.EmitRuntimeCall(Function, Args);
+  }
+  // PVOID __RTDynamicCast(
+  //   PVOID inptr,
+  //   LONG VfDelta,
+  //   PVOID SrcType,
+  //   PVOID TargetType,
+  //   BOOL isReference)
+  llvm::Type *ArgTypes[] = {Int8PtrTy, Int32Ty, Int8PtrTy, Int8PtrTy, Int32Ty};
+  llvm::Constant *Function = CGF.CGM.CreateRuntimeFunction(
+      llvm::FunctionType::get(Int8PtrTy, ArgTypes, false), "__RTDynamicCast");
+  llvm::Value *Args[] = {
+    Value, Offset,
+      CGF.CGM.GetAddrOfRTTIDescriptor(SrcTy.getUnqualifiedType()),
+      CGF.CGM.GetAddrOfRTTIDescriptor(DstTy.getUnqualifiedType()),
+      llvm::ConstantInt::get(Int32Ty, IsPtrCast ? 0 : 1)};
+  return CGF.EmitRuntimeCall(Function, Args);
+}
+
+llvm::Value *MSDynamicCastBuilder::emitDynamicCast(llvm::Value *Value) {
+  // Note about undefined behavior: If the dynamic cast is casting to a
+  // reference type and the input is null, we hit a grey area in the standard.
+  // Here we're interpreting the behavior as undefined.  The effects are the
+  // following:  If the compiler determines that the argument is statically null
+  // or if the argument is dynamically null but does not require base
+  // adjustment, __RTDynamicCast will be called with a null argument and the
+  // isreference bit set.  In this case __RTDynamicCast will throw
+  // std::bad_cast. If the argument is dynamically null and a base adjustment is
+  // required the resulting code will produce an out of bounds memory reference
+  // when trying to read VBTblPtr.  In Itanium mode clang also emits a vtable
+  // load that fails at run time.
+  llvm::PointerType *DstLTy = CGF.ConvertType(DstTy)->getPointerTo();
+  if (IsCastOfNull && IsPtrCast)
+    return Builder.CreateBitCast(Value, DstLTy);
+  if (IsCastOfNull || !IsPtrCast || !SrcDecl)
+    return Builder.CreateBitCast(emitDynamicCastCall(Value), DstLTy);
+  // !IsCastOfNull && IsPtrCast && SrcDecl
+  // In this case we have a pointer that requires a base adjustment.  An
+  // adjustment is only required if the pointer is actually valid so here we
+  // perform a null check before doing the base adjustment and calling
+  // __RTDynamicCast.  In the case that the argument is null we simply return
+  // null without calling __RTDynamicCast.
+  llvm::BasicBlock *EntryBlock = Builder.GetInsertBlock();
+  llvm::BasicBlock *CallBlock = CGF.createBasicBlock("dynamic_cast.valid");
+  llvm::BasicBlock *ExitBlock = CGF.createBasicBlock("dynamic_cast.call");
+  Builder.CreateCondBr(Builder.CreateIsNull(Value), ExitBlock, CallBlock);
+  // Emit the call block and code for it.
+  CGF.EmitBlock(CallBlock);
+  Value = emitDynamicCastCall(Value);
+  // Emit the call block and the phi nodes for it.
+  CGF.EmitBlock(ExitBlock);
+  llvm::PHINode *ValuePHI = Builder.CreatePHI(Int8PtrTy, 2);
+  ValuePHI->addIncoming(Value, CallBlock);
+  ValuePHI->addIncoming(llvm::Constant::getNullValue(Int8PtrTy), EntryBlock);
+  return Builder.CreateBitCast(ValuePHI, DstLTy);
+}
+
 llvm::Value *CodeGenFunction::EmitDynamicCast(llvm::Value *Value,
                                               const CXXDynamicCastExpr *DCE) {
+  if (getTarget().getCXXABI().isMicrosoft()) {
+    MSDynamicCastBuilder Builder(*this, DCE);
+    return Builder.emitDynamicCast(Value);
+  }
+
   QualType DestTy = DCE->getTypeAsWritten();
 
   if (DCE->isAlwaysNull())
-    if (llvm::Value *T = EmitDynamicCastToNull(*this, DestTy))
-      return T;
+    return EmitDynamicCastToNull(*this, DestTy);
 
   QualType SrcTy = DCE->getSubExpr()->getType();
 
-  // C++ [expr.dynamic.cast]p7:
-  //   If T is "pointer to cv void," then the result is a pointer to the most
-  //   derived object pointed to by v.
-  const PointerType *DestPTy = DestTy->getAs<PointerType>();
-
-  bool isDynamicCastToVoid;
-  QualType SrcRecordTy;
-  QualType DestRecordTy;
-  if (DestPTy) {
-    isDynamicCastToVoid = DestPTy->getPointeeType()->isVoidType();
-    SrcRecordTy = SrcTy->castAs<PointerType>()->getPointeeType();
-    DestRecordTy = DestPTy->getPointeeType();
-  } else {
-    isDynamicCastToVoid = false;
-    SrcRecordTy = SrcTy;
-    DestRecordTy = DestTy->castAs<ReferenceType>()->getPointeeType();
-  }
-
-  assert(SrcRecordTy->isRecordType() && "source type must be a record type!");
-
   // C++ [expr.dynamic.cast]p4: 
   //   If the value of v is a null pointer value in the pointer case, the result
   //   is the null pointer value of type T.
-  bool ShouldNullCheckSrcValue =
-      CGM.getCXXABI().shouldDynamicCastCallBeNullChecked(SrcTy->isPointerType(),
-                                                         SrcRecordTy);
+  bool ShouldNullCheckSrcValue = SrcTy->isPointerType();
 
   llvm::BasicBlock *CastNull = nullptr;
   llvm::BasicBlock *CastNotNull = nullptr;
@@ -1736,15 +2058,7 @@
     EmitBlock(CastNotNull);
   }
 
-  if (isDynamicCastToVoid) {
-    Value = CGM.getCXXABI().EmitDynamicCastToVoid(*this, Value, SrcRecordTy,
-                                                  DestTy);
-  } else {
-    assert(DestRecordTy->isRecordType() &&
-           "destination type must be a record type!");
-    Value = CGM.getCXXABI().EmitDynamicCastCall(*this, Value, SrcRecordTy,
-                                                DestTy, DestRecordTy, CastEnd);
-  }
+  Value = EmitItaniumDynamicCastCall(*this, Value, SrcTy, DestTy, CastEnd);
 
   if (ShouldNullCheckSrcValue) {
     EmitBranch(CastEnd);