blob: 0ee1469e097a2ab2e5b051b8f1c6038cd79449c8 [file] [log] [blame]
Anders Carlsson59486a22009-11-24 05:51:11 +00001//===--- CGClass.cpp - Emit LLVM Code for C++ classes ---------------------===//
Anders Carlsson9a57c5a2009-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 Carlssonc6d171e2009-10-06 22:43:30 +000015#include "clang/AST/CXXInheritance.h"
Anders Carlsson9a57c5a2009-09-12 04:27:24 +000016#include "clang/AST/RecordLayout.h"
Anders Carlssonc6d171e2009-10-06 22:43:30 +000017
Anders Carlsson9a57c5a2009-09-12 04:27:24 +000018using namespace clang;
19using namespace CodeGen;
20
Anders Carlssonc6d171e2009-10-06 22:43:30 +000021static uint64_t
22ComputeNonVirtualBaseClassOffset(ASTContext &Context, CXXBasePaths &Paths,
23 unsigned Start) {
24 uint64_t Offset = 0;
Anders Carlsson9a57c5a2009-09-12 04:27:24 +000025
Anders Carlssonc6d171e2009-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 Carlsson9a57c5a2009-09-12 04:27:24 +000029
Anders Carlssonc6d171e2009-10-06 22:43:30 +000030 // Get the layout.
31 const ASTRecordLayout &Layout = Context.getASTRecordLayout(Element.Class);
Anders Carlsson9a57c5a2009-09-12 04:27:24 +000032
Anders Carlssonc6d171e2009-10-06 22:43:30 +000033 const CXXBaseSpecifier *BS = Element.Base;
Mike Stump88fc7d42009-11-13 18:53:35 +000034 // FIXME: enable test3 from virt.cc to not abort.
35 if (BS->isVirtual())
36 return 0;
Anders Carlssonc6d171e2009-10-06 22:43:30 +000037 assert(!BS->isVirtual() && "Should not see virtual bases here!");
Anders Carlsson9a57c5a2009-09-12 04:27:24 +000038
Anders Carlssonc6d171e2009-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 Carlsson9a57c5a2009-09-12 04:27:24 +000047}
48
Anders Carlsson9150a2a2009-09-29 03:13:20 +000049llvm::Constant *
Anders Carlsson32bfb1c2009-10-03 14:56:57 +000050CodeGenModule::GetCXXBaseClassOffset(const CXXRecordDecl *ClassDecl,
51 const CXXRecordDecl *BaseClassDecl) {
Anders Carlsson9150a2a2009-09-29 03:13:20 +000052 if (ClassDecl == BaseClassDecl)
53 return 0;
54
Anders Carlssonc6d171e2009-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 Carlsson9150a2a2009-09-29 03:13:20 +000062
Anders Carlssonc6d171e2009-10-06 22:43:30 +000063 uint64_t Offset = ComputeNonVirtualBaseClassOffset(getContext(), Paths, 0);
Anders Carlsson9150a2a2009-09-29 03:13:20 +000064 if (!Offset)
65 return 0;
66
Anders Carlsson32bfb1c2009-10-03 14:56:57 +000067 const llvm::Type *PtrDiffTy =
68 Types.ConvertType(getContext().getPointerDiffType());
Anders Carlsson9150a2a2009-09-29 03:13:20 +000069
70 return llvm::ConstantInt::get(PtrDiffTy, Offset);
71}
72
Anders Carlssonc6d171e2009-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,
Eli Friedman78910a52009-11-28 03:31:34 +000078 /*RecordPaths=*/true, /*DetectVirtual=*/false);
Anders Carlssonc6d171e2009-10-06 22:43:30 +000079 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;
Eli Friedman78910a52009-11-28 03:31:34 +000087
88 const CXXBasePath &Path = Paths.front();
89 const CXXRecordDecl *VBase = 0;
90 for (unsigned i = 0, e = Path.size(); i != e; ++i) {
91 const CXXBasePathElement& Element = Path[i];
92 if (Element.Base->isVirtual()) {
93 Start = i+1;
94 QualType VBaseType = Element.Base->getType();
95 VBase = cast<CXXRecordDecl>(VBaseType->getAs<RecordType>()->getDecl());
Anders Carlssonc6d171e2009-10-06 22:43:30 +000096 }
97 }
Eli Friedman78910a52009-11-28 03:31:34 +000098 if (VBase)
99 VirtualOffset =
100 CGF.GetVirtualCXXBaseClassOffset(BaseValue, ClassDecl, VBase);
Anders Carlssonc6d171e2009-10-06 22:43:30 +0000101
102 uint64_t Offset =
103 ComputeNonVirtualBaseClassOffset(CGF.getContext(), Paths, Start);
104
105 if (!Offset)
106 return VirtualOffset;
107
108 const llvm::Type *PtrDiffTy =
109 CGF.ConvertType(CGF.getContext().getPointerDiffType());
110 llvm::Value *NonVirtualOffset = llvm::ConstantInt::get(PtrDiffTy, Offset);
111
112 if (VirtualOffset)
113 return CGF.Builder.CreateAdd(VirtualOffset, NonVirtualOffset);
114
115 return NonVirtualOffset;
116}
117
Anders Carlsson9a57c5a2009-09-12 04:27:24 +0000118llvm::Value *
Anders Carlsson8c793172009-11-23 17:57:54 +0000119CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value,
120 const CXXRecordDecl *ClassDecl,
121 const CXXRecordDecl *BaseClassDecl,
122 bool NullCheckValue) {
Anders Carlsson8fef09c2009-09-22 21:58:22 +0000123 QualType BTy =
124 getContext().getCanonicalType(
125 getContext().getTypeDeclType(const_cast<CXXRecordDecl*>(BaseClassDecl)));
126 const llvm::Type *BasePtrTy = llvm::PointerType::getUnqual(ConvertType(BTy));
Anders Carlsson9a57c5a2009-09-12 04:27:24 +0000127
Anders Carlssonc6d171e2009-10-06 22:43:30 +0000128 if (ClassDecl == BaseClassDecl) {
Anders Carlsson8fef09c2009-09-22 21:58:22 +0000129 // Just cast back.
Anders Carlsson8c793172009-11-23 17:57:54 +0000130 return Builder.CreateBitCast(Value, BasePtrTy);
Anders Carlsson8fef09c2009-09-22 21:58:22 +0000131 }
Eli Friedmand76f4382009-11-10 22:48:10 +0000132
Anders Carlsson360e7d02009-09-12 06:04:24 +0000133 llvm::BasicBlock *CastNull = 0;
134 llvm::BasicBlock *CastNotNull = 0;
135 llvm::BasicBlock *CastEnd = 0;
136
137 if (NullCheckValue) {
138 CastNull = createBasicBlock("cast.null");
139 CastNotNull = createBasicBlock("cast.notnull");
140 CastEnd = createBasicBlock("cast.end");
141
142 llvm::Value *IsNull =
Anders Carlsson8c793172009-11-23 17:57:54 +0000143 Builder.CreateICmpEQ(Value,
144 llvm::Constant::getNullValue(Value->getType()));
Anders Carlsson360e7d02009-09-12 06:04:24 +0000145 Builder.CreateCondBr(IsNull, CastNull, CastNotNull);
146 EmitBlock(CastNotNull);
147 }
148
Benjamin Kramerabd5b902009-10-13 10:07:13 +0000149 const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext);
Eli Friedmand76f4382009-11-10 22:48:10 +0000150
151 llvm::Value *Offset =
Anders Carlsson8c793172009-11-23 17:57:54 +0000152 GetCXXBaseClassOffset(*this, Value, ClassDecl, BaseClassDecl);
Anders Carlsson9a57c5a2009-09-12 04:27:24 +0000153
Eli Friedmand76f4382009-11-10 22:48:10 +0000154 if (Offset) {
155 // Apply the offset.
Anders Carlsson8c793172009-11-23 17:57:54 +0000156 Value = Builder.CreateBitCast(Value, Int8PtrTy);
157 Value = Builder.CreateGEP(Value, Offset, "add.ptr");
Eli Friedmand76f4382009-11-10 22:48:10 +0000158 }
Anders Carlsson9a57c5a2009-09-12 04:27:24 +0000159
Anders Carlsson9a57c5a2009-09-12 04:27:24 +0000160 // Cast back.
Anders Carlsson8c793172009-11-23 17:57:54 +0000161 Value = Builder.CreateBitCast(Value, BasePtrTy);
Anders Carlsson360e7d02009-09-12 06:04:24 +0000162
163 if (NullCheckValue) {
164 Builder.CreateBr(CastEnd);
165 EmitBlock(CastNull);
166 Builder.CreateBr(CastEnd);
167 EmitBlock(CastEnd);
168
Anders Carlsson8c793172009-11-23 17:57:54 +0000169 llvm::PHINode *PHI = Builder.CreatePHI(Value->getType());
Anders Carlsson360e7d02009-09-12 06:04:24 +0000170 PHI->reserveOperandSpace(2);
Anders Carlsson8c793172009-11-23 17:57:54 +0000171 PHI->addIncoming(Value, CastNotNull);
172 PHI->addIncoming(llvm::Constant::getNullValue(Value->getType()),
Anders Carlsson360e7d02009-09-12 06:04:24 +0000173 CastNull);
Anders Carlsson8c793172009-11-23 17:57:54 +0000174 Value = PHI;
Anders Carlsson360e7d02009-09-12 06:04:24 +0000175 }
Anders Carlsson9a57c5a2009-09-12 04:27:24 +0000176
Anders Carlsson8c793172009-11-23 17:57:54 +0000177 return Value;
178}
179
180llvm::Value *
181CodeGenFunction::GetAddressOfDerivedClass(llvm::Value *Value,
182 const CXXRecordDecl *ClassDecl,
183 const CXXRecordDecl *DerivedClassDecl,
184 bool NullCheckValue) {
185 QualType DerivedTy =
186 getContext().getCanonicalType(
187 getContext().getTypeDeclType(const_cast<CXXRecordDecl*>(DerivedClassDecl)));
188 const llvm::Type *DerivedPtrTy = ConvertType(DerivedTy)->getPointerTo();
189
190 if (ClassDecl == DerivedClassDecl) {
191 // Just cast back.
192 return Builder.CreateBitCast(Value, DerivedPtrTy);
193 }
194
195 llvm::BasicBlock *CastNull = 0;
196 llvm::BasicBlock *CastNotNull = 0;
197 llvm::BasicBlock *CastEnd = 0;
198
199 if (NullCheckValue) {
200 CastNull = createBasicBlock("cast.null");
201 CastNotNull = createBasicBlock("cast.notnull");
202 CastEnd = createBasicBlock("cast.end");
203
204 llvm::Value *IsNull =
205 Builder.CreateICmpEQ(Value,
206 llvm::Constant::getNullValue(Value->getType()));
207 Builder.CreateCondBr(IsNull, CastNull, CastNotNull);
208 EmitBlock(CastNotNull);
209 }
210
211 llvm::Value *Offset = GetCXXBaseClassOffset(*this, Value, DerivedClassDecl,
212 ClassDecl);
213 if (Offset) {
214 // Apply the offset.
215 Value = Builder.CreatePtrToInt(Value, Offset->getType());
216 Value = Builder.CreateSub(Value, Offset);
217 Value = Builder.CreateIntToPtr(Value, DerivedPtrTy);
218 } else {
219 // Just cast.
220 Value = Builder.CreateBitCast(Value, DerivedPtrTy);
221 }
222
223 if (NullCheckValue) {
224 Builder.CreateBr(CastEnd);
225 EmitBlock(CastNull);
226 Builder.CreateBr(CastEnd);
227 EmitBlock(CastEnd);
228
229 llvm::PHINode *PHI = Builder.CreatePHI(Value->getType());
230 PHI->reserveOperandSpace(2);
231 PHI->addIncoming(Value, CastNotNull);
232 PHI->addIncoming(llvm::Constant::getNullValue(Value->getType()),
233 CastNull);
234 Value = PHI;
235 }
236
237 return Value;
Anders Carlsson9a57c5a2009-09-12 04:27:24 +0000238}