blob: e122b95a7338ea0fa5182832c3c188af68621e90 [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"
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;
Mike Stumpa6604402009-11-13 18:53:35 +000034 // FIXME: enable test3 from virt.cc to not abort.
35 if (BS->isVirtual())
36 return 0;
Anders Carlsson2f1986b2009-10-06 22:43:30 +000037 assert(!BS->isVirtual() && "Should not see virtual bases here!");
Anders Carlsson5d58a1d2009-09-12 04:27:24 +000038
Anders Carlsson2f1986b2009-10-06 22:43:30 +000039 const CXXRecordDecl *Base =
40 cast<CXXRecordDecl>(BS->getType()->getAs<RecordType>()->getDecl());
41
42 // Add the offset.
43 Offset += Layout.getBaseClassOffset(Base) / 8;
44 }
45
46 return Offset;
Anders Carlsson5d58a1d2009-09-12 04:27:24 +000047}
48
Anders Carlsson84080ec2009-09-29 03:13:20 +000049llvm::Constant *
Anders Carlsson2b358352009-10-03 14:56:57 +000050CodeGenModule::GetCXXBaseClassOffset(const CXXRecordDecl *ClassDecl,
51 const CXXRecordDecl *BaseClassDecl) {
Anders Carlsson84080ec2009-09-29 03:13:20 +000052 if (ClassDecl == BaseClassDecl)
53 return 0;
54
Anders Carlsson2f1986b2009-10-06 22:43:30 +000055 CXXBasePaths Paths(/*FindAmbiguities=*/false,
56 /*RecordPaths=*/true, /*DetectVirtual=*/false);
57 if (!const_cast<CXXRecordDecl *>(ClassDecl)->
58 isDerivedFrom(const_cast<CXXRecordDecl *>(BaseClassDecl), Paths)) {
59 assert(false && "Class must be derived from the passed in base class!");
60 return 0;
61 }
Anders Carlsson84080ec2009-09-29 03:13:20 +000062
Anders Carlsson2f1986b2009-10-06 22:43:30 +000063 uint64_t Offset = ComputeNonVirtualBaseClassOffset(getContext(), Paths, 0);
Anders Carlsson84080ec2009-09-29 03:13:20 +000064 if (!Offset)
65 return 0;
66
Anders Carlsson2b358352009-10-03 14:56:57 +000067 const llvm::Type *PtrDiffTy =
68 Types.ConvertType(getContext().getPointerDiffType());
Anders Carlsson84080ec2009-09-29 03:13:20 +000069
70 return llvm::ConstantInt::get(PtrDiffTy, Offset);
71}
72
Anders Carlsson2f1986b2009-10-06 22:43:30 +000073static llvm::Value *GetCXXBaseClassOffset(CodeGenFunction &CGF,
74 llvm::Value *BaseValue,
75 const CXXRecordDecl *ClassDecl,
76 const CXXRecordDecl *BaseClassDecl) {
77 CXXBasePaths Paths(/*FindAmbiguities=*/false,
78 /*RecordPaths=*/true, /*DetectVirtual=*/true);
79 if (!const_cast<CXXRecordDecl *>(ClassDecl)->
80 isDerivedFrom(const_cast<CXXRecordDecl *>(BaseClassDecl), Paths)) {
81 assert(false && "Class must be derived from the passed in base class!");
82 return 0;
83 }
84
85 unsigned Start = 0;
86 llvm::Value *VirtualOffset = 0;
87 if (const RecordType *RT = Paths.getDetectedVirtual()) {
88 const CXXRecordDecl *VBase = cast<CXXRecordDecl>(RT->getDecl());
89
90 VirtualOffset =
91 CGF.GetVirtualCXXBaseClassOffset(BaseValue, ClassDecl, VBase);
92
93 const CXXBasePath &Path = Paths.front();
94 unsigned e = Path.size();
95 for (Start = 0; Start != e; ++Start) {
96 const CXXBasePathElement& Element = Path[Start];
97
98 if (Element.Class == VBase)
99 break;
100 }
101 }
102
103 uint64_t Offset =
104 ComputeNonVirtualBaseClassOffset(CGF.getContext(), Paths, Start);
105
106 if (!Offset)
107 return VirtualOffset;
108
109 const llvm::Type *PtrDiffTy =
110 CGF.ConvertType(CGF.getContext().getPointerDiffType());
111 llvm::Value *NonVirtualOffset = llvm::ConstantInt::get(PtrDiffTy, Offset);
112
113 if (VirtualOffset)
114 return CGF.Builder.CreateAdd(VirtualOffset, NonVirtualOffset);
115
116 return NonVirtualOffset;
117}
118
Anders Carlsson5d58a1d2009-09-12 04:27:24 +0000119llvm::Value *
Anders Carlssona3697c92009-11-23 17:57:54 +0000120CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value,
121 const CXXRecordDecl *ClassDecl,
122 const CXXRecordDecl *BaseClassDecl,
123 bool NullCheckValue) {
Anders Carlssondfd03302009-09-22 21:58:22 +0000124 QualType BTy =
125 getContext().getCanonicalType(
126 getContext().getTypeDeclType(const_cast<CXXRecordDecl*>(BaseClassDecl)));
127 const llvm::Type *BasePtrTy = llvm::PointerType::getUnqual(ConvertType(BTy));
Anders Carlsson5d58a1d2009-09-12 04:27:24 +0000128
Anders Carlsson2f1986b2009-10-06 22:43:30 +0000129 if (ClassDecl == BaseClassDecl) {
Anders Carlssondfd03302009-09-22 21:58:22 +0000130 // Just cast back.
Anders Carlssona3697c92009-11-23 17:57:54 +0000131 return Builder.CreateBitCast(Value, BasePtrTy);
Anders Carlssondfd03302009-09-22 21:58:22 +0000132 }
Eli Friedman4a5dc242009-11-10 22:48:10 +0000133
Anders Carlsson32baf622009-09-12 06:04:24 +0000134 llvm::BasicBlock *CastNull = 0;
135 llvm::BasicBlock *CastNotNull = 0;
136 llvm::BasicBlock *CastEnd = 0;
137
138 if (NullCheckValue) {
139 CastNull = createBasicBlock("cast.null");
140 CastNotNull = createBasicBlock("cast.notnull");
141 CastEnd = createBasicBlock("cast.end");
142
143 llvm::Value *IsNull =
Anders Carlssona3697c92009-11-23 17:57:54 +0000144 Builder.CreateICmpEQ(Value,
145 llvm::Constant::getNullValue(Value->getType()));
Anders Carlsson32baf622009-09-12 06:04:24 +0000146 Builder.CreateCondBr(IsNull, CastNull, CastNotNull);
147 EmitBlock(CastNotNull);
148 }
149
Benjamin Kramer3c0ef8c2009-10-13 10:07:13 +0000150 const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext);
Eli Friedman4a5dc242009-11-10 22:48:10 +0000151
152 llvm::Value *Offset =
Anders Carlssona3697c92009-11-23 17:57:54 +0000153 GetCXXBaseClassOffset(*this, Value, ClassDecl, BaseClassDecl);
Anders Carlsson5d58a1d2009-09-12 04:27:24 +0000154
Eli Friedman4a5dc242009-11-10 22:48:10 +0000155 if (Offset) {
156 // Apply the offset.
Anders Carlssona3697c92009-11-23 17:57:54 +0000157 Value = Builder.CreateBitCast(Value, Int8PtrTy);
158 Value = Builder.CreateGEP(Value, Offset, "add.ptr");
Eli Friedman4a5dc242009-11-10 22:48:10 +0000159 }
Anders Carlsson5d58a1d2009-09-12 04:27:24 +0000160
Anders Carlsson5d58a1d2009-09-12 04:27:24 +0000161 // Cast back.
Anders Carlssona3697c92009-11-23 17:57:54 +0000162 Value = Builder.CreateBitCast(Value, BasePtrTy);
Anders Carlsson32baf622009-09-12 06:04:24 +0000163
164 if (NullCheckValue) {
165 Builder.CreateBr(CastEnd);
166 EmitBlock(CastNull);
167 Builder.CreateBr(CastEnd);
168 EmitBlock(CastEnd);
169
Anders Carlssona3697c92009-11-23 17:57:54 +0000170 llvm::PHINode *PHI = Builder.CreatePHI(Value->getType());
Anders Carlsson32baf622009-09-12 06:04:24 +0000171 PHI->reserveOperandSpace(2);
Anders Carlssona3697c92009-11-23 17:57:54 +0000172 PHI->addIncoming(Value, CastNotNull);
173 PHI->addIncoming(llvm::Constant::getNullValue(Value->getType()),
Anders Carlsson32baf622009-09-12 06:04:24 +0000174 CastNull);
Anders Carlssona3697c92009-11-23 17:57:54 +0000175 Value = PHI;
Anders Carlsson32baf622009-09-12 06:04:24 +0000176 }
Anders Carlsson5d58a1d2009-09-12 04:27:24 +0000177
Anders Carlssona3697c92009-11-23 17:57:54 +0000178 return Value;
179}
180
181llvm::Value *
182CodeGenFunction::GetAddressOfDerivedClass(llvm::Value *Value,
183 const CXXRecordDecl *ClassDecl,
184 const CXXRecordDecl *DerivedClassDecl,
185 bool NullCheckValue) {
186 QualType DerivedTy =
187 getContext().getCanonicalType(
188 getContext().getTypeDeclType(const_cast<CXXRecordDecl*>(DerivedClassDecl)));
189 const llvm::Type *DerivedPtrTy = ConvertType(DerivedTy)->getPointerTo();
190
191 if (ClassDecl == DerivedClassDecl) {
192 // Just cast back.
193 return Builder.CreateBitCast(Value, DerivedPtrTy);
194 }
195
196 llvm::BasicBlock *CastNull = 0;
197 llvm::BasicBlock *CastNotNull = 0;
198 llvm::BasicBlock *CastEnd = 0;
199
200 if (NullCheckValue) {
201 CastNull = createBasicBlock("cast.null");
202 CastNotNull = createBasicBlock("cast.notnull");
203 CastEnd = createBasicBlock("cast.end");
204
205 llvm::Value *IsNull =
206 Builder.CreateICmpEQ(Value,
207 llvm::Constant::getNullValue(Value->getType()));
208 Builder.CreateCondBr(IsNull, CastNull, CastNotNull);
209 EmitBlock(CastNotNull);
210 }
211
212 llvm::Value *Offset = GetCXXBaseClassOffset(*this, Value, DerivedClassDecl,
213 ClassDecl);
214 if (Offset) {
215 // Apply the offset.
216 Value = Builder.CreatePtrToInt(Value, Offset->getType());
217 Value = Builder.CreateSub(Value, Offset);
218 Value = Builder.CreateIntToPtr(Value, DerivedPtrTy);
219 } else {
220 // Just cast.
221 Value = Builder.CreateBitCast(Value, DerivedPtrTy);
222 }
223
224 if (NullCheckValue) {
225 Builder.CreateBr(CastEnd);
226 EmitBlock(CastNull);
227 Builder.CreateBr(CastEnd);
228 EmitBlock(CastEnd);
229
230 llvm::PHINode *PHI = Builder.CreatePHI(Value->getType());
231 PHI->reserveOperandSpace(2);
232 PHI->addIncoming(Value, CastNotNull);
233 PHI->addIncoming(llvm::Constant::getNullValue(Value->getType()),
234 CastNull);
235 Value = PHI;
236 }
237
238 return Value;
Anders Carlsson5d58a1d2009-09-12 04:27:24 +0000239}