//===--- CGCXXClass.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/RecordLayout.h" using namespace clang; using namespace CodeGen; static bool GetNestedPaths(llvm::SmallVectorImpl &NestedBasePaths, const CXXRecordDecl *ClassDecl, const CXXRecordDecl *BaseClassDecl) { for (CXXRecordDecl::base_class_const_iterator i = ClassDecl->bases_begin(), e = ClassDecl->bases_end(); i != e; ++i) { if (i->isVirtual()) continue; const CXXRecordDecl *Base = cast(i->getType()->getAs()->getDecl()); if (Base == BaseClassDecl) { NestedBasePaths.push_back(BaseClassDecl); return true; } } // BaseClassDecl not an immediate base of ClassDecl. for (CXXRecordDecl::base_class_const_iterator i = ClassDecl->bases_begin(), e = ClassDecl->bases_end(); i != e; ++i) { if (i->isVirtual()) continue; const CXXRecordDecl *Base = cast(i->getType()->getAs()->getDecl()); if (GetNestedPaths(NestedBasePaths, Base, BaseClassDecl)) { NestedBasePaths.push_back(Base); return true; } } return false; } static uint64_t ComputeBaseClassOffset(ASTContext &Context, const CXXRecordDecl *ClassDecl, const CXXRecordDecl *BaseClassDecl) { uint64_t Offset = 0; llvm::SmallVector NestedBasePaths; GetNestedPaths(NestedBasePaths, ClassDecl, BaseClassDecl); assert(NestedBasePaths.size() > 0 && "AddressCXXOfBaseClass - inheritence path failed"); NestedBasePaths.push_back(ClassDecl); for (unsigned i = NestedBasePaths.size() - 1; i > 0; i--) { const CXXRecordDecl *DerivedClass = NestedBasePaths[i]; const CXXRecordDecl *BaseClass = NestedBasePaths[i-1]; const ASTRecordLayout &Layout = Context.getASTRecordLayout(DerivedClass); Offset += Layout.getBaseClassOffset(BaseClass) / 8; } return Offset; } llvm::Value * CodeGenFunction::GetAddressCXXOfBaseClass(llvm::Value *BaseValue, const CXXRecordDecl *ClassDecl, const CXXRecordDecl *BaseClassDecl, bool NullCheckValue) { if (ClassDecl == BaseClassDecl) return BaseValue; QualType BTy = getContext().getCanonicalType( getContext().getTypeDeclType(const_cast(BaseClassDecl))); const llvm::Type *BasePtrTy = llvm::PointerType::getUnqual(ConvertType(BTy)); uint64_t Offset = ComputeBaseClassOffset(getContext(), ClassDecl, BaseClassDecl); if (!Offset) { // Just cast back. return Builder.CreateBitCast(BaseValue, 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.CreateICmpEQ(BaseValue, llvm::Constant::getNullValue(BaseValue->getType())); Builder.CreateCondBr(IsNull, CastNull, CastNotNull); EmitBlock(CastNotNull); } const llvm::Type *LongTy = CGM.getTypes().ConvertType(CGM.getContext().LongTy); const llvm::Type *Int8PtrTy = llvm::PointerType::getUnqual(llvm::Type::getInt8Ty(VMContext)); llvm::Value *OffsetVal = llvm::ConstantInt::get(LongTy, Offset); // Apply the offset. BaseValue = Builder.CreateBitCast(BaseValue, Int8PtrTy); BaseValue = Builder.CreateGEP(BaseValue, OffsetVal, "add.ptr"); // Cast back. BaseValue = Builder.CreateBitCast(BaseValue, BasePtrTy); if (NullCheckValue) { Builder.CreateBr(CastEnd); EmitBlock(CastNull); Builder.CreateBr(CastEnd); EmitBlock(CastEnd); llvm::PHINode *PHI = Builder.CreatePHI(BaseValue->getType()); PHI->reserveOperandSpace(2); PHI->addIncoming(BaseValue, CastNotNull); PHI->addIncoming(llvm::Constant::getNullValue(BaseValue->getType()), CastNull); BaseValue = PHI; } return BaseValue; }