Mercurial > projects > ldc
comparison gen/classes.cpp @ 100:5071469303d4 trunk
[svn r104] TONS OF FIXES.
Split up declaration, constant initializer gen and definition for globals, structs, classes and functions.
Improved ClassInfo support (not complete), not in vtable yet.
Fixed a bunch of forward reference problems.
Much more. Major commit! :)
author | lindquist |
---|---|
date | Fri, 16 Nov 2007 08:21:47 +0100 |
parents | |
children | 027b8d8b71ec |
comparison
equal
deleted
inserted
replaced
99:a676a7743642 | 100:5071469303d4 |
---|---|
1 #include "gen/llvm.h" | |
2 | |
3 #include "mtype.h" | |
4 #include "aggregate.h" | |
5 #include "init.h" | |
6 #include "declaration.h" | |
7 | |
8 #include "gen/irstate.h" | |
9 #include "gen/tollvm.h" | |
10 #include "gen/arrays.h" | |
11 #include "gen/logger.h" | |
12 #include "gen/classes.h" | |
13 | |
14 ////////////////////////////////////////////////////////////////////////////////////////// | |
15 | |
16 static void LLVM_AddBaseClassData(BaseClasses* bcs) | |
17 { | |
18 // add base class data members first | |
19 for (int j=0; j<bcs->dim; j++) | |
20 { | |
21 BaseClass* bc = (BaseClass*)(bcs->data[j]); | |
22 assert(bc); | |
23 Logger::println("Adding base class members of %s", bc->base->toChars()); | |
24 LOG_SCOPE; | |
25 | |
26 bc->base->toObjFile(); | |
27 | |
28 LLVM_AddBaseClassData(&bc->base->baseclasses); | |
29 for (int k=0; k < bc->base->members->dim; k++) { | |
30 Dsymbol* dsym = (Dsymbol*)(bc->base->members->data[k]); | |
31 if (dsym->isVarDeclaration()) | |
32 { | |
33 dsym->toObjFile(); | |
34 } | |
35 } | |
36 } | |
37 } | |
38 | |
39 ////////////////////////////////////////////////////////////////////////////////////////// | |
40 | |
41 void DtoDeclareClass(ClassDeclaration* cd) | |
42 { | |
43 if (cd->llvmTouched) return; | |
44 cd->llvmTouched = true; | |
45 | |
46 Logger::println("DtoDeclareClass(%s)\n", cd->toPrettyChars()); | |
47 LOG_SCOPE; | |
48 | |
49 assert(cd->type->ty == Tclass); | |
50 TypeClass* ts = (TypeClass*)cd->type; | |
51 | |
52 assert(!cd->llvmIRStruct); | |
53 IRStruct* irstruct = new IRStruct(ts); | |
54 cd->llvmIRStruct = irstruct; | |
55 | |
56 gIR->structs.push_back(irstruct); | |
57 gIR->classes.push_back(cd); | |
58 | |
59 // add vtable | |
60 llvm::PATypeHolder pa = llvm::OpaqueType::get(); | |
61 const llvm::Type* vtabty = llvm::PointerType::get(pa); | |
62 | |
63 std::vector<const llvm::Type*> fieldtypes; | |
64 fieldtypes.push_back(vtabty); | |
65 | |
66 // base classes first | |
67 LLVM_AddBaseClassData(&cd->baseclasses); | |
68 | |
69 // then add own members | |
70 for (int k=0; k < cd->members->dim; k++) { | |
71 Dsymbol* dsym = (Dsymbol*)(cd->members->data[k]); | |
72 dsym->toObjFile(); | |
73 } | |
74 | |
75 // add field types | |
76 for (IRStruct::OffsetMap::iterator i=irstruct->offsets.begin(); i!=irstruct->offsets.end(); ++i) { | |
77 fieldtypes.push_back(i->second.type); | |
78 } | |
79 | |
80 const llvm::StructType* structtype = llvm::StructType::get(fieldtypes); | |
81 // refine abstract types for stuff like: class C {C next;} | |
82 assert(irstruct->recty != 0); | |
83 { | |
84 llvm::PATypeHolder& spa = irstruct->recty; | |
85 llvm::cast<llvm::OpaqueType>(spa.get())->refineAbstractTypeTo(structtype); | |
86 structtype = isaStruct(spa.get()); | |
87 } | |
88 | |
89 // create the type | |
90 ts->llvmType = new llvm::PATypeHolder(structtype); | |
91 | |
92 bool needs_definition = false; | |
93 if (cd->parent->isModule()) { | |
94 gIR->module->addTypeName(cd->mangle(), ts->llvmType->get()); | |
95 needs_definition = (cd->getModule() == gIR->dmodule); | |
96 } | |
97 else { | |
98 assert(0 && "class parent is not a module"); | |
99 } | |
100 | |
101 // generate vtable | |
102 llvm::GlobalVariable* svtblVar = 0; | |
103 std::vector<llvm::Constant*> sinits; | |
104 std::vector<const llvm::Type*> sinits_ty; | |
105 sinits.reserve(cd->vtbl.dim); | |
106 sinits_ty.reserve(cd->vtbl.dim); | |
107 | |
108 for (int k=0; k < cd->vtbl.dim; k++) | |
109 { | |
110 Dsymbol* dsym = (Dsymbol*)cd->vtbl.data[k]; | |
111 assert(dsym); | |
112 //Logger::cout() << "vtblsym: " << dsym->toChars() << '\n'; | |
113 | |
114 if (FuncDeclaration* fd = dsym->isFuncDeclaration()) { | |
115 fd->toObjFile(); | |
116 assert(fd->llvmValue); | |
117 llvm::Constant* c = llvm::cast<llvm::Constant>(fd->llvmValue); | |
118 sinits.push_back(c); | |
119 sinits_ty.push_back(c->getType()); | |
120 } | |
121 else if (ClassDeclaration* cd = dsym->isClassDeclaration()) { | |
122 const llvm::Type* cty = llvm::PointerType::get(llvm::Type::Int8Ty); | |
123 llvm::Constant* c = llvm::Constant::getNullValue(cty); | |
124 sinits.push_back(c); | |
125 sinits_ty.push_back(cty); | |
126 } | |
127 else | |
128 assert(0); | |
129 } | |
130 | |
131 const llvm::StructType* svtbl_ty = 0; | |
132 if (!sinits.empty()) | |
133 { | |
134 llvm::GlobalValue::LinkageTypes _linkage = llvm::GlobalValue::ExternalLinkage; | |
135 | |
136 std::string varname("_D"); | |
137 varname.append(cd->mangle()); | |
138 varname.append("6__vtblZ"); | |
139 | |
140 std::string styname(cd->mangle()); | |
141 styname.append("__vtblTy"); | |
142 | |
143 svtbl_ty = llvm::StructType::get(sinits_ty); | |
144 gIR->module->addTypeName(styname, svtbl_ty); | |
145 svtblVar = new llvm::GlobalVariable(svtbl_ty, true, _linkage, 0, varname, gIR->module); | |
146 | |
147 cd->llvmConstVtbl = llvm::cast<llvm::ConstantStruct>(llvm::ConstantStruct::get(svtbl_ty, sinits)); | |
148 if (needs_definition) | |
149 svtblVar->setInitializer(cd->llvmConstVtbl); | |
150 cd->llvmVtbl = svtblVar; | |
151 } | |
152 | |
153 // refine for final vtable type | |
154 llvm::cast<llvm::OpaqueType>(pa.get())->refineAbstractTypeTo(svtbl_ty); | |
155 | |
156 std::string initname("_D"); | |
157 initname.append(cd->mangle()); | |
158 initname.append("6__initZ"); | |
159 llvm::GlobalValue::LinkageTypes _linkage = llvm::GlobalValue::ExternalLinkage; | |
160 llvm::GlobalVariable* initvar = new llvm::GlobalVariable(ts->llvmType->get(), true, _linkage, NULL, initname, gIR->module); | |
161 ts->llvmInit = initvar; | |
162 | |
163 gIR->classes.pop_back(); | |
164 gIR->structs.pop_back(); | |
165 | |
166 gIR->constInitQueue.push_back(cd); | |
167 if (needs_definition) | |
168 gIR->defineQueue.push_back(cd); | |
169 } | |
170 | |
171 ////////////////////////////////////////////////////////////////////////////////////////// | |
172 | |
173 void DtoConstInitClass(ClassDeclaration* cd) | |
174 { | |
175 IRStruct* irstruct = cd->llvmIRStruct; | |
176 if (irstruct->constinited) return; | |
177 irstruct->constinited = true; | |
178 | |
179 Logger::println("DtoConstInitClass(%s)\n", cd->toPrettyChars()); | |
180 LOG_SCOPE; | |
181 | |
182 gIR->structs.push_back(irstruct); | |
183 gIR->classes.push_back(cd); | |
184 | |
185 // make sure each offset knows its default initializer | |
186 for (IRStruct::OffsetMap::iterator i=irstruct->offsets.begin(); i!=irstruct->offsets.end(); ++i) | |
187 { | |
188 IRStruct::Offset* so = &i->second; | |
189 llvm::Constant* finit = DtoConstFieldInitializer(so->var->type, so->var->init); | |
190 so->init = finit; | |
191 so->var->llvmConstInit = finit; | |
192 } | |
193 | |
194 // fill out fieldtypes/inits | |
195 std::vector<llvm::Constant*> fieldinits; | |
196 | |
197 // first field is always the vtable | |
198 assert(cd->llvmVtbl != 0); | |
199 fieldinits.push_back(cd->llvmVtbl); | |
200 | |
201 // rest | |
202 for (IRStruct::OffsetMap::iterator i=irstruct->offsets.begin(); i!=irstruct->offsets.end(); ++i) { | |
203 fieldinits.push_back(i->second.init); | |
204 } | |
205 | |
206 // get the struct (class) type | |
207 assert(cd->type->ty == Tclass); | |
208 TypeClass* ts = (TypeClass*)cd->type; | |
209 const llvm::StructType* structtype = isaStruct(ts->llvmType->get()); | |
210 | |
211 // generate initializer | |
212 Logger::cout() << cd->toPrettyChars() << " | " << *structtype << '\n'; | |
213 Logger::println("%u %u fields", structtype->getNumElements(), fieldinits.size()); | |
214 llvm::Constant* _init = llvm::ConstantStruct::get(structtype, fieldinits); | |
215 assert(_init); | |
216 cd->llvmInitZ = _init; | |
217 | |
218 gIR->classes.pop_back(); | |
219 gIR->structs.pop_back(); | |
220 } | |
221 | |
222 ////////////////////////////////////////////////////////////////////////////////////////// | |
223 | |
224 void DtoDefineClass(ClassDeclaration* cd) | |
225 { | |
226 IRStruct* irstruct = cd->llvmIRStruct; | |
227 if (irstruct->defined) return; | |
228 irstruct->defined = true; | |
229 | |
230 Logger::println("DtoDefineClass(%s)\n", cd->toPrettyChars()); | |
231 LOG_SCOPE; | |
232 | |
233 // get the struct (class) type | |
234 assert(cd->type->ty == Tclass); | |
235 TypeClass* ts = (TypeClass*)cd->type; | |
236 | |
237 bool def = false; | |
238 if (cd->parent->isModule() && cd->getModule() == gIR->dmodule) { | |
239 ts->llvmInit->setInitializer(cd->llvmInitZ); | |
240 def = true; | |
241 } | |
242 | |
243 // generate classinfo | |
244 DtoDeclareClassInfo(cd); | |
245 if (def) DtoDefineClassInfo(cd); | |
246 } | |
247 | |
248 ////////////////////////////////////////////////////////////////////////////////////////// | |
249 | |
250 void DtoCallClassDtors(TypeClass* tc, llvm::Value* instance) | |
251 { | |
252 Array* arr = &tc->sym->dtors; | |
253 for (size_t i=0; i<arr->dim; i++) | |
254 { | |
255 FuncDeclaration* fd = (FuncDeclaration*)arr->data[i]; | |
256 assert(fd->llvmValue); | |
257 new llvm::CallInst(fd->llvmValue, instance, "", gIR->scopebb()); | |
258 } | |
259 } | |
260 | |
261 ////////////////////////////////////////////////////////////////////////////////////////// | |
262 | |
263 void DtoInitClass(TypeClass* tc, llvm::Value* dst) | |
264 { | |
265 assert(gIR); | |
266 | |
267 assert(tc->llvmType); | |
268 uint64_t size_t_size = gTargetData->getTypeSize(DtoSize_t()); | |
269 uint64_t n = gTargetData->getTypeSize(tc->llvmType->get()) - size_t_size; | |
270 | |
271 // set vtable field | |
272 llvm::Value* vtblvar = DtoGEPi(dst,0,0,"tmp",gIR->scopebb()); | |
273 assert(tc->sym->llvmVtbl); | |
274 new llvm::StoreInst(tc->sym->llvmVtbl, vtblvar, gIR->scopebb()); | |
275 | |
276 // copy the static initializer | |
277 if (n > 0) { | |
278 assert(tc->llvmInit); | |
279 assert(dst->getType() == tc->llvmInit->getType()); | |
280 | |
281 llvm::Type* arrty = llvm::PointerType::get(llvm::Type::Int8Ty); | |
282 | |
283 llvm::Value* dstarr = new llvm::BitCastInst(dst,arrty,"tmp",gIR->scopebb()); | |
284 dstarr = DtoGEPi(dstarr,size_t_size,"tmp",gIR->scopebb()); | |
285 | |
286 llvm::Value* srcarr = new llvm::BitCastInst(tc->llvmInit,arrty,"tmp",gIR->scopebb()); | |
287 srcarr = DtoGEPi(srcarr,size_t_size,"tmp",gIR->scopebb()); | |
288 | |
289 llvm::Function* fn = LLVM_DeclareMemCpy32(); | |
290 std::vector<llvm::Value*> llargs; | |
291 llargs.resize(4); | |
292 llargs[0] = dstarr; | |
293 llargs[1] = srcarr; | |
294 llargs[2] = llvm::ConstantInt::get(llvm::Type::Int32Ty, n, false); | |
295 llargs[3] = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false); | |
296 | |
297 new llvm::CallInst(fn, llargs.begin(), llargs.end(), "", gIR->scopebb()); | |
298 } | |
299 } | |
300 | |
301 ////////////////////////////////////////////////////////////////////////////////////////// | |
302 | |
303 void DtoDeclareClassInfo(ClassDeclaration* cd) | |
304 { | |
305 if (cd->llvmClass) | |
306 return; | |
307 | |
308 Logger::println("CLASS INFO DECLARATION: %s", cd->toChars()); | |
309 LOG_SCOPE; | |
310 | |
311 ClassDeclaration* cinfo = ClassDeclaration::classinfo; | |
312 cinfo->toObjFile(); | |
313 | |
314 const llvm::Type* st = cinfo->type->llvmType->get(); | |
315 | |
316 std::string gname("_D"); | |
317 gname.append(cd->mangle()); | |
318 gname.append("7__ClassZ"); | |
319 | |
320 cd->llvmClass = new llvm::GlobalVariable(st, true, llvm::GlobalValue::ExternalLinkage, NULL, gname, gIR->module); | |
321 } | |
322 | |
323 void DtoDefineClassInfo(ClassDeclaration* cd) | |
324 { | |
325 // The layout is: | |
326 // { | |
327 // void **vptr; | |
328 // monitor_t monitor; | |
329 // byte[] initializer; // static initialization data | |
330 // char[] name; // class name | |
331 // void *[] vtbl; | |
332 // Interface[] interfaces; | |
333 // ClassInfo *base; // base class | |
334 // void *destructor; | |
335 // void *invariant; // class invariant | |
336 // uint flags; | |
337 // void *deallocator; | |
338 // OffsetTypeInfo[] offTi; | |
339 // void *defaultConstructor; | |
340 // } | |
341 | |
342 if (cd->llvmClassZ) | |
343 return; | |
344 | |
345 Logger::println("CLASS INFO DEFINITION: %s", cd->toChars()); | |
346 LOG_SCOPE; | |
347 assert(cd->llvmClass); | |
348 | |
349 // holds the list of initializers for llvm | |
350 std::vector<llvm::Constant*> inits; | |
351 | |
352 ClassDeclaration* cinfo = ClassDeclaration::classinfo; | |
353 DtoConstInitClass(cinfo); | |
354 assert(cinfo->llvmInitZ); | |
355 | |
356 llvm::Constant* c; | |
357 | |
358 // own vtable | |
359 c = cinfo->llvmInitZ->getOperand(0); | |
360 assert(c); | |
361 inits.push_back(c); | |
362 | |
363 // monitor | |
364 // TODO no monitors yet | |
365 | |
366 // initializer | |
367 c = cinfo->llvmInitZ->getOperand(1); | |
368 inits.push_back(c); | |
369 | |
370 // class name | |
371 // from dmd | |
372 char *name = cd->ident->toChars(); | |
373 size_t namelen = strlen(name); | |
374 if (!(namelen > 9 && memcmp(name, "TypeInfo_", 9) == 0)) | |
375 { | |
376 name = cd->toPrettyChars(); | |
377 namelen = strlen(name); | |
378 } | |
379 c = DtoConstString(name); | |
380 inits.push_back(c); | |
381 | |
382 // vtbl array | |
383 c = cinfo->llvmInitZ->getOperand(3); | |
384 inits.push_back(c); | |
385 | |
386 // interfaces array | |
387 c = cinfo->llvmInitZ->getOperand(4); | |
388 inits.push_back(c); | |
389 | |
390 // base classinfo | |
391 c = cinfo->llvmInitZ->getOperand(5); | |
392 inits.push_back(c); | |
393 | |
394 // destructor | |
395 c = cinfo->llvmInitZ->getOperand(6); | |
396 inits.push_back(c); | |
397 | |
398 // invariant | |
399 c = cinfo->llvmInitZ->getOperand(7); | |
400 inits.push_back(c); | |
401 | |
402 // flags | |
403 c = cinfo->llvmInitZ->getOperand(8); | |
404 inits.push_back(c); | |
405 | |
406 // allocator | |
407 c = cinfo->llvmInitZ->getOperand(9); | |
408 inits.push_back(c); | |
409 | |
410 // offset typeinfo | |
411 c = cinfo->llvmInitZ->getOperand(10); | |
412 inits.push_back(c); | |
413 | |
414 // default constructor | |
415 c = cinfo->llvmInitZ->getOperand(11); | |
416 inits.push_back(c); | |
417 | |
418 /*size_t n = inits.size(); | |
419 for (size_t i=0; i<n; ++i) | |
420 { | |
421 Logger::cout() << "inits[" << i << "]: " << *inits[i] << '\n'; | |
422 }*/ | |
423 | |
424 // build the initializer | |
425 const llvm::StructType* st = isaStruct(cinfo->llvmInitZ->getType()); | |
426 llvm::Constant* finalinit = llvm::ConstantStruct::get(st, inits); | |
427 //Logger::cout() << "built the classinfo initializer:\n" << *finalinit <<'\n'; | |
428 | |
429 cd->llvmClassZ = finalinit; | |
430 cd->llvmClass->setInitializer(finalinit); | |
431 } |