blob: ff879f5786ffc7bc11f312d4f3b10f4e72a752f2 [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;
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,
75 /*RecordPaths=*/true, /*DetectVirtual=*/true);
76 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;
84 if (const RecordType *RT = Paths.getDetectedVirtual()) {
85 const CXXRecordDecl *VBase = cast<CXXRecordDecl>(RT->getDecl());
86
87 VirtualOffset =
88 CGF.GetVirtualCXXBaseClassOffset(BaseValue, ClassDecl, VBase);
89
90 const CXXBasePath &Path = Paths.front();
91 unsigned e = Path.size();
92 for (Start = 0; Start != e; ++Start) {
93 const CXXBasePathElement& Element = Path[Start];
94
95 if (Element.Class == VBase)
96 break;
97 }
98 }
99
100 uint64_t Offset =
101 ComputeNonVirtualBaseClassOffset(CGF.getContext(), Paths, Start);
102
103 if (!Offset)
104 return VirtualOffset;
105
106 const llvm::Type *PtrDiffTy =
107 CGF.ConvertType(CGF.getContext().getPointerDiffType());
108 llvm::Value *NonVirtualOffset = llvm::ConstantInt::get(PtrDiffTy, Offset);
109
110 if (VirtualOffset)
111 return CGF.Builder.CreateAdd(VirtualOffset, NonVirtualOffset);
112
113 return NonVirtualOffset;
114}
115
Anders Carlsson5d58a1d2009-09-12 04:27:24 +0000116llvm::Value *
117CodeGenFunction::GetAddressCXXOfBaseClass(llvm::Value *BaseValue,
118 const CXXRecordDecl *ClassDecl,
119 const CXXRecordDecl *BaseClassDecl,
120 bool NullCheckValue) {
Anders Carlssondfd03302009-09-22 21:58:22 +0000121 QualType BTy =
122 getContext().getCanonicalType(
123 getContext().getTypeDeclType(const_cast<CXXRecordDecl*>(BaseClassDecl)));
124 const llvm::Type *BasePtrTy = llvm::PointerType::getUnqual(ConvertType(BTy));
Anders Carlsson5d58a1d2009-09-12 04:27:24 +0000125
Anders Carlsson2f1986b2009-10-06 22:43:30 +0000126 if (ClassDecl == BaseClassDecl) {
Anders Carlssondfd03302009-09-22 21:58:22 +0000127 // Just cast back.
128 return Builder.CreateBitCast(BaseValue, BasePtrTy);
129 }
130
Anders Carlsson32baf622009-09-12 06:04:24 +0000131 llvm::BasicBlock *CastNull = 0;
132 llvm::BasicBlock *CastNotNull = 0;
133 llvm::BasicBlock *CastEnd = 0;
134
135 if (NullCheckValue) {
136 CastNull = createBasicBlock("cast.null");
137 CastNotNull = createBasicBlock("cast.notnull");
138 CastEnd = createBasicBlock("cast.end");
139
140 llvm::Value *IsNull =
141 Builder.CreateICmpEQ(BaseValue,
142 llvm::Constant::getNullValue(BaseValue->getType()));
143 Builder.CreateCondBr(IsNull, CastNull, CastNotNull);
144 EmitBlock(CastNotNull);
145 }
146
Anders Carlsson5d58a1d2009-09-12 04:27:24 +0000147 const llvm::Type *Int8PtrTy =
148 llvm::PointerType::getUnqual(llvm::Type::getInt8Ty(VMContext));
Anders Carlsson2f1986b2009-10-06 22:43:30 +0000149
150 llvm::Value *Offset =
151 GetCXXBaseClassOffset(*this, BaseValue, ClassDecl, BaseClassDecl);
Anders Carlsson5d58a1d2009-09-12 04:27:24 +0000152
Anders Carlsson2f1986b2009-10-06 22:43:30 +0000153 if (Offset) {
154 // Apply the offset.
155 BaseValue = Builder.CreateBitCast(BaseValue, Int8PtrTy);
156 BaseValue = Builder.CreateGEP(BaseValue, Offset, "add.ptr");
157 }
Anders Carlsson5d58a1d2009-09-12 04:27:24 +0000158
Anders Carlsson5d58a1d2009-09-12 04:27:24 +0000159 // Cast back.
Anders Carlssondfd03302009-09-22 21:58:22 +0000160 BaseValue = Builder.CreateBitCast(BaseValue, BasePtrTy);
Anders Carlsson32baf622009-09-12 06:04:24 +0000161
162 if (NullCheckValue) {
163 Builder.CreateBr(CastEnd);
164 EmitBlock(CastNull);
165 Builder.CreateBr(CastEnd);
166 EmitBlock(CastEnd);
167
168 llvm::PHINode *PHI = Builder.CreatePHI(BaseValue->getType());
169 PHI->reserveOperandSpace(2);
170 PHI->addIncoming(BaseValue, CastNotNull);
171 PHI->addIncoming(llvm::Constant::getNullValue(BaseValue->getType()),
172 CastNull);
173 BaseValue = PHI;
174 }
Anders Carlsson5d58a1d2009-09-12 04:27:24 +0000175
176 return BaseValue;
177}