blob: b3c2b986d1903c811ddec72ad6079f2e41c77210 [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 Carlsson5d58a1d2009-09-12 04:27:24 +0000115llvm::Value *
Anders Carlssona3697c92009-11-23 17:57:54 +0000116CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value,
117 const CXXRecordDecl *ClassDecl,
118 const CXXRecordDecl *BaseClassDecl,
119 bool NullCheckValue) {
Anders Carlssondfd03302009-09-22 21:58:22 +0000120 QualType BTy =
121 getContext().getCanonicalType(
122 getContext().getTypeDeclType(const_cast<CXXRecordDecl*>(BaseClassDecl)));
123 const llvm::Type *BasePtrTy = llvm::PointerType::getUnqual(ConvertType(BTy));
Anders Carlsson5d58a1d2009-09-12 04:27:24 +0000124
Anders Carlsson2f1986b2009-10-06 22:43:30 +0000125 if (ClassDecl == BaseClassDecl) {
Anders Carlssondfd03302009-09-22 21:58:22 +0000126 // Just cast back.
Anders Carlssona3697c92009-11-23 17:57:54 +0000127 return Builder.CreateBitCast(Value, BasePtrTy);
Anders Carlssondfd03302009-09-22 21:58:22 +0000128 }
Eli Friedman4a5dc242009-11-10 22:48:10 +0000129
Anders Carlsson32baf622009-09-12 06:04:24 +0000130 llvm::BasicBlock *CastNull = 0;
131 llvm::BasicBlock *CastNotNull = 0;
132 llvm::BasicBlock *CastEnd = 0;
133
134 if (NullCheckValue) {
135 CastNull = createBasicBlock("cast.null");
136 CastNotNull = createBasicBlock("cast.notnull");
137 CastEnd = createBasicBlock("cast.end");
138
139 llvm::Value *IsNull =
Anders Carlssona3697c92009-11-23 17:57:54 +0000140 Builder.CreateICmpEQ(Value,
141 llvm::Constant::getNullValue(Value->getType()));
Anders Carlsson32baf622009-09-12 06:04:24 +0000142 Builder.CreateCondBr(IsNull, CastNull, CastNotNull);
143 EmitBlock(CastNotNull);
144 }
145
Benjamin Kramer3c0ef8c2009-10-13 10:07:13 +0000146 const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext);
Eli Friedman4a5dc242009-11-10 22:48:10 +0000147
148 llvm::Value *Offset =
Anders Carlssona3697c92009-11-23 17:57:54 +0000149 GetCXXBaseClassOffset(*this, Value, ClassDecl, BaseClassDecl);
Anders Carlsson5d58a1d2009-09-12 04:27:24 +0000150
Eli Friedman4a5dc242009-11-10 22:48:10 +0000151 if (Offset) {
152 // Apply the offset.
Anders Carlssona3697c92009-11-23 17:57:54 +0000153 Value = Builder.CreateBitCast(Value, Int8PtrTy);
154 Value = Builder.CreateGEP(Value, Offset, "add.ptr");
Eli Friedman4a5dc242009-11-10 22:48:10 +0000155 }
Anders Carlsson5d58a1d2009-09-12 04:27:24 +0000156
Anders Carlsson5d58a1d2009-09-12 04:27:24 +0000157 // Cast back.
Anders Carlssona3697c92009-11-23 17:57:54 +0000158 Value = Builder.CreateBitCast(Value, BasePtrTy);
Anders Carlsson32baf622009-09-12 06:04:24 +0000159
160 if (NullCheckValue) {
161 Builder.CreateBr(CastEnd);
162 EmitBlock(CastNull);
163 Builder.CreateBr(CastEnd);
164 EmitBlock(CastEnd);
165
Anders Carlssona3697c92009-11-23 17:57:54 +0000166 llvm::PHINode *PHI = Builder.CreatePHI(Value->getType());
Anders Carlsson32baf622009-09-12 06:04:24 +0000167 PHI->reserveOperandSpace(2);
Anders Carlssona3697c92009-11-23 17:57:54 +0000168 PHI->addIncoming(Value, CastNotNull);
169 PHI->addIncoming(llvm::Constant::getNullValue(Value->getType()),
Anders Carlsson32baf622009-09-12 06:04:24 +0000170 CastNull);
Anders Carlssona3697c92009-11-23 17:57:54 +0000171 Value = PHI;
Anders Carlsson32baf622009-09-12 06:04:24 +0000172 }
Anders Carlsson5d58a1d2009-09-12 04:27:24 +0000173
Anders Carlssona3697c92009-11-23 17:57:54 +0000174 return Value;
175}
176
177llvm::Value *
178CodeGenFunction::GetAddressOfDerivedClass(llvm::Value *Value,
179 const CXXRecordDecl *ClassDecl,
180 const CXXRecordDecl *DerivedClassDecl,
181 bool NullCheckValue) {
182 QualType DerivedTy =
183 getContext().getCanonicalType(
184 getContext().getTypeDeclType(const_cast<CXXRecordDecl*>(DerivedClassDecl)));
185 const llvm::Type *DerivedPtrTy = ConvertType(DerivedTy)->getPointerTo();
186
187 if (ClassDecl == DerivedClassDecl) {
188 // Just cast back.
189 return Builder.CreateBitCast(Value, DerivedPtrTy);
190 }
191
192 llvm::BasicBlock *CastNull = 0;
193 llvm::BasicBlock *CastNotNull = 0;
194 llvm::BasicBlock *CastEnd = 0;
195
196 if (NullCheckValue) {
197 CastNull = createBasicBlock("cast.null");
198 CastNotNull = createBasicBlock("cast.notnull");
199 CastEnd = createBasicBlock("cast.end");
200
201 llvm::Value *IsNull =
202 Builder.CreateICmpEQ(Value,
203 llvm::Constant::getNullValue(Value->getType()));
204 Builder.CreateCondBr(IsNull, CastNull, CastNotNull);
205 EmitBlock(CastNotNull);
206 }
207
208 llvm::Value *Offset = GetCXXBaseClassOffset(*this, Value, DerivedClassDecl,
209 ClassDecl);
210 if (Offset) {
211 // Apply the offset.
212 Value = Builder.CreatePtrToInt(Value, Offset->getType());
213 Value = Builder.CreateSub(Value, Offset);
214 Value = Builder.CreateIntToPtr(Value, DerivedPtrTy);
215 } else {
216 // Just cast.
217 Value = Builder.CreateBitCast(Value, DerivedPtrTy);
218 }
219
220 if (NullCheckValue) {
221 Builder.CreateBr(CastEnd);
222 EmitBlock(CastNull);
223 Builder.CreateBr(CastEnd);
224 EmitBlock(CastEnd);
225
226 llvm::PHINode *PHI = Builder.CreatePHI(Value->getType());
227 PHI->reserveOperandSpace(2);
228 PHI->addIncoming(Value, CastNotNull);
229 PHI->addIncoming(llvm::Constant::getNullValue(Value->getType()),
230 CastNull);
231 Value = PHI;
232 }
233
234 return Value;
Anders Carlsson5d58a1d2009-09-12 04:27:24 +0000235}