Mercurial > projects > ldc
comparison gen/classes.cpp @ 132:1700239cab2e trunk
[svn r136] MAJOR UNSTABLE UPDATE!!!
Initial commit after moving to Tango instead of Phobos.
Lots of bugfixes...
This build is not suitable for most things.
author | lindquist |
---|---|
date | Fri, 11 Jan 2008 17:57:40 +0100 |
parents | 7f9a0a58394b |
children | 44a95ac7368a |
comparison
equal
deleted
inserted
replaced
131:5825d48b27d1 | 132:1700239cab2e |
---|---|
9 #include "gen/irstate.h" | 9 #include "gen/irstate.h" |
10 #include "gen/tollvm.h" | 10 #include "gen/tollvm.h" |
11 #include "gen/arrays.h" | 11 #include "gen/arrays.h" |
12 #include "gen/logger.h" | 12 #include "gen/logger.h" |
13 #include "gen/classes.h" | 13 #include "gen/classes.h" |
14 #include "gen/structs.h" | |
14 #include "gen/functions.h" | 15 #include "gen/functions.h" |
15 #include "gen/runtime.h" | 16 #include "gen/runtime.h" |
16 #include "gen/dvalue.h" | 17 #include "gen/dvalue.h" |
17 | 18 |
18 ////////////////////////////////////////////////////////////////////////////////////////// | 19 ////////////////////////////////////////////////////////////////////////////////////////// |
30 LLVM_AddBaseClassData(&bc->base->baseclasses); | 31 LLVM_AddBaseClassData(&bc->base->baseclasses); |
31 | 32 |
32 Logger::println("Adding base class members of %s", bc->base->toChars()); | 33 Logger::println("Adding base class members of %s", bc->base->toChars()); |
33 LOG_SCOPE; | 34 LOG_SCOPE; |
34 | 35 |
35 for (int k=0; k < bc->base->members->dim; k++) { | 36 Array* arr = &bc->base->fields; |
37 for (int k=0; k < arr->dim; k++) { | |
38 VarDeclaration* v = (VarDeclaration*)(arr->data[k]); | |
39 v->toObjFile(); | |
40 } | |
41 | |
42 /*for (int k=0; k < bc->base->members->dim; k++) { | |
36 Dsymbol* dsym = (Dsymbol*)(bc->base->members->data[k]); | 43 Dsymbol* dsym = (Dsymbol*)(bc->base->members->data[k]); |
37 if (dsym->isVarDeclaration()) | 44 if (dsym->isVarDeclaration()) |
38 { | 45 { |
39 dsym->toObjFile(); | 46 dsym->toObjFile(); |
40 } | 47 } |
41 } | 48 }*/ |
42 } | 49 } |
43 } | 50 } |
44 | 51 |
45 ////////////////////////////////////////////////////////////////////////////////////////// | 52 ////////////////////////////////////////////////////////////////////////////////////////// |
46 | 53 |
63 // Fill in vtbl[] | 70 // Fill in vtbl[] |
64 b->fillVtbl(cd, &b->vtbl, 1); | 71 b->fillVtbl(cd, &b->vtbl, 1); |
65 } | 72 } |
66 } | 73 } |
67 | 74 |
68 Logger::println("DtoResolveClass(%s)", cd->toPrettyChars()); | 75 Logger::println("DtoResolveClass(%s): %s", cd->toPrettyChars(), cd->loc.toChars()); |
69 LOG_SCOPE; | 76 LOG_SCOPE; |
70 | 77 |
71 assert(cd->type->ty == Tclass); | 78 assert(cd->type->ty == Tclass); |
72 TypeClass* ts = (TypeClass*)cd->type; | 79 TypeClass* ts = (TypeClass*)cd->type; |
73 | 80 |
111 for (int k=0; k < cd->members->dim; k++) { | 118 for (int k=0; k < cd->members->dim; k++) { |
112 Dsymbol* dsym = (Dsymbol*)(cd->members->data[k]); | 119 Dsymbol* dsym = (Dsymbol*)(cd->members->data[k]); |
113 dsym->toObjFile(); | 120 dsym->toObjFile(); |
114 } | 121 } |
115 | 122 |
123 // resolve class data fields (possibly unions) | |
124 Logger::println("doing class fields"); | |
125 | |
126 if (irstruct->offsets.empty()) | |
127 { | |
128 Logger::println("has no fields"); | |
129 } | |
130 else | |
131 { | |
132 Logger::println("has fields"); | |
133 unsigned prevsize = (unsigned)-1; | |
134 unsigned lastoffset = (unsigned)-1; | |
135 const llvm::Type* fieldtype = NULL; | |
136 VarDeclaration* fieldinit = NULL; | |
137 size_t fieldpad = 0; | |
138 int idx = 0; | |
139 for (IRStruct::OffsetMap::iterator i=irstruct->offsets.begin(); i!=irstruct->offsets.end(); ++i) { | |
140 // first iteration | |
141 if (lastoffset == (unsigned)-1) { | |
142 lastoffset = i->first; | |
143 fieldtype = i->second.type; | |
144 fieldinit = i->second.var; | |
145 prevsize = gTargetData->getTypeSize(fieldtype); | |
146 i->second.var->llvmFieldIndex = idx; | |
147 } | |
148 // colliding offset? | |
149 else if (lastoffset == i->first) { | |
150 size_t s = gTargetData->getTypeSize(i->second.type); | |
151 if (s > prevsize) { | |
152 fieldpad += s - prevsize; | |
153 prevsize = s; | |
154 } | |
155 cd->llvmHasUnions = true; | |
156 i->second.var->llvmFieldIndex = idx; | |
157 } | |
158 // intersecting offset? | |
159 else if (i->first < (lastoffset + prevsize)) { | |
160 size_t s = gTargetData->getTypeSize(i->second.type); | |
161 assert((i->first + s) <= (lastoffset + prevsize)); // this holds because all types are aligned to their size | |
162 cd->llvmHasUnions = true; | |
163 i->second.var->llvmFieldIndex = idx; | |
164 i->second.var->llvmFieldIndexOffset = (i->first - lastoffset) / s; | |
165 } | |
166 // fresh offset | |
167 else { | |
168 // commit the field | |
169 fieldtypes.push_back(fieldtype); | |
170 irstruct->defaultFields.push_back(fieldinit); | |
171 if (fieldpad) { | |
172 fieldtypes.push_back(llvm::ArrayType::get(llvm::Type::Int8Ty, fieldpad)); | |
173 irstruct->defaultFields.push_back(NULL); | |
174 idx++; | |
175 } | |
176 | |
177 idx++; | |
178 | |
179 // start new | |
180 lastoffset = i->first; | |
181 fieldtype = i->second.type; | |
182 fieldinit = i->second.var; | |
183 prevsize = gTargetData->getTypeSize(fieldtype); | |
184 i->second.var->llvmFieldIndex = idx; | |
185 fieldpad = 0; | |
186 } | |
187 } | |
188 fieldtypes.push_back(fieldtype); | |
189 irstruct->defaultFields.push_back(fieldinit); | |
190 if (fieldpad) { | |
191 fieldtypes.push_back(llvm::ArrayType::get(llvm::Type::Int8Ty, fieldpad)); | |
192 irstruct->defaultFields.push_back(NULL); | |
193 } | |
194 } | |
195 | |
196 /* | |
116 // add field types | 197 // add field types |
117 for (IRStruct::OffsetMap::iterator i=irstruct->offsets.begin(); i!=irstruct->offsets.end(); ++i) { | 198 for (IRStruct::OffsetMap::iterator i=irstruct->offsets.begin(); i!=irstruct->offsets.end(); ++i) { |
118 fieldtypes.push_back(i->second.type); | 199 fieldtypes.push_back(i->second.type); |
119 } | 200 } |
201 */ | |
120 | 202 |
121 const llvm::StructType* structtype = llvm::StructType::get(fieldtypes); | 203 const llvm::StructType* structtype = llvm::StructType::get(fieldtypes); |
122 // refine abstract types for stuff like: class C {C next;} | 204 // refine abstract types for stuff like: class C {C next;} |
123 assert(irstruct->recty != 0); | 205 assert(irstruct->recty != 0); |
124 | 206 |
212 void DtoDeclareClass(ClassDeclaration* cd) | 294 void DtoDeclareClass(ClassDeclaration* cd) |
213 { | 295 { |
214 if (cd->llvmDeclared) return; | 296 if (cd->llvmDeclared) return; |
215 cd->llvmDeclared = true; | 297 cd->llvmDeclared = true; |
216 | 298 |
217 Logger::println("DtoDeclareClass(%s)", cd->toPrettyChars()); | 299 Logger::println("DtoDeclareClass(%s): %s", cd->toPrettyChars(), cd->loc.toChars()); |
218 LOG_SCOPE; | 300 LOG_SCOPE; |
219 | 301 |
220 assert(cd->type->ty == Tclass); | 302 assert(cd->type->ty == Tclass); |
221 TypeClass* ts = (TypeClass*)cd->type; | 303 TypeClass* ts = (TypeClass*)cd->type; |
222 | 304 |
260 types.push_back(llvm::Type::Int32Ty); | 342 types.push_back(llvm::Type::Int32Ty); |
261 // create type | 343 // create type |
262 const llvm::StructType* infoTy = llvm::StructType::get(types); | 344 const llvm::StructType* infoTy = llvm::StructType::get(types); |
263 | 345 |
264 // interface info array | 346 // interface info array |
265 if (needs_definition && cd->vtblInterfaces->dim > 0) { | 347 if (cd->vtblInterfaces->dim > 0) { |
266 // symbol name | 348 // symbol name |
267 std::string nam = "_D"; | 349 std::string nam = "_D"; |
268 nam.append(cd->mangle()); | 350 nam.append(cd->mangle()); |
269 nam.append("16__interfaceInfosZ"); | 351 nam.append("16__interfaceInfosZ"); |
270 // resolve array type | 352 // resolve array type |
271 const llvm::ArrayType* arrTy = llvm::ArrayType::get(infoTy, cd->vtblInterfaces->dim); | 353 const llvm::ArrayType* arrTy = llvm::ArrayType::get(infoTy, cd->vtblInterfaces->dim); |
272 // declare global | 354 // declare global |
273 irstruct->interfaceInfosTy = arrTy; | 355 irstruct->interfaceInfosTy = arrTy; |
274 irstruct->interfaceInfos = new llvm::GlobalVariable(arrTy, true, llvm::GlobalValue::InternalLinkage, 0, nam, gIR->module); | 356 irstruct->interfaceInfos = new llvm::GlobalVariable(arrTy, true, _linkage, NULL, nam, gIR->module); |
275 } | 357 } |
276 | 358 |
277 // interface vtables | 359 // interface vtables |
278 unsigned idx = 0; | 360 unsigned idx = 0; |
279 for (IRStruct::InterfaceIter i=irstruct->interfaces.begin(); i!=irstruct->interfaces.end(); ++i) | 361 for (IRStruct::InterfaceIter i=irstruct->interfaces.begin(); i!=irstruct->interfaces.end(); ++i) |
327 cd->llvmInitialized = true; | 409 cd->llvmInitialized = true; |
328 | 410 |
329 if (cd->isInterfaceDeclaration()) | 411 if (cd->isInterfaceDeclaration()) |
330 return; // nothing to do | 412 return; // nothing to do |
331 | 413 |
332 Logger::println("DtoConstInitClass(%s)", cd->toPrettyChars()); | 414 Logger::println("DtoConstInitClass(%s): %s", cd->toPrettyChars(), cd->loc.toChars()); |
333 LOG_SCOPE; | 415 LOG_SCOPE; |
334 | 416 |
335 IRStruct* irstruct = cd->llvmIRStruct; | 417 IRStruct* irstruct = cd->llvmIRStruct; |
336 gIR->structs.push_back(irstruct); | 418 gIR->structs.push_back(irstruct); |
337 gIR->classes.push_back(cd); | 419 gIR->classes.push_back(cd); |
353 fieldinits.push_back(cd->llvmVtbl); | 435 fieldinits.push_back(cd->llvmVtbl); |
354 | 436 |
355 // then comes monitor | 437 // then comes monitor |
356 fieldinits.push_back(llvm::ConstantPointerNull::get(llvm::PointerType::get(llvm::Type::Int8Ty))); | 438 fieldinits.push_back(llvm::ConstantPointerNull::get(llvm::PointerType::get(llvm::Type::Int8Ty))); |
357 | 439 |
440 size_t dataoffset = 2; | |
441 | |
358 // next comes interface vtables | 442 // next comes interface vtables |
359 for (IRStruct::InterfaceIter i=irstruct->interfaces.begin(); i!=irstruct->interfaces.end(); ++i) | 443 for (IRStruct::InterfaceIter i=irstruct->interfaces.begin(); i!=irstruct->interfaces.end(); ++i) |
360 { | 444 { |
361 IRInterface* iri = i->second; | 445 IRInterface* iri = i->second; |
362 assert(iri->vtbl); | 446 assert(iri->vtbl); |
363 fieldinits.push_back(iri->vtbl); | 447 fieldinits.push_back(iri->vtbl); |
364 } | 448 ++dataoffset; |
365 | 449 } |
450 | |
451 /* | |
366 // rest | 452 // rest |
367 for (IRStruct::OffsetMap::iterator i=irstruct->offsets.begin(); i!=irstruct->offsets.end(); ++i) { | 453 for (IRStruct::OffsetMap::iterator i=irstruct->offsets.begin(); i!=irstruct->offsets.end(); ++i) { |
368 Logger::println("adding fieldinit for: %s", i->second.var->toChars()); | 454 Logger::println("adding fieldinit for: %s", i->second.var->toChars()); |
369 fieldinits.push_back(i->second.init); | 455 fieldinits.push_back(i->second.init); |
370 } | 456 } |
457 */ | |
371 | 458 |
372 // get the struct (class) type | 459 // get the struct (class) type |
373 assert(cd->type->ty == Tclass); | 460 assert(cd->type->ty == Tclass); |
374 TypeClass* ts = (TypeClass*)cd->type; | 461 TypeClass* ts = (TypeClass*)cd->type; |
375 const llvm::StructType* structtype = isaStruct(ts->llvmType->get()); | 462 const llvm::StructType* structtype = isaStruct(ts->llvmType->get()); |
376 const llvm::StructType* vtbltype = isaStruct(ts->llvmVtblType->get()); | 463 const llvm::StructType* vtbltype = isaStruct(ts->llvmVtblType->get()); |
464 | |
465 // go through the field inits and build the default initializer | |
466 size_t nfi = irstruct->defaultFields.size(); | |
467 for (size_t i=0; i<nfi; ++i) { | |
468 llvm::Constant* c; | |
469 if (irstruct->defaultFields[i] != NULL) { | |
470 c = irstruct->defaultFields[i]->llvmConstInit; | |
471 assert(c); | |
472 } | |
473 else { | |
474 const llvm::ArrayType* arrty = isaArray(structtype->getElementType(i+dataoffset)); | |
475 std::vector<llvm::Constant*> vals(arrty->getNumElements(), llvm::ConstantInt::get(llvm::Type::Int8Ty, 0, false)); | |
476 c = llvm::ConstantArray::get(arrty, vals); | |
477 } | |
478 fieldinits.push_back(c); | |
479 } | |
377 | 480 |
378 // generate initializer | 481 // generate initializer |
379 #if 0 | 482 #if 0 |
380 Logger::cout() << cd->toPrettyChars() << " | " << *structtype << '\n'; | 483 Logger::cout() << cd->toPrettyChars() << " | " << *structtype << '\n'; |
381 | 484 |
507 void DtoDefineClass(ClassDeclaration* cd) | 610 void DtoDefineClass(ClassDeclaration* cd) |
508 { | 611 { |
509 if (cd->llvmDefined) return; | 612 if (cd->llvmDefined) return; |
510 cd->llvmDefined = true; | 613 cd->llvmDefined = true; |
511 | 614 |
512 Logger::println("DtoDefineClass(%s)", cd->toPrettyChars()); | 615 Logger::println("DtoDefineClass(%s): %s", cd->toPrettyChars(), cd->loc.toChars()); |
513 LOG_SCOPE; | 616 LOG_SCOPE; |
514 | 617 |
515 // get the struct (class) type | 618 // get the struct (class) type |
516 assert(cd->type->ty == Tclass); | 619 assert(cd->type->ty == Tclass); |
517 TypeClass* ts = (TypeClass*)cd->type; | 620 TypeClass* ts = (TypeClass*)cd->type; |
696 ret = DtoBitCast(ret, DtoType(to)); | 799 ret = DtoBitCast(ret, DtoType(to)); |
697 else | 800 else |
698 to = ClassDeclaration::object->type; | 801 to = ClassDeclaration::object->type; |
699 | 802 |
700 return new DImValue(to, ret); | 803 return new DImValue(to, ret); |
804 } | |
805 | |
806 ////////////////////////////////////////////////////////////////////////////////////////// | |
807 | |
808 static unsigned LLVM_ClassOffsetToIndex(ClassDeclaration* cd, unsigned os, unsigned& idx) | |
809 { | |
810 // start at the bottom of the inheritance chain | |
811 if (cd->baseClass != 0) { | |
812 unsigned o = LLVM_ClassOffsetToIndex(cd->baseClass, os, idx); | |
813 if (o != (unsigned)-1) | |
814 return o; | |
815 } | |
816 | |
817 // check this class | |
818 unsigned i; | |
819 for (i=0; i<cd->fields.dim; ++i) { | |
820 VarDeclaration* vd = (VarDeclaration*)cd->fields.data[i]; | |
821 if (os == vd->offset) | |
822 return i+idx; | |
823 } | |
824 idx += i; | |
825 | |
826 return (unsigned)-1; | |
827 } | |
828 | |
829 ////////////////////////////////////////////////////////////////////////////////////////// | |
830 | |
831 void ClassDeclaration::offsetToIndex(Type* t, unsigned os, std::vector<unsigned>& result) | |
832 { | |
833 unsigned idx = 0; | |
834 unsigned r = LLVM_ClassOffsetToIndex(this, os, idx); | |
835 assert(r != (unsigned)-1 && "Offset not found in any aggregate field"); | |
836 // vtable is 0, monitor is 1 | |
837 r += 2; | |
838 // interface offset further | |
839 r += vtblInterfaces->dim; | |
840 // the final index was not pushed | |
841 result.push_back(r); | |
842 } | |
843 | |
844 ////////////////////////////////////////////////////////////////////////////////////////// | |
845 | |
846 llvm::Value* DtoIndexClass(llvm::Value* ptr, ClassDeclaration* cd, Type* t, unsigned os, std::vector<unsigned>& idxs) | |
847 { | |
848 Logger::println("checking for offset %u type %s:", os, t->toChars()); | |
849 LOG_SCOPE; | |
850 | |
851 if (idxs.empty()) | |
852 idxs.push_back(0); | |
853 | |
854 const llvm::Type* llt = llvm::PointerType::get(DtoType(t)); | |
855 const llvm::Type* st = DtoType(cd->type); | |
856 if (ptr->getType() != st) { | |
857 assert(cd->llvmHasUnions); | |
858 ptr = gIR->ir->CreateBitCast(ptr, st, "tmp"); | |
859 } | |
860 | |
861 unsigned dataoffset = 2 + cd->vtblInterfaces->dim; | |
862 | |
863 IRStruct* irstruct = cd->llvmIRStruct; | |
864 for (IRStruct::OffsetMap::iterator i=irstruct->offsets.begin(); i!=irstruct->offsets.end(); ++i) { | |
865 //for (unsigned i=0; i<cd->fields.dim; ++i) { | |
866 //VarDeclaration* vd = (VarDeclaration*)cd->fields.data[i]; | |
867 VarDeclaration* vd = i->second.var; | |
868 assert(vd); | |
869 Type* vdtype = DtoDType(vd->type); | |
870 Logger::println("found %u type %s", vd->offset, vdtype->toChars()); | |
871 assert(vd->llvmFieldIndex >= 0); | |
872 if (os == vd->offset && vdtype == t) { | |
873 idxs.push_back(vd->llvmFieldIndex + dataoffset); | |
874 Logger::cout() << "indexing: " << *ptr << '\n'; | |
875 ptr = DtoGEP(ptr, idxs, "tmp"); | |
876 if (ptr->getType() != llt) | |
877 ptr = gIR->ir->CreateBitCast(ptr, llt, "tmp"); | |
878 Logger::cout() << "indexing: " << *ptr << '\n'; | |
879 if (vd->llvmFieldIndexOffset) | |
880 ptr = new llvm::GetElementPtrInst(ptr, DtoConstUint(vd->llvmFieldIndexOffset), "tmp", gIR->scopebb()); | |
881 Logger::cout() << "indexing: " << *ptr << '\n'; | |
882 return ptr; | |
883 } | |
884 else if (vdtype->ty == Tstruct && (vd->offset + vdtype->size()) > os) { | |
885 TypeStruct* ts = (TypeStruct*)vdtype; | |
886 StructDeclaration* ssd = ts->sym; | |
887 idxs.push_back(vd->llvmFieldIndex + dataoffset); | |
888 if (vd->llvmFieldIndexOffset) { | |
889 Logger::println("has union field offset"); | |
890 ptr = DtoGEP(ptr, idxs, "tmp"); | |
891 if (ptr->getType() != llt) | |
892 ptr = gIR->ir->CreateBitCast(ptr, llt, "tmp"); | |
893 ptr = new llvm::GetElementPtrInst(ptr, DtoConstUint(vd->llvmFieldIndexOffset), "tmp", gIR->scopebb()); | |
894 std::vector<unsigned> tmp; | |
895 return DtoIndexStruct(ptr, ssd, t, os-vd->offset, tmp); | |
896 } | |
897 else { | |
898 const llvm::Type* sty = llvm::PointerType::get(DtoType(vd->type)); | |
899 if (ptr->getType() != sty) { | |
900 ptr = gIR->ir->CreateBitCast(ptr, sty, "tmp"); | |
901 std::vector<unsigned> tmp; | |
902 return DtoIndexStruct(ptr, ssd, t, os-vd->offset, tmp); | |
903 } | |
904 else { | |
905 return DtoIndexStruct(ptr, ssd, t, os-vd->offset, idxs); | |
906 } | |
907 } | |
908 } | |
909 } | |
910 | |
911 assert(0); | |
912 | |
913 size_t llt_sz = gTargetData->getTypeSize(llt->getContainedType(0)); | |
914 assert(os % llt_sz == 0); | |
915 ptr = gIR->ir->CreateBitCast(ptr, llt, "tmp"); | |
916 return new llvm::GetElementPtrInst(ptr, DtoConstUint(os / llt_sz), "tmp", gIR->scopebb()); | |
701 } | 917 } |
702 | 918 |
703 ////////////////////////////////////////////////////////////////////////////////////////// | 919 ////////////////////////////////////////////////////////////////////////////////////////// |
704 | 920 |
705 void DtoDeclareClassInfo(ClassDeclaration* cd) | 921 void DtoDeclareClassInfo(ClassDeclaration* cd) |