Skip to content
CGClass.cpp 61.5 KiB
Newer Older
//===--- CGClass.cpp - Emit LLVM Code for C++ classes ---------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This contains code dealing with C++ code generation of classes
//
//===----------------------------------------------------------------------===//

#include "CodeGenFunction.h"
#include "clang/AST/EvaluatedExprVisitor.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtCXX.h"
using namespace clang;
using namespace CodeGen;

ComputeNonVirtualBaseClassOffset(ASTContext &Context, 
                                 const CXXRecordDecl *DerivedClass,
                                 CastExpr::path_const_iterator Start,
                                 CastExpr::path_const_iterator End) {
  CharUnits Offset = CharUnits::Zero();
  for (CastExpr::path_const_iterator I = Start; I != End; ++I) {
    const CXXBaseSpecifier *Base = *I;
    assert(!Base->isVirtual() && "Should not see virtual bases here!");

    // Get the layout.
    const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
    
    const CXXRecordDecl *BaseDecl = 
      cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
    
    // Add the offset.
    Offset += Layout.getBaseClassOffset(BaseDecl);
llvm::Constant *
CodeGenModule::GetNonVirtualBaseClassOffset(const CXXRecordDecl *ClassDecl,
                                   CastExpr::path_const_iterator PathBegin,
                                   CastExpr::path_const_iterator PathEnd) {
  assert(PathBegin != PathEnd && "Base path should not be empty!");
    ComputeNonVirtualBaseClassOffset(getContext(), ClassDecl,
                                     PathBegin, PathEnd);
  llvm::Type *PtrDiffTy = 
  Types.ConvertType(getContext().getPointerDiffType());
  
  return llvm::ConstantInt::get(PtrDiffTy, Offset.getQuantity());
/// Gets the address of a direct base class within a complete object.
/// This should only be used for (1) non-virtual bases or (2) virtual bases
/// when the type is known to be complete (e.g. in complete destructors).
///
/// The object pointed to by 'This' is assumed to be non-null.
llvm::Value *
CodeGenFunction::GetAddressOfDirectBaseInCompleteClass(llvm::Value *This,
                                                   const CXXRecordDecl *Derived,
                                                   const CXXRecordDecl *Base,
                                                   bool BaseIsVirtual) {
  // 'this' must be a pointer (in some address space) to Derived.
  assert(This->getType()->isPointerTy() &&
         cast<llvm::PointerType>(This->getType())->getElementType()
           == ConvertType(Derived));

  // Compute the offset of the virtual base.
  const ASTRecordLayout &Layout = getContext().getASTRecordLayout(Derived);
    Offset = Layout.getVBaseClassOffset(Base);
    Offset = Layout.getBaseClassOffset(Base);

  // Shift and cast down to the base type.
  // TODO: for complete types, this should be possible with a GEP.
  llvm::Value *V = This;
    llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext());
    V = Builder.CreateBitCast(V, Int8PtrTy);
    V = Builder.CreateConstInBoundsGEP1_64(V, Offset.getQuantity());
  }
  V = Builder.CreateBitCast(V, ConvertType(Base)->getPointerTo());

  return V;
static llvm::Value *
ApplyNonVirtualAndVirtualOffset(CodeGenFunction &CGF, llvm::Value *ThisPtr,
                                CharUnits NonVirtual, llvm::Value *Virtual) {
  llvm::Type *PtrDiffTy = 
    CGF.ConvertType(CGF.getContext().getPointerDiffType());
  
  llvm::Value *NonVirtualOffset = 0;
  if (!NonVirtual.isZero())
    NonVirtualOffset = llvm::ConstantInt::get(PtrDiffTy, 
                                              NonVirtual.getQuantity());
  
  llvm::Value *BaseOffset;
  if (Virtual) {
    if (NonVirtualOffset)
      BaseOffset = CGF.Builder.CreateAdd(Virtual, NonVirtualOffset);
    else
      BaseOffset = Virtual;
  } else
    BaseOffset = NonVirtualOffset;
  
  // Apply the base offset.
  llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
  ThisPtr = CGF.Builder.CreateBitCast(ThisPtr, Int8PtrTy);
  ThisPtr = CGF.Builder.CreateGEP(ThisPtr, BaseOffset, "add.ptr");

  return ThisPtr;
}

llvm::Value *
CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value, 
                                       CastExpr::path_const_iterator PathBegin,
                                       CastExpr::path_const_iterator PathEnd,
  assert(PathBegin != PathEnd && "Base path should not be empty!");
  CastExpr::path_const_iterator Start = PathBegin;
  const CXXRecordDecl *VBase = 0;
  
  // Get the virtual base.
  if ((*Start)->isVirtual()) {
    VBase = 
      cast<CXXRecordDecl>((*Start)->getType()->getAs<RecordType>()->getDecl());
    ++Start;
  }
  
    ComputeNonVirtualBaseClassOffset(getContext(), VBase ? VBase : Derived,
  llvm::Type *BasePtrTy = 
    ConvertType((PathEnd[-1])->getType())->getPointerTo();
  if (NonVirtualOffset.isZero() && !VBase) {
    // Just cast back.
    return Builder.CreateBitCast(Value, BasePtrTy);
  }    
  
  llvm::BasicBlock *CastNull = 0;
  llvm::BasicBlock *CastNotNull = 0;
  llvm::BasicBlock *CastEnd = 0;
  
  if (NullCheckValue) {
    CastNull = createBasicBlock("cast.null");
    CastNotNull = createBasicBlock("cast.notnull");
    CastEnd = createBasicBlock("cast.end");
    
    llvm::Value *IsNull = Builder.CreateIsNull(Value);
    Builder.CreateCondBr(IsNull, CastNull, CastNotNull);
    EmitBlock(CastNotNull);
  }

  llvm::Value *VirtualOffset = 0;

  if (VBase) {
    if (Derived->hasAttr<FinalAttr>()) {
      VirtualOffset = 0;

      const ASTRecordLayout &Layout = getContext().getASTRecordLayout(Derived);

      CharUnits VBaseOffset = Layout.getVBaseClassOffset(VBase);
      NonVirtualOffset += VBaseOffset;
    } else
      VirtualOffset = GetVirtualBaseClassOffset(Value, Derived, VBase);
  }
  Value = ApplyNonVirtualAndVirtualOffset(*this, Value, 
                                          VirtualOffset);
  
  // Cast back.
  Value = Builder.CreateBitCast(Value, BasePtrTy);
Loading
Loading full blame...