blob: 6d53e83e7cf08c5011997beab93075c8b37da300 [file] [log] [blame]
Anders Carlsson9a57c5a2009-09-12 04:27:24 +00001//===--- CGCXXClass.cpp - Emit LLVM Code for C++ classes ------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This contains code dealing with C++ code generation of classes
11//
12//===----------------------------------------------------------------------===//
13
14#include "CodeGenFunction.h"
15#include "clang/AST/RecordLayout.h"
16using namespace clang;
17using namespace CodeGen;
18
19static bool
20GetNestedPaths(llvm::SmallVectorImpl<const CXXRecordDecl *> &NestedBasePaths,
21 const CXXRecordDecl *ClassDecl,
22 const CXXRecordDecl *BaseClassDecl) {
23 for (CXXRecordDecl::base_class_const_iterator i = ClassDecl->bases_begin(),
24 e = ClassDecl->bases_end(); i != e; ++i) {
25 if (i->isVirtual())
26 continue;
27 const CXXRecordDecl *Base =
28 cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
29 if (Base == BaseClassDecl) {
30 NestedBasePaths.push_back(BaseClassDecl);
31 return true;
32 }
33 }
34 // BaseClassDecl not an immediate base of ClassDecl.
35 for (CXXRecordDecl::base_class_const_iterator i = ClassDecl->bases_begin(),
36 e = ClassDecl->bases_end(); i != e; ++i) {
37 if (i->isVirtual())
38 continue;
39 const CXXRecordDecl *Base =
40 cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
41 if (GetNestedPaths(NestedBasePaths, Base, BaseClassDecl)) {
42 NestedBasePaths.push_back(Base);
43 return true;
44 }
45 }
46 return false;
47}
48
49static uint64_t ComputeBaseClassOffset(ASTContext &Context,
50 const CXXRecordDecl *ClassDecl,
51 const CXXRecordDecl *BaseClassDecl) {
52 uint64_t Offset = 0;
53
54 llvm::SmallVector<const CXXRecordDecl *, 16> NestedBasePaths;
55 GetNestedPaths(NestedBasePaths, ClassDecl, BaseClassDecl);
56 assert(NestedBasePaths.size() > 0 &&
57 "AddressCXXOfBaseClass - inheritence path failed");
58 NestedBasePaths.push_back(ClassDecl);
59
60 for (unsigned i = NestedBasePaths.size() - 1; i > 0; i--) {
61 const CXXRecordDecl *DerivedClass = NestedBasePaths[i];
62 const CXXRecordDecl *BaseClass = NestedBasePaths[i-1];
63 const ASTRecordLayout &Layout =
64 Context.getASTRecordLayout(DerivedClass);
65
66 Offset += Layout.getBaseClassOffset(BaseClass) / 8;
67 }
68
69 return Offset;
70}
71
72llvm::Value *
73CodeGenFunction::GetAddressCXXOfBaseClass(llvm::Value *BaseValue,
74 const CXXRecordDecl *ClassDecl,
75 const CXXRecordDecl *BaseClassDecl,
76 bool NullCheckValue) {
77 if (ClassDecl == BaseClassDecl)
78 return BaseValue;
79
Anders Carlsson8fef09c2009-09-22 21:58:22 +000080 QualType BTy =
81 getContext().getCanonicalType(
82 getContext().getTypeDeclType(const_cast<CXXRecordDecl*>(BaseClassDecl)));
83 const llvm::Type *BasePtrTy = llvm::PointerType::getUnqual(ConvertType(BTy));
Anders Carlsson9a57c5a2009-09-12 04:27:24 +000084
85 uint64_t Offset = ComputeBaseClassOffset(getContext(),
86 ClassDecl, BaseClassDecl);
Anders Carlsson8fef09c2009-09-22 21:58:22 +000087 if (!Offset) {
88 // Just cast back.
89 return Builder.CreateBitCast(BaseValue, BasePtrTy);
90 }
91
Anders Carlsson360e7d02009-09-12 06:04:24 +000092 llvm::BasicBlock *CastNull = 0;
93 llvm::BasicBlock *CastNotNull = 0;
94 llvm::BasicBlock *CastEnd = 0;
95
96 if (NullCheckValue) {
97 CastNull = createBasicBlock("cast.null");
98 CastNotNull = createBasicBlock("cast.notnull");
99 CastEnd = createBasicBlock("cast.end");
100
101 llvm::Value *IsNull =
102 Builder.CreateICmpEQ(BaseValue,
103 llvm::Constant::getNullValue(BaseValue->getType()));
104 Builder.CreateCondBr(IsNull, CastNull, CastNotNull);
105 EmitBlock(CastNotNull);
106 }
107
Anders Carlsson9a57c5a2009-09-12 04:27:24 +0000108 const llvm::Type *LongTy =
109 CGM.getTypes().ConvertType(CGM.getContext().LongTy);
110 const llvm::Type *Int8PtrTy =
111 llvm::PointerType::getUnqual(llvm::Type::getInt8Ty(VMContext));
112
113 llvm::Value *OffsetVal = llvm::ConstantInt::get(LongTy, Offset);
114
115 // Apply the offset.
116 BaseValue = Builder.CreateBitCast(BaseValue, Int8PtrTy);
117 BaseValue = Builder.CreateGEP(BaseValue, OffsetVal, "add.ptr");
118
Anders Carlsson9a57c5a2009-09-12 04:27:24 +0000119 // Cast back.
Anders Carlsson8fef09c2009-09-22 21:58:22 +0000120 BaseValue = Builder.CreateBitCast(BaseValue, BasePtrTy);
Anders Carlsson360e7d02009-09-12 06:04:24 +0000121
122 if (NullCheckValue) {
123 Builder.CreateBr(CastEnd);
124 EmitBlock(CastNull);
125 Builder.CreateBr(CastEnd);
126 EmitBlock(CastEnd);
127
128 llvm::PHINode *PHI = Builder.CreatePHI(BaseValue->getType());
129 PHI->reserveOperandSpace(2);
130 PHI->addIncoming(BaseValue, CastNotNull);
131 PHI->addIncoming(llvm::Constant::getNullValue(BaseValue->getType()),
132 CastNull);
133 BaseValue = PHI;
134 }
Anders Carlsson9a57c5a2009-09-12 04:27:24 +0000135
136 return BaseValue;
137}