100
|
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 }
|