r211402 - CodeGen: Refactor dynamic_cast and typeid

David Majnemer david.majnemer at gmail.com
Fri Jun 20 14:11:01 PDT 2014


Author: majnemer
Date: Fri Jun 20 16:11:00 2014
New Revision: 211402

URL: http://llvm.org/viewvc/llvm-project?rev=211402&view=rev
Log:
CodeGen: Refactor dynamic_cast and typeid

This refactors the emission of dynamic_cast and typeid expressions so
that ABI specific knowledge lives in appropriate places.  There are
quite a few benefits for having the two implementations share a common
core like sharing logic for optimization opportunities.

While we are at it, clean up the tests.

Modified:
    cfe/trunk/lib/CodeGen/CGCXXABI.h
    cfe/trunk/lib/CodeGen/CGExprCXX.cpp
    cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
    cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
    cfe/trunk/test/CodeGenCXX/microsoft-abi-dynamic-cast.cpp
    cfe/trunk/test/CodeGenCXX/microsoft-abi-typeid.cpp

Modified: cfe/trunk/lib/CodeGen/CGCXXABI.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXXABI.h?rev=211402&r1=211401&r2=211402&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCXXABI.h (original)
+++ cfe/trunk/lib/CodeGen/CGCXXABI.h Fri Jun 20 16:11:00 2014
@@ -207,6 +207,28 @@ public:
                                               llvm::Value *ptr,
                                               QualType type) = 0;
 
+  virtual bool shouldTypeidBeNullChecked(bool IsDeref,
+                                         QualType SrcRecordTy) = 0;
+  virtual void EmitBadTypeidCall(CodeGenFunction &CGF) = 0;
+  virtual llvm::Value *EmitTypeid(CodeGenFunction &CGF, QualType SrcRecordTy,
+                                  llvm::Value *ThisPtr,
+                                  llvm::Type *StdTypeInfoPtrTy) = 0;
+
+  virtual bool shouldDynamicCastCallBeNullChecked(bool SrcIsPtr,
+                                                  QualType SrcRecordTy) = 0;
+
+  virtual llvm::Value *
+  EmitDynamicCastCall(CodeGenFunction &CGF, llvm::Value *Value,
+                      QualType SrcRecordTy, QualType DestTy,
+                      QualType DestRecordTy, llvm::BasicBlock *CastEnd) = 0;
+
+  virtual llvm::Value *EmitDynamicCastToVoid(CodeGenFunction &CGF,
+                                             llvm::Value *Value,
+                                             QualType SrcRecordTy,
+                                             QualType DestTy) = 0;
+
+  virtual bool EmitBadCastCall(CodeGenFunction &CGF) = 0;
+
   virtual llvm::Value *GetVirtualBaseClassOffset(CodeGenFunction &CGF,
                                                  llvm::Value *This,
                                                  const CXXRecordDecl *ClassDecl,

Modified: cfe/trunk/lib/CodeGen/CGExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprCXX.cpp?rev=211402&r1=211401&r2=211402&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprCXX.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprCXX.cpp Fri Jun 20 16:11:00 2014
@@ -1615,98 +1615,36 @@ void CodeGenFunction::EmitCXXDeleteExpr(
   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.
-  if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(E->IgnoreParens())) {
-    if (UO->getOpcode() == UO_Deref) {
-      llvm::BasicBlock *BadTypeidBlock = 
+  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 =
         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);
-      EmitBadTypeidCall(CGF);
-      CGF.EmitBlock(EndBlock);
-    }
+    CGF.EmitBlock(BadTypeidBlock);
+    CGF.CGM.getCXXABI().EmitBadTypeidCall(CGF);
+    CGF.EmitBlock(EndBlock);
   }
 
-  llvm::Value *Value = CGF.GetVTablePtr(ThisPtr, 
-                                        StdTypeInfoPtrTy->getPointerTo());
-
-  // Load the type info.
-  Value = CGF.Builder.CreateConstInBoundsGEP1_64(Value, -1ULL);
-  return CGF.Builder.CreateLoad(Value);
+  return CGF.CGM.getCXXABI().EmitTypeid(CGF, SrcRecordTy, ThisPtr,
+                                        StdTypeInfoPtrTy);
 }
 
 llvm::Value *CodeGenFunction::EmitCXXTypeidExpr(const CXXTypeidExpr *E) {
@@ -1733,173 +1671,6 @@ llvm::Value *CodeGenFunction::EmitCXXTyp
                                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);
@@ -1908,142 +1679,49 @@ static llvm::Value *EmitDynamicCastToNul
 
   /// C++ [expr.dynamic.cast]p9:
   ///   A failed cast to reference type throws std::bad_cast
-  EmitBadCastCall(CGF);
+  if (!CGF.CGM.getCXXABI().EmitBadCastCall(CGF))
+    return nullptr;
 
   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())
-    return EmitDynamicCastToNull(*this, DestTy);
+    if (llvm::Value *T = EmitDynamicCastToNull(*this, DestTy))
+      return T;
 
   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 = SrcTy->isPointerType();
+  bool ShouldNullCheckSrcValue =
+      CGM.getCXXABI().shouldDynamicCastCallBeNullChecked(SrcTy->isPointerType(),
+                                                         SrcRecordTy);
 
   llvm::BasicBlock *CastNull = nullptr;
   llvm::BasicBlock *CastNotNull = nullptr;
@@ -2058,7 +1736,15 @@ llvm::Value *CodeGenFunction::EmitDynami
     EmitBlock(CastNotNull);
   }
 
-  Value = EmitItaniumDynamicCastCall(*this, Value, SrcTy, DestTy, CastEnd);
+  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);
+  }
 
   if (ShouldNullCheckSrcValue) {
     EmitBranch(CastEnd);

Modified: cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp?rev=211402&r1=211401&r2=211402&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp (original)
+++ cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp Fri Jun 20 16:11:00 2014
@@ -25,6 +25,7 @@
 #include "CodeGenModule.h"
 #include "clang/AST/Mangle.h"
 #include "clang/AST/Type.h"
+#include "llvm/IR/CallSite.h"
 #include "llvm/IR/DataLayout.h"
 #include "llvm/IR/Intrinsics.h"
 #include "llvm/IR/Value.h"
@@ -108,6 +109,26 @@ public:
   llvm::Value *adjustToCompleteObject(CodeGenFunction &CGF, llvm::Value *ptr,
                                       QualType type) override;
 
+  bool shouldTypeidBeNullChecked(bool IsDeref, QualType SrcRecordTy) override;
+  void EmitBadTypeidCall(CodeGenFunction &CGF) override;
+  llvm::Value *EmitTypeid(CodeGenFunction &CGF, QualType SrcRecordTy,
+                          llvm::Value *ThisPtr,
+                          llvm::Type *StdTypeInfoPtrTy) override;
+
+  bool shouldDynamicCastCallBeNullChecked(bool SrcIsPtr,
+                                          QualType SrcRecordTy) override;
+
+  llvm::Value *EmitDynamicCastCall(CodeGenFunction &CGF, llvm::Value *Value,
+                                   QualType SrcRecordTy, QualType DestTy,
+                                   QualType DestRecordTy,
+                                   llvm::BasicBlock *CastEnd) override;
+
+  llvm::Value *EmitDynamicCastToVoid(CodeGenFunction &CGF, llvm::Value *Value,
+                                     QualType SrcRecordTy,
+                                     QualType DestTy) override;
+
+  bool EmitBadCastCall(CodeGenFunction &CGF) override;
+
   llvm::Value *
     GetVirtualBaseClassOffset(CodeGenFunction &CGF, llvm::Value *This,
                               const CXXRecordDecl *ClassDecl,
@@ -800,6 +821,194 @@ llvm::Value *ItaniumCXXABI::adjustToComp
   return CGF.Builder.CreateInBoundsGEP(ptr, offset);
 }
 
+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");
+}
+
+/// \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::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");
+}
+
+bool ItaniumCXXABI::shouldTypeidBeNullChecked(bool IsDeref,
+                                              QualType SrcRecordTy) {
+  return IsDeref;
+}
+
+void ItaniumCXXABI::EmitBadTypeidCall(CodeGenFunction &CGF) {
+  llvm::Value *Fn = getBadTypeidFn(CGF);
+  CGF.EmitRuntimeCallOrInvoke(Fn).setDoesNotReturn();
+  CGF.Builder.CreateUnreachable();
+}
+
+llvm::Value *ItaniumCXXABI::EmitTypeid(CodeGenFunction &CGF,
+                                       QualType SrcRecordTy,
+                                       llvm::Value *ThisPtr,
+                                       llvm::Type *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);
+}
+
+bool ItaniumCXXABI::shouldDynamicCastCallBeNullChecked(bool SrcIsPtr,
+                                                       QualType SrcRecordTy) {
+  return SrcIsPtr;
+}
+
+llvm::Value *ItaniumCXXABI::EmitDynamicCastCall(
+    CodeGenFunction &CGF, llvm::Value *Value, QualType SrcRecordTy,
+    QualType DestTy, QualType DestRecordTy, llvm::BasicBlock *CastEnd) {
+  llvm::Type *PtrDiffLTy =
+      CGF.ConvertType(CGF.getContext().getPointerDiffType());
+  llvm::Type *DestLTy = CGF.ConvertType(DestTy);
+
+  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;
+}
+
+llvm::Value *ItaniumCXXABI::EmitDynamicCastToVoid(CodeGenFunction &CGF,
+                                                  llvm::Value *Value,
+                                                  QualType SrcRecordTy,
+                                                  QualType DestTy) {
+  llvm::Type *PtrDiffLTy =
+      CGF.ConvertType(CGF.getContext().getPointerDiffType());
+  llvm::Type *DestLTy = CGF.ConvertType(DestTy);
+
+  // 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);
+}
+
+bool ItaniumCXXABI::EmitBadCastCall(CodeGenFunction &CGF) {
+  llvm::Value *Fn = getBadCastFn(CGF);
+  CGF.EmitRuntimeCallOrInvoke(Fn).setDoesNotReturn();
+  CGF.Builder.CreateUnreachable();
+  return true;
+}
+
 llvm::Value *
 ItaniumCXXABI::GetVirtualBaseClassOffset(CodeGenFunction &CGF,
                                          llvm::Value *This,

Modified: cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp?rev=211402&r1=211401&r2=211402&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp (original)
+++ cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp Fri Jun 20 16:11:00 2014
@@ -21,6 +21,7 @@
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/VTableBuilder.h"
 #include "llvm/ADT/StringSet.h"
+#include "llvm/IR/CallSite.h"
 
 using namespace clang;
 using namespace CodeGen;
@@ -56,6 +57,26 @@ public:
                                       llvm::Value *ptr,
                                       QualType type) override;
 
+  bool shouldTypeidBeNullChecked(bool IsDeref, QualType SrcRecordTy) override;
+  void EmitBadTypeidCall(CodeGenFunction &CGF) override;
+  llvm::Value *EmitTypeid(CodeGenFunction &CGF, QualType SrcRecordTy,
+                          llvm::Value *ThisPtr,
+                          llvm::Type *StdTypeInfoPtrTy) override;
+
+  bool shouldDynamicCastCallBeNullChecked(bool SrcIsPtr,
+                                          QualType SrcRecordTy) override;
+
+  llvm::Value *EmitDynamicCastCall(CodeGenFunction &CGF, llvm::Value *Value,
+                                   QualType SrcRecordTy, QualType DestTy,
+                                   QualType DestRecordTy,
+                                   llvm::BasicBlock *CastEnd) override;
+
+  llvm::Value *EmitDynamicCastToVoid(CodeGenFunction &CGF, llvm::Value *Value,
+                                     QualType SrcRecordTy,
+                                     QualType DestTy) override;
+
+  bool EmitBadCastCall(CodeGenFunction &CGF) override;
+
   llvm::Value *
   GetVirtualBaseClassOffset(CodeGenFunction &CGF, llvm::Value *This,
                             const CXXRecordDecl *ClassDecl,
@@ -469,6 +490,132 @@ llvm::Value *MicrosoftCXXABI::adjustToCo
   return ptr;
 }
 
+/// \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 std::pair<llvm::Value *, llvm::Value *>
+performBaseAdjustment(CodeGenFunction &CGF, llvm::Value *Value,
+                      QualType SrcRecordTy) {
+  Value = CGF.Builder.CreateBitCast(Value, CGF.Int8PtrTy);
+  const CXXRecordDecl *SrcDecl = SrcRecordTy->getAsCXXRecordDecl();
+
+  if (CGF.getContext().getASTRecordLayout(SrcDecl).hasExtendableVFPtr())
+    return std::make_pair(Value, llvm::ConstantInt::get(CGF.Int32Ty, 0));
+
+  // Perform a base adjustment.
+  llvm::Value *Offset = getPolymorphicOffset(CGF, SrcDecl, Value);
+  Value = CGF.Builder.CreateInBoundsGEP(Value, Offset);
+  Offset = CGF.Builder.CreateTrunc(Offset, CGF.Int32Ty);
+  return std::make_pair(Value, Offset);
+}
+
+bool MicrosoftCXXABI::shouldTypeidBeNullChecked(bool IsDeref,
+                                                QualType SrcRecordTy) {
+  const CXXRecordDecl *SrcDecl = SrcRecordTy->getAsCXXRecordDecl();
+  return IsDeref &&
+         !CGM.getContext().getASTRecordLayout(SrcDecl).hasExtendableVFPtr();
+}
+
+static llvm::CallSite emitRTtypeidCall(CodeGenFunction &CGF,
+                                       llvm::Value *Argument) {
+  llvm::Type *ArgTypes[] = {CGF.Int8PtrTy};
+  llvm::FunctionType *FTy =
+      llvm::FunctionType::get(CGF.Int8PtrTy, ArgTypes, false);
+  llvm::Value *Args[] = {Argument};
+  llvm::Constant *Fn = CGF.CGM.CreateRuntimeFunction(FTy, "__RTtypeid");
+  return CGF.EmitRuntimeCallOrInvoke(Fn, Args);
+}
+
+void MicrosoftCXXABI::EmitBadTypeidCall(CodeGenFunction &CGF) {
+  llvm::CallSite Call =
+      emitRTtypeidCall(CGF, llvm::Constant::getNullValue(CGM.VoidPtrTy));
+  Call.setDoesNotReturn();
+  CGF.Builder.CreateUnreachable();
+}
+
+llvm::Value *MicrosoftCXXABI::EmitTypeid(CodeGenFunction &CGF,
+                                         QualType SrcRecordTy,
+                                         llvm::Value *ThisPtr,
+                                         llvm::Type *StdTypeInfoPtrTy) {
+  const CXXRecordDecl *RD = SrcRecordTy->getAsCXXRecordDecl();
+  llvm::Value *CastPtr = CGF.Builder.CreateBitCast(ThisPtr, CGF.Int8PtrTy);
+  llvm::Value *AdjustedThisPtr = CGF.Builder.CreateInBoundsGEP(
+      CastPtr, getPolymorphicOffset(CGF, RD, CastPtr));
+  return CGF.Builder.CreateBitCast(
+      emitRTtypeidCall(CGF, AdjustedThisPtr).getInstruction(),
+      StdTypeInfoPtrTy);
+}
+
+bool MicrosoftCXXABI::shouldDynamicCastCallBeNullChecked(bool SrcIsPtr,
+                                                         QualType SrcRecordTy) {
+  const CXXRecordDecl *SrcDecl = SrcRecordTy->getAsCXXRecordDecl();
+  return SrcIsPtr &&
+         !CGM.getContext().getASTRecordLayout(SrcDecl).hasExtendableVFPtr();
+}
+
+llvm::Value *MicrosoftCXXABI::EmitDynamicCastCall(
+    CodeGenFunction &CGF, llvm::Value *Value, QualType SrcRecordTy,
+    QualType DestTy, QualType DestRecordTy, llvm::BasicBlock *CastEnd) {
+  llvm::Type *DestLTy = CGF.ConvertType(DestTy);
+
+  llvm::Value *SrcRTTI =
+      CGF.CGM.GetAddrOfRTTIDescriptor(SrcRecordTy.getUnqualifiedType());
+  llvm::Value *DestRTTI =
+      CGF.CGM.GetAddrOfRTTIDescriptor(DestRecordTy.getUnqualifiedType());
+
+  llvm::Value *Offset;
+  std::tie(Value, Offset) = performBaseAdjustment(CGF, Value, SrcRecordTy);
+
+  // PVOID __RTDynamicCast(
+  //   PVOID inptr,
+  //   LONG VfDelta,
+  //   PVOID SrcType,
+  //   PVOID TargetType,
+  //   BOOL isReference)
+  llvm::Type *ArgTypes[] = {CGF.Int8PtrTy, CGF.Int32Ty, CGF.Int8PtrTy,
+                            CGF.Int8PtrTy, CGF.Int32Ty};
+  llvm::Constant *Function = CGF.CGM.CreateRuntimeFunction(
+      llvm::FunctionType::get(CGF.Int8PtrTy, ArgTypes, false),
+      "__RTDynamicCast");
+  llvm::Value *Args[] = {
+      Value, Offset, SrcRTTI, DestRTTI,
+      llvm::ConstantInt::get(CGF.Int32Ty, DestTy->isReferenceType())};
+  Value = CGF.EmitRuntimeCallOrInvoke(Function, Args).getInstruction();
+  return CGF.Builder.CreateBitCast(Value, DestLTy);
+}
+
+llvm::Value *
+MicrosoftCXXABI::EmitDynamicCastToVoid(CodeGenFunction &CGF, llvm::Value *Value,
+                                       QualType SrcRecordTy,
+                                       QualType DestTy) {
+  llvm::Value *Offset;
+  std::tie(Value, Offset) = performBaseAdjustment(CGF, Value, SrcRecordTy);
+
+  // PVOID __RTCastToVoid(
+  //   PVOID inptr)
+  llvm::Type *ArgTypes[] = {CGF.Int8PtrTy};
+  llvm::Constant *Function = CGF.CGM.CreateRuntimeFunction(
+      llvm::FunctionType::get(CGF.Int8PtrTy, ArgTypes, false),
+      "__RTCastToVoid");
+  llvm::Value *Args[] = {Value};
+  return CGF.EmitRuntimeCall(Function, Args);
+}
+
+bool MicrosoftCXXABI::EmitBadCastCall(CodeGenFunction &CGF) {
+  return false;
+}
+
 llvm::Value *
 MicrosoftCXXABI::GetVirtualBaseClassOffset(CodeGenFunction &CGF,
                                            llvm::Value *This,

Modified: cfe/trunk/test/CodeGenCXX/microsoft-abi-dynamic-cast.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-dynamic-cast.cpp?rev=211402&r1=211401&r2=211402&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/microsoft-abi-dynamic-cast.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/microsoft-abi-dynamic-cast.cpp Fri Jun 20 16:11:00 2014
@@ -1,158 +1,143 @@
-// RUN: %clang_cc1 -emit-llvm -O2 -optzns -o - -triple=i386-pc-win32 2>/dev/null %s | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -O1 -o - -triple=i386-pc-win32 %s | FileCheck %s
 // REQUIRES: asserts
 
 struct S { char a; };
-struct V { virtual void f(){} };
+struct V { virtual void f(); };
 struct A : virtual V {};
 struct B : S, virtual V {};
 struct T {};
 
 T* test0() { return dynamic_cast<T*>((B*)0); }
-// CHECK: define noalias %struct.T* @"\01?test0@@YAPAUT@@XZ"() #0 {
-// CHECK-NEXT: entry:
-// CHECK-NEXT:   ret %struct.T* null
-// CHECK-NEXT: }
+// CHECK-LABEL: define noalias %struct.T* @"\01?test0@@YAPAUT@@XZ"()
+// CHECK:   ret %struct.T* null
 
 T* test1(V* x) { return &dynamic_cast<T&>(*x); }
-// CHECK: define %struct.T* @"\01?test1@@YAPAUT@@PAUV@@@Z"(%struct.V* %x) #1 {
-// CHECK-NEXT: entry:
-// CHECK-NEXT:   %0 = bitcast %struct.V* %x to i8*
-// CHECK-NEXT:   %1 = tail call i8* @__RTDynamicCast(i8* %0, i32 0, i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUV@@@8" to i8*), i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUT@@@8" to i8*), i32 1) #2
-// CHECK-NEXT:   %2 = bitcast i8* %1 to %struct.T*
-// CHECK-NEXT:   ret %struct.T* %2
-// CHECK-NEXT: }
+// CHECK-LABEL: define %struct.T* @"\01?test1@@YAPAUT@@PAUV@@@Z"(%struct.V* %x)
+// CHECK:        [[CAST:%.*]] = bitcast %struct.V* %x to i8*
+// CHECK-NEXT:   [[CALL:%.*]] = tail call i8* @__RTDynamicCast(i8* [[CAST]], i32 0, i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUV@@@8" to i8*), i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUT@@@8" to i8*), i32 1)
+// CHECK-NEXT:   [[RET:%.*]] = bitcast i8* [[CALL]] to %struct.T*
+// CHECK-NEXT:   ret %struct.T* [[RET]]
 
 T* test2(A* x) { return &dynamic_cast<T&>(*x); }
-// CHECK: define %struct.T* @"\01?test2@@YAPAUT@@PAUA@@@Z"(%struct.A* %x) #1 {
-// CHECK-NEXT: entry:
-// CHECK-NEXT:   %0 = bitcast %struct.A* %x to i8*
-// CHECK-NEXT:   %1 = bitcast %struct.A* %x to i8**
-// CHECK-NEXT:   %vbtable = load i8** %1, align 4
-// CHECK-NEXT:   %2 = getelementptr inbounds i8* %vbtable, i32 4
-// CHECK-NEXT:   %3 = bitcast i8* %2 to i32*
-// CHECK-NEXT:   %vbase_offs = load i32* %3, align 4
-// CHECK-NEXT:   %4 = getelementptr inbounds i8* %0, i32 %vbase_offs
-// CHECK-NEXT:   %5 = tail call i8* @__RTDynamicCast(i8* %4, i32 %vbase_offs, i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUA@@@8" to i8*), i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUT@@@8" to i8*), i32 1) #2
-// CHECK-NEXT:   %6 = bitcast i8* %5 to %struct.T*
-// CHECK-NEXT:   ret %struct.T* %6
-// CHECK-NEXT: }
+// CHECK-LABEL: define %struct.T* @"\01?test2@@YAPAUT@@PAUA@@@Z"(%struct.A* %x)
+// CHECK:        [[CAST:%.*]] = bitcast %struct.A* %x to i8*
+// CHECK-NEXT:   [[BITCAST:%.*]] = bitcast %struct.A* %x to i8**
+// CHECK-NEXT:   [[VBTBL:%.*]] = load i8** [[BITCAST]], align 4
+// CHECK-NEXT:   [[VBOFFP:%.*]] = getelementptr inbounds i8* [[VBTBL]], i32 4
+// CHECK-NEXT:   [[VBOFFPCAST:%.*]] = bitcast i8* [[VBOFFP]] to i32*
+// CHECK-NEXT:   [[VBOFFS:%.*]] = load i32* [[VBOFFPCAST]], align 4
+// CHECK-NEXT:   [[ADJ:%.*]] = getelementptr inbounds i8* [[CAST]], i32 [[VBOFFS]]
+// CHECK-NEXT:   [[CALL:%.*]] = tail call i8* @__RTDynamicCast(i8* [[ADJ]], i32 [[VBOFFS]], i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUA@@@8" to i8*), i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUT@@@8" to i8*), i32 1)
+// CHECK-NEXT:   [[RET:%.*]] = bitcast i8* [[CALL]] to %struct.T*
+// CHECK-NEXT:   ret %struct.T* [[RET]]
 
 T* test3(B* x) { return &dynamic_cast<T&>(*x); }
-// CHECK: define %struct.T* @"\01?test3@@YAPAUT@@PAUB@@@Z"(%struct.B* %x) #1 {
-// CHECK-NEXT: entry:
-// CHECK-NEXT:   %0 = getelementptr inbounds %struct.B* %x, i32 0, i32 0, i32 0
-// CHECK-NEXT:   %vbptr = getelementptr inbounds i8* %0, i32 4
-// CHECK-NEXT:   %1 = bitcast i8* %vbptr to i8**
-// CHECK-NEXT:   %vbtable = load i8** %1, align 4
-// CHECK-NEXT:   %2 = getelementptr inbounds i8* %vbtable, i32 4
-// CHECK-NEXT:   %3 = bitcast i8* %2 to i32*
-// CHECK-NEXT:   %vbase_offs = load i32* %3, align 4
-// CHECK-NEXT:   %4 = add nsw i32 %vbase_offs, 4
-// CHECK-NEXT:   %5 = getelementptr inbounds i8* %0, i32 %4
-// CHECK-NEXT:   %6 = tail call i8* @__RTDynamicCast(i8* %5, i32 %4, i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUB@@@8" to i8*), i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUT@@@8" to i8*), i32 1) #2
-// CHECK-NEXT:   %7 = bitcast i8* %6 to %struct.T*
-// CHECK-NEXT:   ret %struct.T* %7
-// CHECK-NEXT: }
+// CHECK-LABEL: define %struct.T* @"\01?test3@@YAPAUT@@PAUB@@@Z"(%struct.B* %x)
+// CHECK:        [[VOIDP:%.*]] = getelementptr inbounds %struct.B* %x, i32 0, i32 0, i32 0
+// CHECK-NEXT:   [[VBPTR:%.*]] = getelementptr inbounds i8* [[VOIDP]], i32 4
+// CHECK-NEXT:   [[BITCAST:%.*]] = bitcast i8* [[VBPTR:%.*]] to i8**
+// CHECK-NEXT:   [[VBTBL:%.*]] = load i8** [[BITCAST]], align 4
+// CHECK-NEXT:   [[VBOFFP:%.*]] = getelementptr inbounds i8* [[VBTBL]], i32 4
+// CHECK-NEXT:   [[VBOFFPCAST:%.*]] = bitcast i8* [[VBOFFP]] to i32*
+// CHECK-NEXT:   [[VBOFFS:%.*]] = load i32* [[VBOFFPCAST]], align 4
+// CHECK-NEXT:   [[DELTA:%.*]] = add nsw i32 [[VBOFFS]], 4
+// CHECK-NEXT:   [[ADJ:%.*]] = getelementptr inbounds i8* [[VOIDP]], i32 [[DELTA]]
+// CHECK-NEXT:   [[CALL:%.*]] = tail call i8* @__RTDynamicCast(i8* [[ADJ]], i32 [[DELTA]], i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUB@@@8" to i8*), i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUT@@@8" to i8*), i32 1)
+// CHECK-NEXT:   [[RET:%.*]] = bitcast i8* [[CALL]] to %struct.T*
+// CHECK-NEXT:   ret %struct.T* [[RET]]
 
 T* test4(V* x) { return dynamic_cast<T*>(x); }
-// CHECK: define %struct.T* @"\01?test4@@YAPAUT@@PAUV@@@Z"(%struct.V* %x) #1 {
-// CHECK-NEXT: entry:
-// CHECK-NEXT:   %0 = bitcast %struct.V* %x to i8*
-// CHECK-NEXT:   %1 = tail call i8* @__RTDynamicCast(i8* %0, i32 0, i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUV@@@8" to i8*), i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUT@@@8" to i8*), i32 0) #2
-// CHECK-NEXT:   %2 = bitcast i8* %1 to %struct.T*
-// CHECK-NEXT:   ret %struct.T* %2
-// CHECK-NEXT: }
+// CHECK-LABEL: define %struct.T* @"\01?test4@@YAPAUT@@PAUV@@@Z"(%struct.V* %x)
+// CHECK:        [[CAST:%.*]] = bitcast %struct.V* %x to i8*
+// CHECK-NEXT:   [[CALL:%.*]] = tail call i8* @__RTDynamicCast(i8* [[CAST]], i32 0, i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUV@@@8" to i8*), i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUT@@@8" to i8*), i32 0)
+// CHECK-NEXT:   [[RET:%.*]] = bitcast i8* [[CALL]] to %struct.T*
+// CHECK-NEXT:   ret %struct.T* [[RET]]
 
 T* test5(A* x) { return dynamic_cast<T*>(x); }
-// CHECK: define %struct.T* @"\01?test5@@YAPAUT@@PAUA@@@Z"(%struct.A* %x) #1 {
-// CHECK-NEXT: entry:
-// CHECK-NEXT:   %0 = icmp eq %struct.A* %x, null
-// CHECK-NEXT:   br i1 %0, label %dynamic_cast.call, label %dynamic_cast.valid
-// CHECK: dynamic_cast.valid:                               ; preds = %entry
-// CHECK-NEXT:   %1 = bitcast %struct.A* %x to i8*
-// CHECK-NEXT:   %2 = bitcast %struct.A* %x to i8**
-// CHECK-NEXT:   %vbtable = load i8** %2, align 4
-// CHECK-NEXT:   %3 = getelementptr inbounds i8* %vbtable, i32 4
-// CHECK-NEXT:   %4 = bitcast i8* %3 to i32*
-// CHECK-NEXT:   %vbase_offs = load i32* %4, align 4
-// CHECK-NEXT:   %5 = getelementptr inbounds i8* %1, i32 %vbase_offs
-// CHECK-NEXT:   %6 = tail call i8* @__RTDynamicCast(i8* %5, i32 %vbase_offs, i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUA@@@8" to i8*), i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUT@@@8" to i8*), i32 0) #2
-// CHECK-NEXT:   %phitmp = bitcast i8* %6 to %struct.T*
-// CHECK-NEXT:   br label %dynamic_cast.call
-// CHECK: dynamic_cast.call:                                ; preds = %dynamic_cast.valid, %entry
-// CHECK-NEXT:   %7 = phi %struct.T* [ %phitmp, %dynamic_cast.valid ], [ null, %entry ]
-// CHECK-NEXT:   ret %struct.T* %7
-// CHECK-NEXT: }
+// CHECK-LABEL: define %struct.T* @"\01?test5@@YAPAUT@@PAUA@@@Z"(%struct.A* %x)
+// CHECK-NEXT: [[ENTRY:.*]]:
+// CHECK-NEXT:   [[CHECK:%.*]] = icmp eq %struct.A* %x, null
+// CHECK-NEXT:   br i1 [[CHECK]], label %dynamic_cast.end, label %dynamic_cast.notnull
+// CHECK-LABEL: dynamic_cast.notnull:
+// CHECK-NEXT:   [[VOIDP:%.*]] = bitcast %struct.A* %x to i8*
+// CHECK-NEXT:   [[BITCAST:%.*]] = bitcast %struct.A* %x to i8**
+// CHECK-NEXT:   [[VBTBL:%.*]] = load i8** [[BITCAST]], align 4
+// CHECK-NEXT:   [[VBOFFP:%.*]] = getelementptr inbounds i8* [[VBTBL]], i32 4
+// CHECK-NEXT:   [[VBOFFPCAST:%.*]] = bitcast i8* [[VBOFFP]] to i32*
+// CHECK-NEXT:   [[VBOFFS:%.*]] = load i32* [[VBOFFPCAST:%.*]], align 4
+// CHECK-NEXT:   [[ADJ:%.*]] = getelementptr inbounds i8* [[VOIDP]], i32 [[VBOFFS]]
+// CHECK-NEXT:   [[CALL:%.*]] = tail call i8* @__RTDynamicCast(i8* [[ADJ]], i32 [[VBOFFS]], i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUA@@@8" to i8*), i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUT@@@8" to i8*), i32 0)
+// CHECK-NEXT:   [[RES:%.*]] = bitcast i8* [[CALL]] to %struct.T*
+// CHECK-NEXT:   br label %dynamic_cast.end
+// CHECK-LABEL: dynamic_cast.end:
+// CHECK-NEXT:   [[RET:%.*]] = phi %struct.T* [ [[RES]], %dynamic_cast.notnull ], [ null, %[[ENTRY]] ]
+// CHECK-NEXT:   ret %struct.T* [[RET]]
 
 T* test6(B* x) { return dynamic_cast<T*>(x); }
-// CHECK: define %struct.T* @"\01?test6@@YAPAUT@@PAUB@@@Z"(%struct.B* %x) #1 {
-// CHECK-NEXT: entry:
-// CHECK-NEXT:   %0 = icmp eq %struct.B* %x, null
-// CHECK-NEXT:   br i1 %0, label %dynamic_cast.call, label %dynamic_cast.valid
-// CHECK: dynamic_cast.valid:                               ; preds = %entry
-// CHECK-NEXT:   %1 = getelementptr inbounds %struct.B* %x, i32 0, i32 0, i32 0
-// CHECK-NEXT:   %vbptr = getelementptr inbounds i8* %1, i32 4
-// CHECK-NEXT:   %2 = bitcast i8* %vbptr to i8**
-// CHECK-NEXT:   %vbtable = load i8** %2, align 4
-// CHECK-NEXT:   %3 = getelementptr inbounds i8* %vbtable, i32 4
-// CHECK-NEXT:   %4 = bitcast i8* %3 to i32*
-// CHECK-NEXT:   %vbase_offs = load i32* %4, align 4
-// CHECK-NEXT:   %5 = add nsw i32 %vbase_offs, 4
-// CHECK-NEXT:   %6 = getelementptr inbounds i8* %1, i32 %5
-// CHECK-NEXT:   %7 = tail call i8* @__RTDynamicCast(i8* %6, i32 %5, i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUB@@@8" to i8*), i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUT@@@8" to i8*), i32 0) #2
-// CHECK-NEXT:   %phitmp = bitcast i8* %7 to %struct.T*
-// CHECK-NEXT:   br label %dynamic_cast.call
-// CHECK: dynamic_cast.call:                                ; preds = %dynamic_cast.valid, %entry
-// CHECK-NEXT:   %8 = phi %struct.T* [ %phitmp, %dynamic_cast.valid ], [ null, %entry ]
-// CHECK-NEXT:   ret %struct.T* %8
-// CHECK-NEXT: }
+// CHECK-LABEL: define %struct.T* @"\01?test6@@YAPAUT@@PAUB@@@Z"(%struct.B* %x)
+// CHECK-NEXT: [[ENTRY:.*]]:
+// CHECK-NEXT:   [[CHECK:%.*]] = icmp eq %struct.B* %x, null
+// CHECK-NEXT:   br i1 [[CHECK]], label %dynamic_cast.end, label %dynamic_cast.notnull
+// CHECK-LABEL: dynamic_cast.notnull:
+// CHECK-NEXT:   [[CAST:%.*]] = getelementptr inbounds %struct.B* %x, i32 0, i32 0, i32 0
+// CHECK-NEXT:   [[VBPTR:%.*]] = getelementptr inbounds i8* [[CAST]], i32 4
+// CHECK-NEXT:   [[BITCAST]] = bitcast i8* [[VBPTR]] to i8**
+// CHECK-NEXT:   [[VBTBL:%.*]] = load i8** [[BITCAST]], align 4
+// CHECK-NEXT:   [[VBOFFP:%.*]] = getelementptr inbounds i8* [[VBTBL]], i32 4
+// CHECK-NEXT:   [[VBOFFPCAST:%.*]] = bitcast i8* [[VBOFFP]] to i32*
+// CHECK-NEXT:   [[VBOFFS:%.*]] = load i32* [[VBOFFPCAST:%.*]], align 4
+// CHECK-NEXT:   [[DELTA:%.*]] = add nsw i32 [[VBOFFS]], 4
+// CHECK-NEXT:   [[ADJ:%.*]] = getelementptr inbounds i8* [[CAST]], i32 [[DELTA]]
+// CHECK-NEXT:   [[CALL:%.*]] = tail call i8* @__RTDynamicCast(i8* [[ADJ]], i32 [[DELTA]], i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUB@@@8" to i8*), i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUT@@@8" to i8*), i32 0)
+// CHECK-NEXT:   [[RES:%.*]] = bitcast i8* [[CALL]] to %struct.T*
+// CHECK-NEXT:   br label %dynamic_cast.end
+// CHECK-LABEL: dynamic_cast.end:
+// CHECK-NEXT:   [[RET:%.*]] = phi %struct.T* [ [[RES]], %dynamic_cast.notnull ], [ null, %[[ENTRY]] ]
+// CHECK-NEXT:   ret %struct.T* [[RET]]
 
 void* test7(V* x) { return dynamic_cast<void*>(x); }
-// CHECK: define i8* @"\01?test7@@YAPAXPAUV@@@Z"(%struct.V* %x) #1 {
-// CHECK-NEXT: entry:
-// CHECK-NEXT:   %0 = bitcast %struct.V* %x to i8*
-// CHECK-NEXT:   %1 = tail call i8* @__RTCastToVoid(i8* %0) #2
-// CHECK-NEXT:   ret i8* %1
-// CHECK-NEXT: }
+// CHECK-LABEL: define i8* @"\01?test7@@YAPAXPAUV@@@Z"(%struct.V* %x)
+// CHECK:        [[CAST:%.*]] = bitcast %struct.V* %x to i8*
+// CHECK-NEXT:   [[RET:%.*]] = tail call i8* @__RTCastToVoid(i8* [[CAST]])
+// CHECK-NEXT:   ret i8* [[RET]]
 
 void* test8(A* x) { return dynamic_cast<void*>(x); }
-// CHECK: define i8* @"\01?test8@@YAPAXPAUA@@@Z"(%struct.A* %x) #1 {
-// CHECK-NEXT: entry:
-// CHECK-NEXT:   %0 = icmp eq %struct.A* %x, null
-// CHECK-NEXT:   br i1 %0, label %dynamic_cast.call, label %dynamic_cast.valid
-// CHECK: dynamic_cast.valid:                               ; preds = %entry
-// CHECK-NEXT:   %1 = bitcast %struct.A* %x to i8*
-// CHECK-NEXT:   %2 = bitcast %struct.A* %x to i8**
-// CHECK-NEXT:   %vbtable = load i8** %2, align 4
-// CHECK-NEXT:   %3 = getelementptr inbounds i8* %vbtable, i32 4
-// CHECK-NEXT:   %4 = bitcast i8* %3 to i32*
-// CHECK-NEXT:   %vbase_offs = load i32* %4, align 4
-// CHECK-NEXT:   %5 = getelementptr inbounds i8* %1, i32 %vbase_offs
-// CHECK-NEXT:   %6 = tail call i8* @__RTCastToVoid(i8* %5) #2
-// CHECK-NEXT:   br label %dynamic_cast.call
-// CHECK: dynamic_cast.call:                                ; preds = %dynamic_cast.valid, %entry
-// CHECK-NEXT:   %7 = phi i8* [ %6, %dynamic_cast.valid ], [ null, %entry ]
-// CHECK-NEXT:   ret i8* %7
-// CHECK-NEXT: }
+// CHECK-LABEL: define i8* @"\01?test8@@YAPAXPAUA@@@Z"(%struct.A* %x)
+// CHECK-NEXT: [[ENTRY:.*]]:
+// CHECK-NEXT:   [[CHECK:%.*]] = icmp eq %struct.A* %x, null
+// CHECK-NEXT:   br i1 [[CHECK]], label %dynamic_cast.end, label %dynamic_cast.notnull
+// CHECK-LABEL: dynamic_cast.notnull:
+// CHECK-NEXT:   [[VOIDP:%.*]] = bitcast %struct.A* %x to i8*
+// CHECK-NEXT:   [[BITCAST]] = bitcast %struct.A* %x to i8**
+// CHECK-NEXT:   [[VBTBL:%.*]] = load i8** [[BITCAST]], align 4
+// CHECK-NEXT:   [[VBOFFP:%.*]] = getelementptr inbounds i8* [[VBTBL]], i32 4
+// CHECK-NEXT:   [[VBOFFPCAST:%.*]] = bitcast i8* [[VBOFFP]] to i32*
+// CHECK-NEXT:   [[VBOFFS:%.*]] = load i32* [[VBOFFPCAST:%.*]], align 4
+// CHECK-NEXT:   [[ADJ:%.*]] = getelementptr inbounds i8* [[VOIDP]], i32 [[VBOFFS]]
+// CHECK-NEXT:   [[RES:%.*]] = tail call i8* @__RTCastToVoid(i8* [[ADJ]])
+// CHECK-NEXT:   br label %dynamic_cast.end
+// CHECK-LABEL: dynamic_cast.end:
+// CHECK-NEXT:   [[RET:%.*]] = phi i8* [ [[RES]], %dynamic_cast.notnull ], [ null, %[[ENTRY]] ]
+// CHECK-NEXT:   ret i8* [[RET]]
 
 void* test9(B* x) { return dynamic_cast<void*>(x); }
-// CHECK: define i8* @"\01?test9@@YAPAXPAUB@@@Z"(%struct.B* %x) #1 {
-// CHECK-NEXT: entry:
-// CHECK-NEXT:   %0 = icmp eq %struct.B* %x, null
-// CHECK-NEXT:   br i1 %0, label %dynamic_cast.call, label %dynamic_cast.valid
-// CHECK: dynamic_cast.valid:                               ; preds = %entry
-// CHECK-NEXT:   %1 = getelementptr inbounds %struct.B* %x, i32 0, i32 0, i32 0
-// CHECK-NEXT:   %vbptr = getelementptr inbounds i8* %1, i32 4
-// CHECK-NEXT:   %2 = bitcast i8* %vbptr to i8**
-// CHECK-NEXT:   %vbtable = load i8** %2, align 4
-// CHECK-NEXT:   %3 = getelementptr inbounds i8* %vbtable, i32 4
-// CHECK-NEXT:   %4 = bitcast i8* %3 to i32*
-// CHECK-NEXT:   %vbase_offs = load i32* %4, align 4
-// CHECK-NEXT:   %5 = add nsw i32 %vbase_offs, 4
-// CHECK-NEXT:   %6 = getelementptr inbounds i8* %1, i32 %5
-// CHECK-NEXT:   %7 = tail call i8* @__RTCastToVoid(i8* %6) #2
-// CHECK-NEXT:   br label %dynamic_cast.call
-// CHECK: dynamic_cast.call:                                ; preds = %dynamic_cast.valid, %entry
-// CHECK-NEXT:   %8 = phi i8* [ %7, %dynamic_cast.valid ], [ null, %entry ]
-// CHECK-NEXT:   ret i8* %8
-// CHECK-NEXT: }
+// CHECK-LABEL: define i8* @"\01?test9@@YAPAXPAUB@@@Z"(%struct.B* %x)
+// CHECK-NEXT: [[ENTRY:.*]]:
+// CHECK-NEXT:   [[CHECK:%.*]] = icmp eq %struct.B* %x, null
+// CHECK-NEXT:   br i1 [[CHECK]], label %dynamic_cast.end, label %dynamic_cast.notnull
+// CHECK-LABEL: dynamic_cast.notnull:
+// CHECK-NEXT:   [[CAST:%.*]] = getelementptr inbounds %struct.B* %x, i32 0, i32 0, i32 0
+// CHECK-NEXT:   [[VBPTR:%.*]] = getelementptr inbounds i8* [[CAST]], i32 4
+// CHECK-NEXT:   [[BITCAST:%.*]] = bitcast i8* [[VBPTR]] to i8**
+// CHECK-NEXT:   [[VBTBL:%.*]] = load i8** [[BITCAST]], align 4
+// CHECK-NEXT:   [[VBOFFP:%.*]] = getelementptr inbounds i8* [[VBTBL]], i32 4
+// CHECK-NEXT:   [[VBOFFPCAST:%.*]] = bitcast i8* [[VBOFFP]] to i32*
+// CHECK-NEXT:   [[VBOFFS:%.*]] = load i32* [[VBOFFPCAST:%.*]], align 4
+// CHECK-NEXT:   [[DELTA:%.*]] = add nsw i32 [[VBOFFS]], 4
+// CHECK-NEXT:   [[ADJ:%.*]] = getelementptr inbounds i8* [[CAST]], i32 [[DELTA]]
+// CHECK-NEXT:   [[CALL:%.*]] = tail call i8* @__RTCastToVoid(i8* [[ADJ]])
+// CHECK-NEXT:   br label %dynamic_cast.end
+// CHECK-LABEL: dynamic_cast.end:
+// CHECK-NEXT:   [[RET:%.*]] = phi i8* [ [[CALL]], %dynamic_cast.notnull ], [ null, %[[ENTRY]] ]
+// CHECK-NEXT:   ret i8* [[RET]]
+

Modified: cfe/trunk/test/CodeGenCXX/microsoft-abi-typeid.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-typeid.cpp?rev=211402&r1=211401&r2=211402&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/microsoft-abi-typeid.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/microsoft-abi-typeid.cpp Fri Jun 20 16:11:00 2014
@@ -1,58 +1,48 @@
-// RUN: %clang_cc1 -emit-llvm -O2 -optzns -o - -triple=i386-pc-win32 2>/dev/null %s | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -O1 -o - -triple=i386-pc-win32 %s | FileCheck %s
 // REQUIRES: asserts
 
-struct type_info { const char* raw_name() const; };
+struct type_info;
 namespace std { using ::type_info; }
 
-struct V { virtual void f() {}; };
-struct A : virtual V {};
+struct V { virtual void f(); };
+struct A : virtual V { A(); };
 
-A a;
-int b;
+extern A a;
+extern int b;
 A* fn();
 
 const std::type_info* test0_typeid() { return &typeid(int); }
-// CHECK: define %struct.type_info* @"\01?test0_typeid@@YAPBUtype_info@@XZ"() #0 {
-// CHECK-NEXT: entry:
-// CHECK-NEXT:   ret %struct.type_info* bitcast (%"MSRTTITypeDescriptor\02"* @"\01??_R0H at 8" to %struct.type_info*)
-// CHECK-NEXT: }
+// CHECK-LABEL: define %struct.type_info* @"\01?test0_typeid@@YAPBUtype_info@@XZ"()
+// CHECK:   ret %struct.type_info* bitcast (%"MSRTTITypeDescriptor\02"* @"\01??_R0H at 8" to %struct.type_info*)
 
 const std::type_info* test1_typeid() { return &typeid(A); }
-// CHECK: define %struct.type_info* @"\01?test1_typeid@@YAPBUtype_info@@XZ"() #0 {
-// CHECK-NEXT: entry:
-// CHECK-NEXT:   ret %struct.type_info* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUA@@@8" to %struct.type_info*)
-// CHECK-NEXT: }
+// CHECK-LABEL: define %struct.type_info* @"\01?test1_typeid@@YAPBUtype_info@@XZ"()
+// CHECK:   ret %struct.type_info* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUA@@@8" to %struct.type_info*)
 
 const std::type_info* test2_typeid() { return &typeid(&a); }
-// CHECK: define %struct.type_info* @"\01?test2_typeid@@YAPBUtype_info@@XZ"() #0 {
-// CHECK-NEXT: entry:
-// CHECK-NEXT:   ret %struct.type_info* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0PAUA@@@8" to %struct.type_info*)
-// CHECK-NEXT: }
+// CHECK-LABEL: define %struct.type_info* @"\01?test2_typeid@@YAPBUtype_info@@XZ"()
+// CHECK:   ret %struct.type_info* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0PAUA@@@8" to %struct.type_info*)
 
 const std::type_info* test3_typeid() { return &typeid(*fn()); }
-// CHECK: define %struct.type_info* @"\01?test3_typeid@@YAPBUtype_info@@XZ"() #1 {
-// CHECK-NEXT: entry:
-// CHECK-NEXT:   %call = tail call %struct.A* @"\01?fn@@YAPAUA@@XZ"() #3
-// CHECK-NEXT:   %0 = icmp eq %struct.A* %call, null
-// CHECK-NEXT:   br i1 %0, label %type_id.call, label %type_id.valid
-// CHECK: type_id.valid:                                    ; preds = %entry
-// CHECK-NEXT:   %1 = bitcast %struct.A* %call to i8*
-// CHECK-NEXT:   %2 = bitcast %struct.A* %call to i8**
-// CHECK-NEXT:   %vbtable = load i8** %2, align 4
-// CHECK-NEXT:   %3 = getelementptr inbounds i8* %vbtable, i32 4
-// CHECK-NEXT:   %4 = bitcast i8* %3 to i32*
-// CHECK-NEXT:   %vbase_offs = load i32* %4, align 4
-// CHECK-NEXT:   %5 = getelementptr inbounds i8* %1, i32 %vbase_offs
-// CHECK-NEXT:   br label %type_id.call
-// CHECK: type_id.call:                                     ; preds = %type_id.valid, %entry
-// CHECK-NEXT:   %6 = phi i8* [ %5, %type_id.valid ], [ null, %entry ]
-// CHECK-NEXT:   %7 = tail call i8* @__RTtypeid(i8* %6) #3
-// CHECK-NEXT:   %8 = bitcast i8* %7 to %struct.type_info*
-// CHECK-NEXT:   ret %struct.type_info* %8
-// CHECK-NEXT: }
+// CHECK-LABEL: define %struct.type_info* @"\01?test3_typeid@@YAPBUtype_info@@XZ"()
+// CHECK:        [[CALL:%.*]] = tail call %struct.A* @"\01?fn@@YAPAUA@@XZ"()
+// CHECK-NEXT:   [[CMP:%.*]] = icmp eq %struct.A* [[CALL]], null
+// CHECK-NEXT:   br i1 [[CMP]], label %typeid.bad_typeid, label %typeid.end
+// CHECK-LABEL: typeid.bad_typeid:
+// CHECK-NEXT:   tail call i8* @__RTtypeid(i8* null)
+// CHECK-NEXT:   unreachable
+// CHECK-LABEL: typeid.end:
+// CHECK-NEXT:   [[THIS:%.*]] = bitcast %struct.A* [[CALL]] to i8*
+// CHECK-NEXT:   [[VBTBLP:%.*]] = bitcast %struct.A* [[CALL]] to i8**
+// CHECK-NEXT:   [[VBTBL:%.*]] = load i8** [[VBTBLP]], align 4
+// CHECK-NEXT:   [[VBSLOT:%.*]] = getelementptr inbounds i8* [[VBTBL]], i32 4
+// CHECK-NEXT:   [[VBITCST:%.*]] = bitcast i8* [[VBSLOT]] to i32*
+// CHECK-NEXT:   [[VBASE_OFFS:%.*]] = load i32* [[VBITCST]], align 4
+// CHECK-NEXT:   [[ADJ:%.*]] = getelementptr inbounds i8* [[THIS]], i32 [[VBASE_OFFS]]
+// CHECK-NEXT:   [[RT:%.*]] = tail call i8* @__RTtypeid(i8* [[ADJ]])
+// CHECK-NEXT:   [[RET:%.*]] = bitcast i8* [[RT]] to %struct.type_info*
+// CHECK-NEXT:   ret %struct.type_info* [[RET]]
 
 const std::type_info* test4_typeid() { return &typeid(b); }
-// CHECK: define %struct.type_info* @"\01?test4_typeid@@YAPBUtype_info@@XZ"() #0 {
-// CHECK-NEXT: entry:
-// CHECK-NEXT:   ret %struct.type_info* bitcast (%"MSRTTITypeDescriptor\02"* @"\01??_R0H at 8" to %struct.type_info*)
-// CHECK-NEXT: }
+// CHECK: define %struct.type_info* @"\01?test4_typeid@@YAPBUtype_info@@XZ"()
+// CHECK:   ret %struct.type_info* bitcast (%"MSRTTITypeDescriptor\02"* @"\01??_R0H at 8" to %struct.type_info*)





More information about the cfe-commits mailing list