blob: fd2afe70e00ed6e42a567af894a7fd873d710fdd [file] [log] [blame]
Anders Carlsson5b955922009-11-24 05:51:11 +00001//===--- CGClass.cpp - Emit LLVM Code for C++ classes ---------------------===//
Anders Carlsson5d58a1d2009-09-12 04:27:24 +00002//
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"
Anders Carlsson2f1986b2009-10-06 22:43:30 +000015#include "clang/AST/CXXInheritance.h"
Anders Carlsson5d58a1d2009-09-12 04:27:24 +000016#include "clang/AST/RecordLayout.h"
Anders Carlsson2f1986b2009-10-06 22:43:30 +000017
Anders Carlsson5d58a1d2009-09-12 04:27:24 +000018using namespace clang;
19using namespace CodeGen;
20
Anders Carlsson2f1986b2009-10-06 22:43:30 +000021static uint64_t
22ComputeNonVirtualBaseClassOffset(ASTContext &Context, CXXBasePaths &Paths,
23 unsigned Start) {
24 uint64_t Offset = 0;
Anders Carlsson5d58a1d2009-09-12 04:27:24 +000025
Anders Carlsson2f1986b2009-10-06 22:43:30 +000026 const CXXBasePath &Path = Paths.front();
27 for (unsigned i = Start, e = Path.size(); i != e; ++i) {
28 const CXXBasePathElement& Element = Path[i];
Anders Carlsson5d58a1d2009-09-12 04:27:24 +000029
Anders Carlsson2f1986b2009-10-06 22:43:30 +000030 // Get the layout.
31 const ASTRecordLayout &Layout = Context.getASTRecordLayout(Element.Class);
Anders Carlsson5d58a1d2009-09-12 04:27:24 +000032
Anders Carlsson2f1986b2009-10-06 22:43:30 +000033 const CXXBaseSpecifier *BS = Element.Base;
34 assert(!BS->isVirtual() && "Should not see virtual bases here!");
Anders Carlsson5d58a1d2009-09-12 04:27:24 +000035
Anders Carlsson2f1986b2009-10-06 22:43:30 +000036 const CXXRecordDecl *Base =
37 cast<CXXRecordDecl>(BS->getType()->getAs<RecordType>()->getDecl());
38
39 // Add the offset.
40 Offset += Layout.getBaseClassOffset(Base) / 8;
41 }
42
43 return Offset;
Anders Carlsson5d58a1d2009-09-12 04:27:24 +000044}
45
Anders Carlsson84080ec2009-09-29 03:13:20 +000046llvm::Constant *
Anders Carlsson2b358352009-10-03 14:56:57 +000047CodeGenModule::GetCXXBaseClassOffset(const CXXRecordDecl *ClassDecl,
48 const CXXRecordDecl *BaseClassDecl) {
Anders Carlsson84080ec2009-09-29 03:13:20 +000049 if (ClassDecl == BaseClassDecl)
50 return 0;
51
Anders Carlsson2f1986b2009-10-06 22:43:30 +000052 CXXBasePaths Paths(/*FindAmbiguities=*/false,
53 /*RecordPaths=*/true, /*DetectVirtual=*/false);
54 if (!const_cast<CXXRecordDecl *>(ClassDecl)->
55 isDerivedFrom(const_cast<CXXRecordDecl *>(BaseClassDecl), Paths)) {
56 assert(false && "Class must be derived from the passed in base class!");
57 return 0;
58 }
Anders Carlsson84080ec2009-09-29 03:13:20 +000059
Anders Carlsson2f1986b2009-10-06 22:43:30 +000060 uint64_t Offset = ComputeNonVirtualBaseClassOffset(getContext(), Paths, 0);
Anders Carlsson84080ec2009-09-29 03:13:20 +000061 if (!Offset)
62 return 0;
63
Anders Carlsson2b358352009-10-03 14:56:57 +000064 const llvm::Type *PtrDiffTy =
65 Types.ConvertType(getContext().getPointerDiffType());
Anders Carlsson84080ec2009-09-29 03:13:20 +000066
67 return llvm::ConstantInt::get(PtrDiffTy, Offset);
68}
69
Anders Carlsson2f1986b2009-10-06 22:43:30 +000070static llvm::Value *GetCXXBaseClassOffset(CodeGenFunction &CGF,
71 llvm::Value *BaseValue,
72 const CXXRecordDecl *ClassDecl,
73 const CXXRecordDecl *BaseClassDecl) {
74 CXXBasePaths Paths(/*FindAmbiguities=*/false,
Eli Friedman8432f252009-11-28 03:31:34 +000075 /*RecordPaths=*/true, /*DetectVirtual=*/false);
Anders Carlsson2f1986b2009-10-06 22:43:30 +000076 if (!const_cast<CXXRecordDecl *>(ClassDecl)->
77 isDerivedFrom(const_cast<CXXRecordDecl *>(BaseClassDecl), Paths)) {
78 assert(false && "Class must be derived from the passed in base class!");
79 return 0;
80 }
81
82 unsigned Start = 0;
83 llvm::Value *VirtualOffset = 0;
Eli Friedman8432f252009-11-28 03:31:34 +000084
85 const CXXBasePath &Path = Paths.front();
86 const CXXRecordDecl *VBase = 0;
87 for (unsigned i = 0, e = Path.size(); i != e; ++i) {
88 const CXXBasePathElement& Element = Path[i];
89 if (Element.Base->isVirtual()) {
90 Start = i+1;
91 QualType VBaseType = Element.Base->getType();
92 VBase = cast<CXXRecordDecl>(VBaseType->getAs<RecordType>()->getDecl());
Anders Carlsson2f1986b2009-10-06 22:43:30 +000093 }
94 }
Eli Friedman8432f252009-11-28 03:31:34 +000095 if (VBase)
96 VirtualOffset =
97 CGF.GetVirtualCXXBaseClassOffset(BaseValue, ClassDecl, VBase);
Anders Carlsson2f1986b2009-10-06 22:43:30 +000098
99 uint64_t Offset =
100 ComputeNonVirtualBaseClassOffset(CGF.getContext(), Paths, Start);
101
102 if (!Offset)
103 return VirtualOffset;
104
105 const llvm::Type *PtrDiffTy =
106 CGF.ConvertType(CGF.getContext().getPointerDiffType());
107 llvm::Value *NonVirtualOffset = llvm::ConstantInt::get(PtrDiffTy, Offset);
108
109 if (VirtualOffset)
110 return CGF.Builder.CreateAdd(VirtualOffset, NonVirtualOffset);
111
112 return NonVirtualOffset;
113}
114
Anders Carlsson9fcfc422009-12-03 03:06:55 +0000115// FIXME: This probably belongs in CGVtable, but it relies on
116// the static function ComputeNonVirtualBaseClassOffset, so we should make that
117// a CodeGenModule member function as well.
118ThunkAdjustment
119CodeGenModule::ComputeThunkAdjustment(const CXXRecordDecl *ClassDecl,
120 const CXXRecordDecl *BaseClassDecl) {
121 CXXBasePaths Paths(/*FindAmbiguities=*/false,
122 /*RecordPaths=*/true, /*DetectVirtual=*/false);
123 if (!const_cast<CXXRecordDecl *>(ClassDecl)->
124 isDerivedFrom(const_cast<CXXRecordDecl *>(BaseClassDecl), Paths)) {
125 assert(false && "Class must be derived from the passed in base class!");
126 return ThunkAdjustment();
127 }
128
129 unsigned Start = 0;
130 uint64_t VirtualOffset = 0;
131
132 const CXXBasePath &Path = Paths.front();
133 const CXXRecordDecl *VBase = 0;
134 for (unsigned i = 0, e = Path.size(); i != e; ++i) {
135 const CXXBasePathElement& Element = Path[i];
136 if (Element.Base->isVirtual()) {
137 Start = i+1;
138 QualType VBaseType = Element.Base->getType();
139 VBase = cast<CXXRecordDecl>(VBaseType->getAs<RecordType>()->getDecl());
140 }
141 }
142 if (VBase)
143 VirtualOffset =
144 getVtableInfo().getVirtualBaseOffsetIndex(ClassDecl, BaseClassDecl);
145
146 uint64_t Offset =
147 ComputeNonVirtualBaseClassOffset(getContext(), Paths, Start);
148 return ThunkAdjustment(Offset, VirtualOffset);
149}
150
Anders Carlsson5d58a1d2009-09-12 04:27:24 +0000151llvm::Value *
Anders Carlssona3697c92009-11-23 17:57:54 +0000152CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value,
153 const CXXRecordDecl *ClassDecl,
154 const CXXRecordDecl *BaseClassDecl,
155 bool NullCheckValue) {
Anders Carlssondfd03302009-09-22 21:58:22 +0000156 QualType BTy =
157 getContext().getCanonicalType(
158 getContext().getTypeDeclType(const_cast<CXXRecordDecl*>(BaseClassDecl)));
159 const llvm::Type *BasePtrTy = llvm::PointerType::getUnqual(ConvertType(BTy));
Anders Carlsson5d58a1d2009-09-12 04:27:24 +0000160
Anders Carlsson2f1986b2009-10-06 22:43:30 +0000161 if (ClassDecl == BaseClassDecl) {
Anders Carlssondfd03302009-09-22 21:58:22 +0000162 // Just cast back.
Anders Carlssona3697c92009-11-23 17:57:54 +0000163 return Builder.CreateBitCast(Value, BasePtrTy);
Anders Carlssondfd03302009-09-22 21:58:22 +0000164 }
Eli Friedman4a5dc242009-11-10 22:48:10 +0000165
Anders Carlsson32baf622009-09-12 06:04:24 +0000166 llvm::BasicBlock *CastNull = 0;
167 llvm::BasicBlock *CastNotNull = 0;
168 llvm::BasicBlock *CastEnd = 0;
169
170 if (NullCheckValue) {
171 CastNull = createBasicBlock("cast.null");
172 CastNotNull = createBasicBlock("cast.notnull");
173 CastEnd = createBasicBlock("cast.end");
174
175 llvm::Value *IsNull =
Anders Carlssona3697c92009-11-23 17:57:54 +0000176 Builder.CreateICmpEQ(Value,
177 llvm::Constant::getNullValue(Value->getType()));
Anders Carlsson32baf622009-09-12 06:04:24 +0000178 Builder.CreateCondBr(IsNull, CastNull, CastNotNull);
179 EmitBlock(CastNotNull);
180 }
181
Benjamin Kramer3c0ef8c2009-10-13 10:07:13 +0000182 const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext);
Eli Friedman4a5dc242009-11-10 22:48:10 +0000183
184 llvm::Value *Offset =
Anders Carlssona3697c92009-11-23 17:57:54 +0000185 GetCXXBaseClassOffset(*this, Value, ClassDecl, BaseClassDecl);
Anders Carlsson5d58a1d2009-09-12 04:27:24 +0000186
Eli Friedman4a5dc242009-11-10 22:48:10 +0000187 if (Offset) {
188 // Apply the offset.
Anders Carlssona3697c92009-11-23 17:57:54 +0000189 Value = Builder.CreateBitCast(Value, Int8PtrTy);
190 Value = Builder.CreateGEP(Value, Offset, "add.ptr");
Eli Friedman4a5dc242009-11-10 22:48:10 +0000191 }
Anders Carlsson5d58a1d2009-09-12 04:27:24 +0000192
Anders Carlsson5d58a1d2009-09-12 04:27:24 +0000193 // Cast back.
Anders Carlssona3697c92009-11-23 17:57:54 +0000194 Value = Builder.CreateBitCast(Value, BasePtrTy);
Anders Carlsson32baf622009-09-12 06:04:24 +0000195
196 if (NullCheckValue) {
197 Builder.CreateBr(CastEnd);
198 EmitBlock(CastNull);
199 Builder.CreateBr(CastEnd);
200 EmitBlock(CastEnd);
201
Anders Carlssona3697c92009-11-23 17:57:54 +0000202 llvm::PHINode *PHI = Builder.CreatePHI(Value->getType());
Anders Carlsson32baf622009-09-12 06:04:24 +0000203 PHI->reserveOperandSpace(2);
Anders Carlssona3697c92009-11-23 17:57:54 +0000204 PHI->addIncoming(Value, CastNotNull);
205 PHI->addIncoming(llvm::Constant::getNullValue(Value->getType()),
Anders Carlsson32baf622009-09-12 06:04:24 +0000206 CastNull);
Anders Carlssona3697c92009-11-23 17:57:54 +0000207 Value = PHI;
Anders Carlsson32baf622009-09-12 06:04:24 +0000208 }
Anders Carlsson5d58a1d2009-09-12 04:27:24 +0000209
Anders Carlssona3697c92009-11-23 17:57:54 +0000210 return Value;
211}
212
213llvm::Value *
214CodeGenFunction::GetAddressOfDerivedClass(llvm::Value *Value,
215 const CXXRecordDecl *ClassDecl,
216 const CXXRecordDecl *DerivedClassDecl,
217 bool NullCheckValue) {
218 QualType DerivedTy =
219 getContext().getCanonicalType(
220 getContext().getTypeDeclType(const_cast<CXXRecordDecl*>(DerivedClassDecl)));
221 const llvm::Type *DerivedPtrTy = ConvertType(DerivedTy)->getPointerTo();
222
223 if (ClassDecl == DerivedClassDecl) {
224 // Just cast back.
225 return Builder.CreateBitCast(Value, DerivedPtrTy);
226 }
227
228 llvm::BasicBlock *CastNull = 0;
229 llvm::BasicBlock *CastNotNull = 0;
230 llvm::BasicBlock *CastEnd = 0;
231
232 if (NullCheckValue) {
233 CastNull = createBasicBlock("cast.null");
234 CastNotNull = createBasicBlock("cast.notnull");
235 CastEnd = createBasicBlock("cast.end");
236
237 llvm::Value *IsNull =
238 Builder.CreateICmpEQ(Value,
239 llvm::Constant::getNullValue(Value->getType()));
240 Builder.CreateCondBr(IsNull, CastNull, CastNotNull);
241 EmitBlock(CastNotNull);
242 }
243
244 llvm::Value *Offset = GetCXXBaseClassOffset(*this, Value, DerivedClassDecl,
245 ClassDecl);
246 if (Offset) {
247 // Apply the offset.
248 Value = Builder.CreatePtrToInt(Value, Offset->getType());
249 Value = Builder.CreateSub(Value, Offset);
250 Value = Builder.CreateIntToPtr(Value, DerivedPtrTy);
251 } else {
252 // Just cast.
253 Value = Builder.CreateBitCast(Value, DerivedPtrTy);
254 }
255
256 if (NullCheckValue) {
257 Builder.CreateBr(CastEnd);
258 EmitBlock(CastNull);
259 Builder.CreateBr(CastEnd);
260 EmitBlock(CastEnd);
261
262 llvm::PHINode *PHI = Builder.CreatePHI(Value->getType());
263 PHI->reserveOperandSpace(2);
264 PHI->addIncoming(Value, CastNotNull);
265 PHI->addIncoming(llvm::Constant::getNullValue(Value->getType()),
266 CastNull);
267 Value = PHI;
268 }
269
270 return Value;
Anders Carlsson5d58a1d2009-09-12 04:27:24 +0000271}