Mercurial > projects > ldc
comparison ir/irclass.cpp @ 1228:79758fd2f48a
Added Doxygen file.
Completely seperated type and symbol generation. Should fix a lot of bugs, but is not yet 100% complete.
author | Tomas Lindquist Olsen <tomas.l.olsen gmail.com> |
---|---|
date | Wed, 15 Apr 2009 20:06:25 +0200 |
parents | |
children | fafe7c8d6734 |
comparison
equal
deleted
inserted
replaced
1215:08f87d8cd101 | 1228:79758fd2f48a |
---|---|
1 #include "llvm/Constants.h" | |
2 #include "llvm/DerivedTypes.h" | |
3 | |
4 #include "aggregate.h" | |
5 #include "declaration.h" | |
6 #include "mtype.h" | |
7 | |
8 #include "gen/irstate.h" | |
9 #include "gen/logger.h" | |
10 #include "gen/tollvm.h" | |
11 #include "gen/llvmhelpers.h" | |
12 #include "gen/utils.h" | |
13 #include "gen/arrays.h" | |
14 | |
15 #include "ir/irstruct.h" | |
16 #include "ir/irtypeclass.h" | |
17 | |
18 ////////////////////////////////////////////////////////////////////////////// | |
19 | |
20 extern LLConstant* get_default_initializer(VarDeclaration* vd, Initializer* init); | |
21 extern size_t add_zeros(std::vector<llvm::Constant*>& constants, size_t diff); | |
22 | |
23 extern LLConstant* DtoDefineClassInfo(ClassDeclaration* cd); | |
24 | |
25 ////////////////////////////////////////////////////////////////////////////// | |
26 | |
27 LLGlobalVariable * IrStruct::getVtblSymbol() | |
28 { | |
29 if (vtbl) | |
30 return vtbl; | |
31 | |
32 // create the initZ symbol | |
33 std::string initname("_D"); | |
34 initname.append(aggrdecl->mangle()); | |
35 initname.append("6__vtblZ"); | |
36 | |
37 llvm::GlobalValue::LinkageTypes _linkage = DtoExternalLinkage(aggrdecl); | |
38 | |
39 const LLType* vtblTy = type->irtype->isClass()->getVtbl(); | |
40 | |
41 vtbl = new llvm::GlobalVariable( | |
42 vtblTy, true, _linkage, NULL, initname, gIR->module); | |
43 | |
44 return vtbl; | |
45 } | |
46 | |
47 ////////////////////////////////////////////////////////////////////////////// | |
48 | |
49 LLGlobalVariable * IrStruct::getClassInfoSymbol() | |
50 { | |
51 if (classInfo) | |
52 return classInfo; | |
53 | |
54 // create the initZ symbol | |
55 std::string initname("_D"); | |
56 initname.append(aggrdecl->mangle()); | |
57 if (aggrdecl->isInterfaceDeclaration()) | |
58 initname.append("11__InterfaceZ"); | |
59 else | |
60 initname.append("7__ClassZ"); | |
61 | |
62 llvm::GlobalValue::LinkageTypes _linkage = DtoExternalLinkage(aggrdecl); | |
63 | |
64 ClassDeclaration* cinfo = ClassDeclaration::classinfo; | |
65 DtoType(cinfo->type); | |
66 IrTypeClass* tc = cinfo->type->irtype->isClass(); | |
67 assert(tc && "invalid ClassInfo type"); | |
68 | |
69 classInfo = new llvm::GlobalVariable( | |
70 tc->getPA().get(), true, _linkage, NULL, initname, gIR->module); | |
71 | |
72 return classInfo; | |
73 } | |
74 | |
75 ////////////////////////////////////////////////////////////////////////////// | |
76 | |
77 LLGlobalVariable * IrStruct::getInterfaceArraySymbol() | |
78 { | |
79 if (classInterfacesArray) | |
80 return classInterfacesArray; | |
81 | |
82 ClassDeclaration* cd = aggrdecl->isClassDeclaration(); | |
83 | |
84 assert(cd->vtblInterfaces && cd->vtblInterfaces->dim > 0 && | |
85 "should not create interface info array for class with no explicit " | |
86 "interface implementations") | |
87 | |
88 VarDeclarationIter idx(ClassDeclaration::classinfo->fields, 3); | |
89 const llvm::Type* InterfaceTy = DtoType(idx->type); | |
90 | |
91 // create Interface[N] | |
92 const llvm::ArrayType* array_type = llvm::ArrayType::get( | |
93 InterfaceTy, | |
94 cd->vtblInterfaces->dim); | |
95 | |
96 // put it in a global | |
97 std::string name("_D"); | |
98 name.append(cd->mangle()); | |
99 name.append("16__interfaceInfosZ"); | |
100 classInterfacesArray = new llvm::GlobalVariable(array_type, true, DtoLinkage(cd), NULL, name, classInfo); | |
101 | |
102 return classInterfacesArray; | |
103 } | |
104 | |
105 ////////////////////////////////////////////////////////////////////////////// | |
106 | |
107 LLConstant * IrStruct::getVtblInit() | |
108 { | |
109 if (constVtbl) | |
110 return constVtbl; | |
111 | |
112 IF_LOG Logger::println("Building vtbl initializer"); | |
113 LOG_SCOPE; | |
114 | |
115 ClassDeclaration* cd = aggrdecl->isClassDeclaration(); | |
116 assert(cd && "not class"); | |
117 | |
118 std::vector<llvm::Constant*> constants; | |
119 constants.reserve(cd->vtbl.dim); | |
120 | |
121 // start with the classinfo | |
122 llvm::Constant* c = getClassInfoSymbol(); | |
123 c = DtoBitCast(c, DtoType(ClassDeclaration::classinfo->type)); | |
124 constants.push_back(c); | |
125 | |
126 // add virtual function pointers | |
127 size_t n = cd->vtbl.dim; | |
128 for (size_t i = 1; i < n; i++) | |
129 { | |
130 Dsymbol* dsym = (Dsymbol*)cd->vtbl.data[i]; | |
131 assert(dsym && "null vtbl member"); | |
132 | |
133 FuncDeclaration* fd = dsym->isFuncDeclaration(); | |
134 assert(fd && "vtbl entry not a function"); | |
135 | |
136 if (fd->isAbstract() && !fd->fbody) | |
137 { | |
138 c = getNullValue(DtoType(fd->type->pointerTo())); | |
139 } | |
140 else | |
141 { | |
142 fd->codegen(Type::sir); | |
143 assert(fd->ir.irFunc && "invalid vtbl function"); | |
144 c = fd->ir.irFunc->func; | |
145 } | |
146 constants.push_back(c); | |
147 } | |
148 | |
149 // build the constant struct | |
150 constVtbl = llvm::ConstantStruct::get(constants, false); | |
151 | |
152 // sanity check | |
153 #if 0 | |
154 IF_LOG Logger::cout() << "constVtbl type: " << *constVtbl->getType() << std::endl; | |
155 IF_LOG Logger::cout() << "vtbl type: " << *type->irtype->isClass()->getVtbl() << std::endl; | |
156 #endif | |
157 | |
158 assert(constVtbl->getType() == type->irtype->isClass()->getVtbl() && | |
159 "vtbl initializer type mismatch"); | |
160 | |
161 return constVtbl; | |
162 } | |
163 | |
164 ////////////////////////////////////////////////////////////////////////////// | |
165 | |
166 LLConstant * IrStruct::getClassInfoInit() | |
167 { | |
168 if (constClassInfo) | |
169 return constClassInfo; | |
170 constClassInfo = DtoDefineClassInfo(aggrdecl->isClassDeclaration()); | |
171 return constClassInfo; | |
172 } | |
173 | |
174 ////////////////////////////////////////////////////////////////////////////// | |
175 | |
176 void IrStruct::addBaseClassInits( | |
177 std::vector<llvm::Constant*>& constants, | |
178 ClassDeclaration* base, | |
179 size_t& offset, | |
180 size_t& field_index) | |
181 { | |
182 if (base->baseClass) | |
183 { | |
184 addBaseClassInits(constants, base->baseClass, offset, field_index); | |
185 } | |
186 | |
187 ArrayIter<VarDeclaration> it(base->fields); | |
188 for (; !it.done(); it.next()) | |
189 { | |
190 VarDeclaration* vd = it.get(); | |
191 | |
192 // skip if offset moved backwards | |
193 if (vd->offset < offset) | |
194 { | |
195 IF_LOG Logger::println("Skipping field %s %s (+%u) for default", vd->type->toChars(), vd->toChars(), vd->offset); | |
196 continue; | |
197 } | |
198 | |
199 IF_LOG Logger::println("Adding default field %s %s (+%u)", vd->type->toChars(), vd->toChars(), vd->offset); | |
200 LOG_SCOPE; | |
201 | |
202 // get next aligned offset for this type | |
203 size_t alignsize = vd->type->alignsize(); | |
204 size_t alignedoffset = (offset + alignsize - 1) & ~(alignsize - 1); | |
205 | |
206 // insert explicit padding? | |
207 if (alignedoffset < vd->offset) | |
208 { | |
209 add_zeros(constants, vd->offset - alignedoffset); | |
210 } | |
211 | |
212 // add default type | |
213 constants.push_back(get_default_initializer(vd, vd->init)); | |
214 | |
215 // advance offset to right past this field | |
216 offset = vd->offset + vd->type->size(); | |
217 } | |
218 | |
219 // has interface vtbls? | |
220 if (base->vtblInterfaces) | |
221 { | |
222 // false when it's not okay to use functions from super classes | |
223 bool newinsts = (base == aggrdecl->isClassDeclaration()); | |
224 | |
225 ArrayIter<BaseClass> it2(*base->vtblInterfaces); | |
226 for (; !it2.done(); it2.next()) | |
227 { | |
228 BaseClass* b = it2.get(); | |
229 constants.push_back(getInterfaceVtbl(b, newinsts)); | |
230 offset += PTRSIZE; | |
231 } | |
232 } | |
233 | |
234 // tail padding? | |
235 if (offset < base->structsize) | |
236 { | |
237 add_zeros(constants, base->structsize - offset); | |
238 offset = base->structsize; | |
239 } | |
240 } | |
241 | |
242 ////////////////////////////////////////////////////////////////////////////// | |
243 | |
244 LLConstant * IrStruct::createClassDefaultInitializer() | |
245 { | |
246 ClassDeclaration* cd = aggrdecl->isClassDeclaration(); | |
247 assert(cd && "invalid class aggregate"); | |
248 | |
249 IF_LOG Logger::println("Building class default initializer %s @ %s", cd->toPrettyChars(), cd->locToChars()); | |
250 LOG_SCOPE; | |
251 IF_LOG Logger::println("Instance size: %u", cd->structsize); | |
252 | |
253 // find the fields that contribute to the default initializer. | |
254 // these will define the default type. | |
255 | |
256 std::vector<llvm::Constant*> constants; | |
257 constants.reserve(32); | |
258 | |
259 // add vtbl | |
260 constants.push_back(getVtblSymbol()); | |
261 // add monitor | |
262 constants.push_back(getNullValue(DtoType(Type::tvoid->pointerTo()))); | |
263 | |
264 // we start right after the vtbl and monitor | |
265 size_t offset = PTRSIZE * 2; | |
266 size_t field_index = 2; | |
267 | |
268 // add data members recursively | |
269 addBaseClassInits(constants, cd, offset, field_index); | |
270 | |
271 // build the constant | |
272 llvm::Constant* definit = llvm::ConstantStruct::get(constants, false); | |
273 | |
274 // sanity check | |
275 assert(definit->getType() == type->irtype->getPA().get() && "class initializer type mismatch"); | |
276 | |
277 return definit; | |
278 } | |
279 | |
280 ////////////////////////////////////////////////////////////////////////////// | |
281 | |
282 llvm::GlobalVariable * IrStruct::getInterfaceVtbl(BaseClass * b, bool new_instance) | |
283 { | |
284 ClassDeclaration* cd = aggrdecl->isClassDeclaration(); | |
285 assert(cd && "not a class aggregate"); | |
286 | |
287 ClassGlobalMap::iterator it = interfaceVtblMap.find(cd); | |
288 if (it != interfaceVtblMap.end()) | |
289 return it->second; | |
290 | |
291 IF_LOG Logger::println("Building vtbl for implementation of interface %s in class %s", | |
292 b->base->toPrettyChars(), aggrdecl->toPrettyChars()); | |
293 LOG_SCOPE; | |
294 | |
295 Array vtbl_array; | |
296 b->fillVtbl(cd, &vtbl_array, new_instance); | |
297 | |
298 std::vector<llvm::Constant*> constants; | |
299 constants.reserve(vtbl_array.dim); | |
300 | |
301 // start with the interface info | |
302 llvm::Constant* c = getNullValue(DtoType(Type::tvoid->pointerTo())); | |
303 constants.push_back(c); | |
304 | |
305 // add virtual function pointers | |
306 size_t n = vtbl_array.dim; | |
307 for (size_t i = 1; i < n; i++) | |
308 { | |
309 Dsymbol* dsym = (Dsymbol*)vtbl_array.data[i]; | |
310 assert(dsym && "null vtbl member"); | |
311 | |
312 FuncDeclaration* fd = dsym->isFuncDeclaration(); | |
313 assert(fd && "vtbl entry not a function"); | |
314 | |
315 assert(!(fd->isAbstract() && !fd->fbody) && | |
316 "null symbol in interface implementation vtable"); | |
317 | |
318 fd->codegen(Type::sir); | |
319 assert(fd->ir.irFunc && "invalid vtbl function"); | |
320 | |
321 constants.push_back(fd->ir.irFunc->func); | |
322 } | |
323 | |
324 // build the vtbl constant | |
325 llvm::Constant* vtbl_constant = llvm::ConstantStruct::get(constants, false); | |
326 | |
327 // create the global variable to hold it | |
328 llvm::GlobalValue::LinkageTypes _linkage = DtoExternalLinkage(aggrdecl); | |
329 | |
330 std::string mangle("_D"); | |
331 mangle.append(cd->mangle()); | |
332 mangle.append("11__interface"); | |
333 mangle.append(b->base->mangle()); | |
334 mangle.append("6__vtblZ"); | |
335 | |
336 llvm::GlobalVariable* GV = new llvm::GlobalVariable( | |
337 vtbl_constant->getType(), | |
338 true, | |
339 _linkage, | |
340 vtbl_constant, | |
341 mangle, | |
342 gIR->module | |
343 ); | |
344 | |
345 interfaceVtblMap.insert(std::make_pair(b->base, GV)); | |
346 | |
347 return GV; | |
348 } | |
349 | |
350 ////////////////////////////////////////////////////////////////////////////// | |
351 | |
352 LLConstant * IrStruct::getClassInfoInterfaces() | |
353 { | |
354 IF_LOG Logger::println("Building ClassInfo.interfaces"); | |
355 LOG_SCOPE; | |
356 | |
357 ClassDeclaration* cd = aggrdecl->isClassDeclaration(); | |
358 assert(cd); | |
359 | |
360 if (!cd->vtblInterfaces || cd->vtblInterfaces->dim == 0) | |
361 { | |
362 VarDeclarationIter idx(ClassDeclaration::classinfo->fields, 3); | |
363 return getNullValue(DtoType(idx->type)); | |
364 } | |
365 | |
366 // Build array of: | |
367 // | |
368 // struct Interface | |
369 // { | |
370 // ClassInfo classinfo; | |
371 // void*[] vtbl; | |
372 // ptrdiff_t offset; | |
373 // } | |
374 | |
375 LLSmallVector<LLConstant*, 6> constants; | |
376 constants.reserve(cd->vtblInterfaces->dim); | |
377 | |
378 const LLType* classinfo_type = DtoType(ClassDeclaration::classinfo->type); | |
379 const LLType* voidptrptr_type = DtoType( | |
380 Type::tvoid->pointerTo()->pointerTo()); | |
381 | |
382 const LLType* our_type = type->irtype->isClass()->getPA().get(); | |
383 | |
384 ArrayIter<BaseClass> it(*cd->vtblInterfaces); | |
385 while (it.more()) | |
386 { | |
387 IF_LOG Logger::println("Adding interface %s", it->base->toPrettyChars()); | |
388 | |
389 IrStruct* irinter = it->base->ir.irStruct; | |
390 assert(irinter && "interface has null IrStruct"); | |
391 IrTypeClass* itc = irinter->type->irtype->isClass(); | |
392 assert(itc && "null interface IrTypeClass"); | |
393 | |
394 // classinfo | |
395 LLConstant* ci = irinter->getClassInfoSymbol(); | |
396 ci = DtoBitCast(ci, classinfo_type); | |
397 | |
398 // vtbl | |
399 ClassGlobalMap::iterator itv = interfaceVtblMap.find(it->base); | |
400 assert(itv != interfaceVtblMap.end() && "interface vtbl not found"); | |
401 LLConstant* vtb = itv->second; | |
402 vtb = DtoBitCast(vtb, voidptrptr_type); | |
403 vtb = DtoConstSlice(DtoConstSize_t(itc->getVtblSize()), vtb); | |
404 | |
405 // offset | |
406 LLConstant* off = DtoConstSize_t(it->offset); | |
407 | |
408 // create Interface struct | |
409 LLConstant* inits[3] = { ci, vtb, off }; | |
410 LLConstant* entry = llvm::ConstantStruct::get(inits, 3); | |
411 constants.push_back(entry); | |
412 | |
413 // next | |
414 it.next(); | |
415 } | |
416 | |
417 // create Interface[N] | |
418 const llvm::ArrayType* array_type = llvm::ArrayType::get( | |
419 constants[0]->getType(), | |
420 cd->vtblInterfaces->dim); | |
421 | |
422 LLConstant* arr = llvm::ConstantArray::get( | |
423 array_type, | |
424 &constants[0], | |
425 constants.size()); | |
426 | |
427 // apply the initializer | |
428 classInterfacesArray->setInitializer(arr); | |
429 | |
430 LLConstant* idxs[2] = { | |
431 DtoConstSize_t(0), | |
432 DtoConstSize_t(0) | |
433 }; | |
434 | |
435 // return as a slice | |
436 return DtoConstSlice( | |
437 DtoConstSize_t(cd->vtblInterfaces->dim), | |
438 llvm::ConstantExpr::getGetElementPtr(classInterfacesArray, idxs, 2)); | |
439 } | |
440 | |
441 ////////////////////////////////////////////////////////////////////////////// |