blob: 9c8174bc22f71e1ccad46ae646ef2500b6ec256f [file] [log] [blame]
Anders Carlsson5d58a1d2009-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
Anders Carlsson84080ec2009-09-29 03:13:20 +000072llvm::Constant *
Anders Carlsson2b358352009-10-03 14:56:57 +000073CodeGenModule::GetCXXBaseClassOffset(const CXXRecordDecl *ClassDecl,
74 const CXXRecordDecl *BaseClassDecl) {
Anders Carlsson84080ec2009-09-29 03:13:20 +000075 if (ClassDecl == BaseClassDecl)
76 return 0;
77
78 QualType BTy =
79 getContext().getCanonicalType(
80 getContext().getTypeDeclType(const_cast<CXXRecordDecl*>(BaseClassDecl)));
81
82 uint64_t Offset = ComputeBaseClassOffset(getContext(),
83 ClassDecl, BaseClassDecl);
84 if (!Offset)
85 return 0;
86
Anders Carlsson2b358352009-10-03 14:56:57 +000087 const llvm::Type *PtrDiffTy =
88 Types.ConvertType(getContext().getPointerDiffType());
Anders Carlsson84080ec2009-09-29 03:13:20 +000089
90 return llvm::ConstantInt::get(PtrDiffTy, Offset);
91}
92
Anders Carlsson5d58a1d2009-09-12 04:27:24 +000093llvm::Value *
94CodeGenFunction::GetAddressCXXOfBaseClass(llvm::Value *BaseValue,
95 const CXXRecordDecl *ClassDecl,
96 const CXXRecordDecl *BaseClassDecl,
97 bool NullCheckValue) {
Anders Carlsson2b358352009-10-03 14:56:57 +000098 llvm::Constant *Offset = CGM.GetCXXBaseClassOffset(ClassDecl, BaseClassDecl);
Anders Carlsson84080ec2009-09-29 03:13:20 +000099
Anders Carlssondfd03302009-09-22 21:58:22 +0000100 QualType BTy =
101 getContext().getCanonicalType(
102 getContext().getTypeDeclType(const_cast<CXXRecordDecl*>(BaseClassDecl)));
103 const llvm::Type *BasePtrTy = llvm::PointerType::getUnqual(ConvertType(BTy));
Anders Carlsson5d58a1d2009-09-12 04:27:24 +0000104
Anders Carlssondfd03302009-09-22 21:58:22 +0000105 if (!Offset) {
106 // Just cast back.
107 return Builder.CreateBitCast(BaseValue, BasePtrTy);
108 }
109
Anders Carlsson32baf622009-09-12 06:04:24 +0000110 llvm::BasicBlock *CastNull = 0;
111 llvm::BasicBlock *CastNotNull = 0;
112 llvm::BasicBlock *CastEnd = 0;
113
114 if (NullCheckValue) {
115 CastNull = createBasicBlock("cast.null");
116 CastNotNull = createBasicBlock("cast.notnull");
117 CastEnd = createBasicBlock("cast.end");
118
119 llvm::Value *IsNull =
120 Builder.CreateICmpEQ(BaseValue,
121 llvm::Constant::getNullValue(BaseValue->getType()));
122 Builder.CreateCondBr(IsNull, CastNull, CastNotNull);
123 EmitBlock(CastNotNull);
124 }
125
Anders Carlsson5d58a1d2009-09-12 04:27:24 +0000126 const llvm::Type *Int8PtrTy =
127 llvm::PointerType::getUnqual(llvm::Type::getInt8Ty(VMContext));
128
Anders Carlsson5d58a1d2009-09-12 04:27:24 +0000129 // Apply the offset.
130 BaseValue = Builder.CreateBitCast(BaseValue, Int8PtrTy);
Anders Carlsson84080ec2009-09-29 03:13:20 +0000131 BaseValue = Builder.CreateGEP(BaseValue, Offset, "add.ptr");
Anders Carlsson5d58a1d2009-09-12 04:27:24 +0000132
Anders Carlsson5d58a1d2009-09-12 04:27:24 +0000133 // Cast back.
Anders Carlssondfd03302009-09-22 21:58:22 +0000134 BaseValue = Builder.CreateBitCast(BaseValue, BasePtrTy);
Anders Carlsson32baf622009-09-12 06:04:24 +0000135
136 if (NullCheckValue) {
137 Builder.CreateBr(CastEnd);
138 EmitBlock(CastNull);
139 Builder.CreateBr(CastEnd);
140 EmitBlock(CastEnd);
141
142 llvm::PHINode *PHI = Builder.CreatePHI(BaseValue->getType());
143 PHI->reserveOperandSpace(2);
144 PHI->addIncoming(BaseValue, CastNotNull);
145 PHI->addIncoming(llvm::Constant::getNullValue(BaseValue->getType()),
146 CastNull);
147 BaseValue = PHI;
148 }
Anders Carlsson5d58a1d2009-09-12 04:27:24 +0000149
150 return BaseValue;
151}