blob: 5d7b8a022c71636f3a111fd39155a8b5df2b43d5 [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"
15#include "clang/AST/RecordLayout.h"
16using namespace clang;
17using namespace CodeGen;
18
19static bool
20GetNestedPaths(llvm::SmallVectorImpl<const CXXRecordDecl *> &NestedBasePaths,
21 const CXXRecordDecl *ClassDecl,
22 const CXXRecordDecl *BaseClassDecl) {
23 for (CXXRecordDecl::base_class_const_iterator i = ClassDecl->bases_begin(),
24 e = ClassDecl->bases_end(); i != e; ++i) {
25 if (i->isVirtual())
26 continue;
27 const CXXRecordDecl *Base =
28 cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
29 if (Base == BaseClassDecl) {
30 NestedBasePaths.push_back(BaseClassDecl);
31 return true;
32 }
33 }
34 // BaseClassDecl not an immediate base of ClassDecl.
35 for (CXXRecordDecl::base_class_const_iterator i = ClassDecl->bases_begin(),
36 e = ClassDecl->bases_end(); i != e; ++i) {
37 if (i->isVirtual())
38 continue;
39 const CXXRecordDecl *Base =
40 cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
41 if (GetNestedPaths(NestedBasePaths, Base, BaseClassDecl)) {
42 NestedBasePaths.push_back(Base);
43 return true;
44 }
45 }
46 return false;
47}
48
49static uint64_t ComputeBaseClassOffset(ASTContext &Context,
50 const CXXRecordDecl *ClassDecl,
51 const CXXRecordDecl *BaseClassDecl) {
52 uint64_t Offset = 0;
53
54 llvm::SmallVector<const CXXRecordDecl *, 16> NestedBasePaths;
55 GetNestedPaths(NestedBasePaths, ClassDecl, BaseClassDecl);
56 assert(NestedBasePaths.size() > 0 &&
57 "AddressCXXOfBaseClass - inheritence path failed");
58 NestedBasePaths.push_back(ClassDecl);
59
60 for (unsigned i = NestedBasePaths.size() - 1; i > 0; i--) {
61 const CXXRecordDecl *DerivedClass = NestedBasePaths[i];
62 const CXXRecordDecl *BaseClass = NestedBasePaths[i-1];
63 const ASTRecordLayout &Layout =
64 Context.getASTRecordLayout(DerivedClass);
65
66 Offset += Layout.getBaseClassOffset(BaseClass) / 8;
67 }
68
69 return Offset;
70}
71
Anders Carlsson84080ec2009-09-29 03:13:20 +000072llvm::Constant *
73CodeGenFunction::GetCXXBaseClassOffset(const CXXRecordDecl *ClassDecl,
74 const CXXRecordDecl *BaseClassDecl) {
75 if (ClassDecl == BaseClassDecl)
76 return 0;
77
78 QualType BTy =
79 getContext().getCanonicalType(
80 getContext().getTypeDeclType(const_cast<CXXRecordDecl*>(BaseClassDecl)));
81
82 uint64_t Offset = ComputeBaseClassOffset(getContext(),
83 ClassDecl, BaseClassDecl);
84 if (!Offset)
85 return 0;
86
87 const llvm::Type *PtrDiffTy = ConvertType(getContext().getPointerDiffType());
88
89 return llvm::ConstantInt::get(PtrDiffTy, Offset);
90}
91
Anders Carlsson5d58a1d2009-09-12 04:27:24 +000092llvm::Value *
93CodeGenFunction::GetAddressCXXOfBaseClass(llvm::Value *BaseValue,
94 const CXXRecordDecl *ClassDecl,
95 const CXXRecordDecl *BaseClassDecl,
96 bool NullCheckValue) {
Anders Carlsson84080ec2009-09-29 03:13:20 +000097 llvm::Constant *Offset = GetCXXBaseClassOffset(ClassDecl, BaseClassDecl);
98
Anders Carlssondfd03302009-09-22 21:58:22 +000099 QualType BTy =
100 getContext().getCanonicalType(
101 getContext().getTypeDeclType(const_cast<CXXRecordDecl*>(BaseClassDecl)));
102 const llvm::Type *BasePtrTy = llvm::PointerType::getUnqual(ConvertType(BTy));
Anders Carlsson5d58a1d2009-09-12 04:27:24 +0000103
Anders Carlssondfd03302009-09-22 21:58:22 +0000104 if (!Offset) {
105 // Just cast back.
106 return Builder.CreateBitCast(BaseValue, BasePtrTy);
107 }
108
Anders Carlsson32baf622009-09-12 06:04:24 +0000109 llvm::BasicBlock *CastNull = 0;
110 llvm::BasicBlock *CastNotNull = 0;
111 llvm::BasicBlock *CastEnd = 0;
112
113 if (NullCheckValue) {
114 CastNull = createBasicBlock("cast.null");
115 CastNotNull = createBasicBlock("cast.notnull");
116 CastEnd = createBasicBlock("cast.end");
117
118 llvm::Value *IsNull =
119 Builder.CreateICmpEQ(BaseValue,
120 llvm::Constant::getNullValue(BaseValue->getType()));
121 Builder.CreateCondBr(IsNull, CastNull, CastNotNull);
122 EmitBlock(CastNotNull);
123 }
124
Anders Carlsson5d58a1d2009-09-12 04:27:24 +0000125 const llvm::Type *Int8PtrTy =
126 llvm::PointerType::getUnqual(llvm::Type::getInt8Ty(VMContext));
127
Anders Carlsson5d58a1d2009-09-12 04:27:24 +0000128 // Apply the offset.
129 BaseValue = Builder.CreateBitCast(BaseValue, Int8PtrTy);
Anders Carlsson84080ec2009-09-29 03:13:20 +0000130 BaseValue = Builder.CreateGEP(BaseValue, Offset, "add.ptr");
Anders Carlsson5d58a1d2009-09-12 04:27:24 +0000131
Anders Carlsson5d58a1d2009-09-12 04:27:24 +0000132 // Cast back.
Anders Carlssondfd03302009-09-22 21:58:22 +0000133 BaseValue = Builder.CreateBitCast(BaseValue, BasePtrTy);
Anders Carlsson32baf622009-09-12 06:04:24 +0000134
135 if (NullCheckValue) {
136 Builder.CreateBr(CastEnd);
137 EmitBlock(CastNull);
138 Builder.CreateBr(CastEnd);
139 EmitBlock(CastEnd);
140
141 llvm::PHINode *PHI = Builder.CreatePHI(BaseValue->getType());
142 PHI->reserveOperandSpace(2);
143 PHI->addIncoming(BaseValue, CastNotNull);
144 PHI->addIncoming(llvm::Constant::getNullValue(BaseValue->getType()),
145 CastNull);
146 BaseValue = PHI;
147 }
Anders Carlsson5d58a1d2009-09-12 04:27:24 +0000148
149 return BaseValue;
150}