Mercurial > projects > ldc
comparison gen/structs.cpp @ 797:340acf1535d0
Removed KDevelop3 project files, CMake can generate them just fine!
Fixed function literals in static initializers.
Changed alignment of delegates from 2*PTRSIZE to just PTRSIZE.
Changed errors to go to stderr instead of stdout.
Fairly major rewriting of struct/union/class handling, STILL A BIT BUGGY !!!
author | Tomas Lindquist Olsen <tomas.l.olsen@gmail.com> |
---|---|
date | Sat, 29 Nov 2008 21:25:43 +0100 |
parents | 6e7a4c3b64d2 |
children | d14e4594c7d7 |
comparison
equal
deleted
inserted
replaced
796:6e7a4c3b64d2 | 797:340acf1535d0 |
---|---|
16 #include "gen/dvalue.h" | 16 #include "gen/dvalue.h" |
17 | 17 |
18 #include "ir/irstruct.h" | 18 #include "ir/irstruct.h" |
19 | 19 |
20 ////////////////////////////////////////////////////////////////////////////////////////// | 20 ////////////////////////////////////////////////////////////////////////////////////////// |
21 void addZeros(std::vector<llvm::Constant*>& inits, unsigned pos, unsigned offset); // defined in irstruct.cpp | |
22 | |
23 // pair of var and its init | |
24 typedef std::pair<VarDeclaration*,Initializer*> VarInitPair; | |
25 | |
26 // comparison func for qsort | |
27 static int varinit_offset_cmp_func(const void* p1, const void* p2) | |
28 { | |
29 VarDeclaration* v1 = ((VarInitPair*)p1)->first; | |
30 VarDeclaration* v2 = ((VarInitPair*)p2)->first; | |
31 if (v1->offset < v2->offset) | |
32 return -1; | |
33 else if (v1->offset > v2->offset) | |
34 return 1; | |
35 else | |
36 return 0; | |
37 } | |
38 | |
39 /* | |
40 this uses a simple algorithm to build the correct constant | |
41 | |
42 (1) first sort the explicit initializers by offset... well, DMD doesn't :) | |
43 | |
44 (2) if there is NO space before the next explicit initializeer, goto (9) | |
45 (3) find the next default initializer that fits before it, if NOT found goto (7) | |
46 (4) insert zero padding up to the next default initializer | |
47 (5) insert the next default initializer | |
48 (6) goto (2) | |
49 | |
50 (7) insert zero padding up to the next explicit initializer | |
51 | |
52 (9) insert the next explicit initializer | |
53 (10) goto (2) | |
54 | |
55 (11) done | |
56 | |
57 (next can be the end too) | |
58 | |
59 */ | |
60 | |
61 // return the next default initializer to use or null | |
62 static VarDeclaration* nextDefault(IrStruct* irstruct, size_t& idx, size_t pos, size_t offset) | |
63 { | |
64 IrStruct::VarDeclVector& defaults = irstruct->defVars; | |
65 size_t ndefaults = defaults.size(); | |
66 | |
67 // for each valid index | |
68 while(idx < ndefaults) | |
69 { | |
70 VarDeclaration* v = defaults[idx]; | |
71 | |
72 // skip defaults before pos | |
73 if (v->offset < pos) | |
74 { | |
75 idx++; | |
76 continue; | |
77 } | |
78 | |
79 // this var default fits | |
80 if (v->offset >= pos && v->offset + v->type->size() <= offset) | |
81 return v; | |
82 | |
83 // not usable | |
84 break; | |
85 } | |
86 | |
87 // not usable | |
88 return NULL; | |
89 } | |
90 | |
21 LLConstant* DtoConstStructInitializer(StructInitializer* si) | 91 LLConstant* DtoConstStructInitializer(StructInitializer* si) |
22 { | 92 { |
23 Logger::println("DtoConstStructInitializer: %s", si->toChars()); | 93 Logger::println("DtoConstStructInitializer: %s", si->toChars()); |
24 LOG_SCOPE; | 94 LOG_SCOPE; |
25 | 95 |
96 // get TypeStruct | |
26 assert(si->ad); | 97 assert(si->ad); |
27 TypeStruct* ts = (TypeStruct*)si->ad->type; | 98 TypeStruct* ts = (TypeStruct*)si->ad->type; |
28 | 99 |
29 DtoResolveDsymbol(si->ad); | 100 // force constant initialization of the symbol |
30 | 101 DtoForceConstInitDsymbol(si->ad); |
102 | |
103 // get formal type | |
31 const llvm::StructType* structtype = isaStruct(ts->ir.type->get()); | 104 const llvm::StructType* structtype = isaStruct(ts->ir.type->get()); |
32 | 105 |
106 // log it | |
33 if (Logger::enabled()) | 107 if (Logger::enabled()) |
34 Logger::cout() << "llvm struct type: " << *structtype << '\n'; | 108 Logger::cout() << "llvm struct type: " << *structtype << '\n'; |
35 | 109 |
110 // sanity check | |
111 assert(si->value.dim > 0); | |
36 assert(si->value.dim == si->vars.dim); | 112 assert(si->value.dim == si->vars.dim); |
37 | 113 |
38 std::vector<DUnionIdx> inits; | 114 // vector of final initializer constants |
39 for (int i = 0; i < si->value.dim; ++i) | 115 std::vector<LLConstant*> inits; |
40 { | 116 |
117 // get the ir struct | |
118 IrStruct* irstruct = si->ad->ir.irStruct; | |
119 | |
120 // get default fields | |
121 IrStruct::VarDeclVector& defaults = irstruct->defVars; | |
122 size_t ndefaults = defaults.size(); | |
123 | |
124 // make sure si->vars is sorted by offset | |
125 std::vector<VarInitPair> vars; | |
126 size_t nvars = si->vars.dim; | |
127 vars.resize(nvars); | |
128 | |
129 // fill pair vector | |
130 for (size_t i = 0; i < nvars; i++) | |
131 { | |
132 VarDeclaration* var = (VarDeclaration*)si->vars.data[i]; | |
41 Initializer* ini = (Initializer*)si->value.data[i]; | 133 Initializer* ini = (Initializer*)si->value.data[i]; |
134 assert(var); | |
42 assert(ini); | 135 assert(ini); |
43 VarDeclaration* vd = (VarDeclaration*)si->vars.data[i]; | 136 vars[i] = std::make_pair(var, ini); |
44 assert(vd); | 137 } |
45 LLConstant* v = DtoConstInitializer(vd->loc, vd->type, ini); | 138 // sort it |
46 inits.push_back(DUnionIdx(vd->ir.irField->index, vd->ir.irField->indexOffset, v)); | 139 qsort(&vars[0], nvars, sizeof(VarInitPair), &varinit_offset_cmp_func); |
47 } | 140 |
48 | 141 // check integrity |
49 DtoConstInitStruct((StructDeclaration*)si->ad); | 142 // and do error checking, since the frontend does verify static struct initializers |
50 return si->ad->ir.irStruct->dunion->getConst(inits); | 143 size_t lastoffset = 0; |
144 size_t lastsize = 0; | |
145 bool overlap = false; | |
146 for (size_t i=0; i < nvars; i++) | |
147 { | |
148 // next explicit init var | |
149 VarDeclaration* var = vars[i].first; | |
150 Logger::println("var = %s : +%u", var->toChars(), var->offset); | |
151 | |
152 // I would have thought this to be a frontend check | |
153 for (size_t j=i+1; j<nvars; j++) | |
154 { | |
155 if (j == i) | |
156 continue; | |
157 VarDeclaration* var2 = vars[j].first; | |
158 if (var2->offset >= var->offset && var2->offset < var->offset + var->type->size()) | |
159 { | |
160 fprintf(stdmsg, "Error: %s: initializer '%s' overlaps with '%s'\n", si->loc.toChars(), var->toChars(), var2->toChars()); | |
161 overlap = true; | |
162 } | |
163 } | |
164 | |
165 // update offsets | |
166 lastoffset = var->offset; | |
167 lastsize = var->type->size(); | |
168 } | |
169 | |
170 // error handling, report all overlaps before aborting | |
171 if (overlap) | |
172 { | |
173 error("%s: overlapping union initializers", si->loc.toChars()); | |
174 } | |
175 | |
176 // go through each explicit initalizer, falling back to defaults or zeros when necessary | |
177 lastoffset = 0; | |
178 lastsize = 0; | |
179 | |
180 size_t j=0; // defaults | |
181 | |
182 for (size_t i=0; i < nvars; i++) | |
183 { | |
184 // get var and init | |
185 VarDeclaration* var = vars[i].first; | |
186 Initializer* ini = vars[i].second; | |
187 | |
188 size_t offset = var->offset; | |
189 size_t size = var->type->size(); | |
190 | |
191 // if there is space before the next explicit initializer | |
192 Lpadding: | |
193 size_t pos = lastoffset+lastsize; | |
194 if (offset > pos) | |
195 { | |
196 // find the the next default initializer that fits in this space | |
197 VarDeclaration* nextdef = nextDefault(irstruct, j, lastoffset+lastsize, offset); | |
198 | |
199 // found | |
200 if (nextdef) | |
201 { | |
202 // need zeros before the default | |
203 if (nextdef->offset > pos) | |
204 { | |
205 Logger::println("inserting %lu byte padding at %lu", nextdef->offset - pos, pos); | |
206 addZeros(inits, pos, nextdef->offset); | |
207 } | |
208 | |
209 // do the default | |
210 Logger::println("adding default field: %s : +%u", nextdef->toChars(), nextdef->offset); | |
211 LLConstant* c = nextdef->ir.irField->constInit; | |
212 inits.push_back(c); | |
213 | |
214 // update offsets | |
215 lastoffset = nextdef->offset; | |
216 lastsize = nextdef->type->size(); | |
217 | |
218 // check if more defaults would fit | |
219 goto Lpadding; | |
220 } | |
221 // not found, pad with zeros | |
222 else | |
223 { | |
224 Logger::println("inserting %lu byte padding at %lu", offset - pos, pos); | |
225 addZeros(inits, pos, offset); | |
226 // offsets are updated by the explicit initializer | |
227 } | |
228 } | |
229 | |
230 // insert next explicit | |
231 Logger::println("adding explicit field: %s : +%lu", var->toChars(), offset); | |
232 LOG_SCOPE; | |
233 LLConstant* c = DtoConstInitializer(var->loc, var->type, ini); | |
234 inits.push_back(c); | |
235 | |
236 lastoffset = offset; | |
237 lastsize = size; | |
238 } | |
239 | |
240 // there might still be padding after the last one, make sure that is defaulted/zeroed as well | |
241 size_t structsize = getABITypeSize(structtype); | |
242 | |
243 // if there is space before the next explicit initializer | |
244 // FIXME: this should be handled in the loop above as well | |
245 Lpadding2: | |
246 size_t pos = lastoffset+lastsize; | |
247 if (structsize > pos) | |
248 { | |
249 // find the the next default initializer that fits in this space | |
250 VarDeclaration* nextdef = nextDefault(irstruct, j, lastoffset+lastsize, structsize); | |
251 | |
252 // found | |
253 if (nextdef) | |
254 { | |
255 // need zeros before the default | |
256 if (nextdef->offset > pos) | |
257 { | |
258 Logger::println("inserting %lu byte padding at %lu", nextdef->offset - pos, pos); | |
259 addZeros(inits, pos, nextdef->offset); | |
260 } | |
261 | |
262 // do the default | |
263 Logger::println("adding default field: %s : +%u", nextdef->toChars(), nextdef->offset); | |
264 LLConstant* c = nextdef->ir.irField->constInit; | |
265 inits.push_back(c); | |
266 | |
267 // update offsets | |
268 lastoffset = nextdef->offset; | |
269 lastsize = nextdef->type->size(); | |
270 | |
271 // check if more defaults would fit | |
272 goto Lpadding2; | |
273 } | |
274 // not found, pad with zeros | |
275 else | |
276 { | |
277 Logger::println("inserting %lu byte padding at %lu", structsize - pos, pos); | |
278 addZeros(inits, pos, structsize); | |
279 lastoffset = pos; | |
280 lastsize = structsize - pos; | |
281 } | |
282 } | |
283 | |
284 assert(lastoffset+lastsize == structsize); | |
285 | |
286 // make the constant struct | |
287 LLConstant* c = LLConstantStruct::get(inits, si->ad->ir.irStruct->packed); | |
288 if (Logger::enabled()) | |
289 { | |
290 Logger::cout() << "constant struct initializer: " << *c << '\n'; | |
291 } | |
292 assert(getABITypeSize(c->getType()) == structsize); | |
293 return c; | |
51 } | 294 } |
52 | 295 |
53 ////////////////////////////////////////////////////////////////////////////////////////// | 296 ////////////////////////////////////////////////////////////////////////////////////////// |
54 | 297 |
55 LLValue* DtoIndexStruct(LLValue* src, StructDeclaration* sd, VarDeclaration* vd) | 298 LLValue* DtoIndexStruct(LLValue* src, StructDeclaration* sd, VarDeclaration* vd) |
59 | 302 |
60 // vd must be a field | 303 // vd must be a field |
61 IrField* field = vd->ir.irField; | 304 IrField* field = vd->ir.irField; |
62 assert(field); | 305 assert(field); |
63 | 306 |
64 unsigned idx = field->index; | 307 // get the start pointer |
65 unsigned off = field->indexOffset; | |
66 | |
67 const LLType* st = getPtrToType(DtoType(sd->type)); | 308 const LLType* st = getPtrToType(DtoType(sd->type)); |
309 | |
310 // cast to the formal struct type | |
68 src = DtoBitCast(src, st); | 311 src = DtoBitCast(src, st); |
69 | 312 |
70 LLValue* val = DtoGEPi(src, 0,idx); | 313 // gep to the index |
314 LLValue* val = DtoGEPi(src, 0, field->index); | |
315 | |
316 // do we need to offset further? (union area) | |
317 if (field->unionOffset) | |
318 { | |
319 // cast to void* | |
320 val = DtoBitCast(val, getVoidPtrType()); | |
321 // offset | |
322 val = DtoGEPi1(val, field->unionOffset); | |
323 } | |
324 | |
325 // cast it to the right type | |
71 val = DtoBitCast(val, getPtrToType(DtoType(vd->type))); | 326 val = DtoBitCast(val, getPtrToType(DtoType(vd->type))); |
72 | |
73 if (off) | |
74 val = DtoGEPi1(val, off); | |
75 | 327 |
76 if (Logger::enabled()) | 328 if (Logger::enabled()) |
77 Logger::cout() << "value: " << *val << '\n'; | 329 Logger::cout() << "value: " << *val << '\n'; |
78 | 330 |
79 return val; | 331 return val; |
80 } | 332 } |
81 | 333 |
82 ////////////////////////////////////////////////////////////////////////////////////////// | |
83 | |
84 void DtoResolveStruct(StructDeclaration* sd) | 334 void DtoResolveStruct(StructDeclaration* sd) |
85 { | 335 { |
336 // don't do anything if already been here | |
86 if (sd->ir.resolved) return; | 337 if (sd->ir.resolved) return; |
338 // make sure above works :P | |
87 sd->ir.resolved = true; | 339 sd->ir.resolved = true; |
88 | 340 |
89 Logger::println("DtoResolveStruct(%s): %s", sd->toChars(), sd->loc.toChars()); | 341 // log what we're doing |
342 Logger::println("Resolving struct type: %s (%s)", sd->toChars(), sd->locToChars()); | |
90 LOG_SCOPE; | 343 LOG_SCOPE; |
91 | 344 |
92 TypeStruct* ts = (TypeStruct*)sd->type->toBasetype(); | 345 // get the DMD TypeStruct |
93 | 346 TypeStruct* ts = (TypeStruct*)sd->type; |
94 // this struct is a forward declaration | 347 |
348 // create the IrStruct | |
349 IrStruct* irstruct = new IrStruct(sd); | |
350 sd->ir.irStruct = irstruct; | |
351 | |
352 // create the type | |
353 ts->ir.type = new LLPATypeHolder(llvm::OpaqueType::get()); | |
354 | |
355 // handle forward declaration structs (opaques) | |
95 // didn't even know D had those ... | 356 // didn't even know D had those ... |
96 if (sd->sizeok != 1) | 357 if (sd->sizeok != 1) |
97 { | 358 { |
98 sd->ir.irStruct = new IrStruct(ts); | 359 // nothing more to do |
99 ts->ir.type = new llvm::PATypeHolder(llvm::OpaqueType::get()); | |
100 return; | 360 return; |
101 } | 361 } |
102 | 362 |
363 // make this struct current | |
364 gIR->structs.push_back(irstruct); | |
365 | |
366 // get some info | |
103 bool ispacked = (ts->alignsize() == 1); | 367 bool ispacked = (ts->alignsize() == 1); |
104 | 368 bool isunion = sd->isUnionDeclaration(); |
105 // create the IrStruct | 369 |
106 IrStruct* irstruct = new IrStruct(ts); | 370 // set irstruct info |
107 sd->ir.irStruct = irstruct; | |
108 gIR->structs.push_back(irstruct); | |
109 | |
110 // add fields | |
111 Array* fields = &sd->fields; | |
112 for (int k=0; k < fields->dim; k++) | |
113 { | |
114 VarDeclaration* v = (VarDeclaration*)fields->data[k]; | |
115 Logger::println("Adding field: %s %s", v->type->toChars(), v->toChars()); | |
116 // init fields, used to happen in VarDeclaration::toObjFile | |
117 irstruct->addField(v); | |
118 } | |
119 | |
120 irstruct->packed = ispacked; | 371 irstruct->packed = ispacked; |
121 | 372 |
373 // defined in this module? | |
122 bool thisModule = false; | 374 bool thisModule = false; |
123 if (sd->getModule() == gIR->dmodule) | 375 if (sd->getModule() == gIR->dmodule) |
124 thisModule = true; | 376 thisModule = true; |
125 | 377 |
126 // methods, fields | 378 // methods, fields |
127 Array* arr = sd->members; | 379 Array* arr = sd->members; |
128 for (int k=0; k < arr->dim; k++) { | 380 for (int k=0; k < arr->dim; k++) { |
129 Dsymbol* s = (Dsymbol*)arr->data[k]; | 381 Dsymbol* s = (Dsymbol*)arr->data[k]; |
130 if (FuncDeclaration* fd = s->isFuncDeclaration()) { | 382 s->toObjFile(0); |
131 if (thisModule || (fd->prot() != PROTprivate)) { | 383 } |
132 fd->toObjFile(0); // TODO: multiobj | 384 |
133 } | 385 const LLType* ST = irstruct->build(); |
134 } | 386 |
135 else if (s->isAttribDeclaration() || | 387 #if 0 |
136 s->isVarDeclaration() || | 388 std::cout << sd->kind() << ' ' << sd->toPrettyChars() << " type: " << *ST << '\n'; |
137 s->isTemplateMixin()) { | 389 |
138 s->toObjFile(0); // TODO: multiobj | 390 // add fields |
139 } | 391 for (int k=0; k < fields->dim; k++) |
140 else { | 392 { |
141 Logger::println("Ignoring dsymbol '%s' in this->members of kind '%s'", s->toPrettyChars(), s->kind()); | 393 VarDeclaration* v = (VarDeclaration*)fields->data[k]; |
142 } | 394 printf(" field: %s %s\n", v->type->toChars(), v->toChars()); |
143 } | 395 printf(" index: %u offset: %u\n", v->ir.irField->index, v->ir.irField->unionOffset); |
396 } | |
397 | |
398 unsigned llvmSize = (unsigned)getABITypeSize(ST); | |
399 unsigned dmdSize = (unsigned)sd->type->size(); | |
400 printf(" llvm size: %u dmd size: %u\n", llvmSize, dmdSize); | |
401 assert(llvmSize == dmdSize); | |
402 | |
403 #endif | |
144 | 404 |
145 /*for (int k=0; k < sd->members->dim; k++) { | 405 /*for (int k=0; k < sd->members->dim; k++) { |
146 Dsymbol* dsym = (Dsymbol*)(sd->members->data[k]); | 406 Dsymbol* dsym = (Dsymbol*)(sd->members->data[k]); |
147 dsym->toObjFile(); | 407 dsym->toObjFile(); |
148 }*/ | 408 }*/ |
149 | 409 |
150 Logger::println("doing struct fields"); | 410 Logger::println("doing struct fields"); |
151 | 411 |
152 const llvm::StructType* structtype = 0; | |
153 std::vector<const LLType*> fieldtypes; | |
154 | |
155 if (irstruct->offsets.empty()) | |
156 { | |
157 Logger::println("has no fields"); | |
158 fieldtypes.push_back(LLType::Int8Ty); | |
159 structtype = llvm::StructType::get(fieldtypes, ispacked); | |
160 } | |
161 else | |
162 { | |
163 Logger::println("has fields"); | |
164 unsigned prevsize = (unsigned)-1; | |
165 unsigned lastoffset = (unsigned)-1; | |
166 const LLType* fieldtype = NULL; | |
167 VarDeclaration* fieldinit = NULL; | |
168 size_t fieldpad = 0; | |
169 int idx = 0; | |
170 for (IrStruct::OffsetMap::iterator i=irstruct->offsets.begin(); i!=irstruct->offsets.end(); ++i) { | |
171 // first iteration | |
172 if (lastoffset == (unsigned)-1) { | |
173 lastoffset = i->first; | |
174 assert(lastoffset == 0); | |
175 fieldtype = i->second.type; | |
176 fieldinit = i->second.var; | |
177 prevsize = fieldinit->type->size(); | |
178 i->second.var->ir.irField->index = idx; | |
179 } | |
180 // colliding offset? | |
181 else if (lastoffset == i->first) { | |
182 size_t s = i->second.var->type->size(); | |
183 if (s > prevsize) { | |
184 fieldpad += s - prevsize; | |
185 prevsize = s; | |
186 } | |
187 sd->ir.irStruct->hasUnions = true; | |
188 i->second.var->ir.irField->index = idx; | |
189 } | |
190 // intersecting offset? | |
191 else if (i->first < (lastoffset + prevsize)) { | |
192 size_t s = i->second.var->type->size(); | |
193 assert((i->first + s) <= (lastoffset + prevsize)); // this holds because all types are aligned to their size | |
194 sd->ir.irStruct->hasUnions = true; | |
195 i->second.var->ir.irField->index = idx; | |
196 i->second.var->ir.irField->indexOffset = (i->first - lastoffset) / s; | |
197 } | |
198 // fresh offset | |
199 else { | |
200 // commit the field | |
201 fieldtypes.push_back(fieldtype); | |
202 irstruct->defaultFields.push_back(fieldinit); | |
203 if (fieldpad) { | |
204 fieldtypes.push_back(llvm::ArrayType::get(LLType::Int8Ty, fieldpad)); | |
205 irstruct->defaultFields.push_back(NULL); | |
206 idx++; | |
207 } | |
208 | |
209 idx++; | |
210 | |
211 // start new | |
212 lastoffset = i->first; | |
213 fieldtype = i->second.type; | |
214 fieldinit = i->second.var; | |
215 prevsize = fieldinit->type->size(); | |
216 i->second.var->ir.irField->index = idx; | |
217 fieldpad = 0; | |
218 } | |
219 } | |
220 fieldtypes.push_back(fieldtype); | |
221 irstruct->defaultFields.push_back(fieldinit); | |
222 if (fieldpad) { | |
223 fieldtypes.push_back(llvm::ArrayType::get(LLType::Int8Ty, fieldpad)); | |
224 irstruct->defaultFields.push_back(NULL); | |
225 } | |
226 | |
227 Logger::println("creating struct type"); | |
228 structtype = llvm::StructType::get(fieldtypes, ispacked); | |
229 } | |
230 | |
231 // refine abstract types for stuff like: struct S{S* next;} | 412 // refine abstract types for stuff like: struct S{S* next;} |
232 if (irstruct->recty != 0) | 413 llvm::cast<llvm::OpaqueType>(ts->ir.type->get())->refineAbstractTypeTo(ST); |
233 { | 414 ST = ts->ir.type->get(); |
234 llvm::PATypeHolder& pa = irstruct->recty; | 415 |
235 llvm::cast<llvm::OpaqueType>(pa.get())->refineAbstractTypeTo(structtype); | 416 // name type |
236 structtype = isaStruct(pa.get()); | |
237 } | |
238 | |
239 assert(ts->ir.type == 0); | |
240 ts->ir.type = new llvm::PATypeHolder(structtype); | |
241 | |
242 if (sd->parent->isModule()) { | 417 if (sd->parent->isModule()) { |
243 gIR->module->addTypeName(sd->mangle(),structtype); | 418 gIR->module->addTypeName(sd->mangle(),ST); |
244 } | 419 } |
245 | 420 |
246 gIR->structs.pop_back(); | 421 gIR->structs.pop_back(); |
247 | 422 |
248 gIR->declareList.push_back(sd); | 423 gIR->declareList.push_back(sd); |
263 std::string initname("_D"); | 438 std::string initname("_D"); |
264 initname.append(sd->mangle()); | 439 initname.append(sd->mangle()); |
265 initname.append("6__initZ"); | 440 initname.append("6__initZ"); |
266 | 441 |
267 llvm::GlobalValue::LinkageTypes _linkage = DtoExternalLinkage(sd); | 442 llvm::GlobalValue::LinkageTypes _linkage = DtoExternalLinkage(sd); |
268 llvm::GlobalVariable* initvar = new llvm::GlobalVariable(ts->ir.type->get(), true, _linkage, NULL, initname, gIR->module); | 443 llvm::GlobalVariable* initvar = new llvm::GlobalVariable(sd->ir.irStruct->initOpaque.get(), true, _linkage, NULL, initname, gIR->module); |
269 sd->ir.irStruct->init = initvar; | 444 sd->ir.irStruct->init = initvar; |
270 | 445 |
271 gIR->constInitList.push_back(sd); | 446 gIR->constInitList.push_back(sd); |
272 if (DtoIsTemplateInstance(sd) || sd->getModule() == gIR->dmodule) | 447 if (DtoIsTemplateInstance(sd) || sd->getModule() == gIR->dmodule) |
273 gIR->defineList.push_back(sd); | 448 gIR->defineList.push_back(sd); |
284 LOG_SCOPE; | 459 LOG_SCOPE; |
285 | 460 |
286 IrStruct* irstruct = sd->ir.irStruct; | 461 IrStruct* irstruct = sd->ir.irStruct; |
287 gIR->structs.push_back(irstruct); | 462 gIR->structs.push_back(irstruct); |
288 | 463 |
464 const llvm::StructType* structtype = isaStruct(sd->type->ir.type->get()); | |
465 | |
289 // make sure each offset knows its default initializer | 466 // make sure each offset knows its default initializer |
290 for (IrStruct::OffsetMap::iterator i=irstruct->offsets.begin(); i!=irstruct->offsets.end(); ++i) | 467 Array* fields = &sd->fields; |
291 { | 468 for (int k=0; k < fields->dim; k++) |
292 IrStruct::Offset* so = &i->second; | 469 { |
293 LLConstant* finit = DtoConstFieldInitializer(so->var->loc, so->var->type, so->var->init); | 470 VarDeclaration* v = (VarDeclaration*)fields->data[k]; |
294 so->init = finit; | 471 LLConstant* finit = DtoConstFieldInitializer(v->loc, v->type, v->init); |
295 so->var->ir.irField->constInit = finit; | 472 v->ir.irField->constInit = finit; |
296 } | 473 } |
297 | |
298 const llvm::StructType* structtype = isaStruct(sd->type->ir.type->get()); | |
299 | |
300 // go through the field inits and build the default initializer | |
301 std::vector<LLConstant*> fieldinits_ll; | |
302 size_t nfi = irstruct->defaultFields.size(); | |
303 for (size_t i=0; i<nfi; ++i) { | |
304 LLConstant* c; | |
305 if (irstruct->defaultFields[i] != NULL) { | |
306 c = irstruct->defaultFields[i]->ir.irField->constInit; | |
307 assert(c); | |
308 } | |
309 else { | |
310 const llvm::ArrayType* arrty = isaArray(structtype->getElementType(i)); | |
311 std::vector<LLConstant*> vals(arrty->getNumElements(), llvm::ConstantInt::get(LLType::Int8Ty, 0, false)); | |
312 c = llvm::ConstantArray::get(arrty, vals); | |
313 } | |
314 fieldinits_ll.push_back(c); | |
315 } | |
316 | |
317 // generate the union mapper | |
318 sd->ir.irStruct->dunion = new DUnion(); // uses gIR->topstruct() | |
319 | 474 |
320 // always generate the constant initalizer | 475 // always generate the constant initalizer |
321 if (!sd->zeroInit) { | 476 if (sd->zeroInit) |
477 { | |
478 Logger::println("Zero initialized"); | |
479 irstruct->constInit = llvm::ConstantAggregateZero::get(structtype); | |
480 } | |
481 else | |
482 { | |
322 Logger::println("Not zero initialized"); | 483 Logger::println("Not zero initialized"); |
323 #if 0 | 484 |
324 //assert(tk == gIR->gIR->topstruct()().size()); | 485 LLConstant* c = irstruct->buildDefaultConstInit(); |
325 #ifndef LLVMD_NO_LOGGER | 486 irstruct->constInit = c; |
326 Logger::cout() << "struct type: " << *structtype << '\n'; | 487 } |
327 for (size_t k=0; k<fieldinits_ll.size(); ++k) { | 488 |
328 Logger::cout() << "Type:" << '\n'; | 489 // refine __initZ global type to the one of the initializer |
329 Logger::cout() << *fieldinits_ll[k]->getType() << '\n'; | 490 llvm::cast<llvm::OpaqueType>(irstruct->initOpaque.get())->refineAbstractTypeTo(irstruct->constInit->getType()); |
330 Logger::cout() << "Value:" << '\n'; | |
331 Logger::cout() << *fieldinits_ll[k] << '\n'; | |
332 } | |
333 Logger::cout() << "Initializer printed" << '\n'; | |
334 #endif | |
335 #endif | |
336 sd->ir.irStruct->constInit = llvm::ConstantStruct::get(structtype,fieldinits_ll); | |
337 } | |
338 else { | |
339 Logger::println("Zero initialized"); | |
340 sd->ir.irStruct->constInit = llvm::ConstantAggregateZero::get(structtype); | |
341 } | |
342 | 491 |
343 gIR->structs.pop_back(); | 492 gIR->structs.pop_back(); |
344 | 493 |
345 // emit typeinfo | 494 // emit typeinfo |
346 if (sd->getModule() == gIR->dmodule && sd->llvmInternal != LLVMno_typeinfo) | 495 if (sd->getModule() == gIR->dmodule && sd->llvmInternal != LLVMno_typeinfo) |
383 // call memcmp | 532 // call memcmp |
384 size_t sz = getABITypeSize(DtoType(t)); | 533 size_t sz = getABITypeSize(DtoType(t)); |
385 LLValue* val = DtoMemCmp(lhs->getRVal(), rhs->getRVal(), DtoConstSize_t(sz)); | 534 LLValue* val = DtoMemCmp(lhs->getRVal(), rhs->getRVal(), DtoConstSize_t(sz)); |
386 return gIR->ir->CreateICmp(cmpop, val, LLConstantInt::get(val->getType(), 0, false), "tmp"); | 535 return gIR->ir->CreateICmp(cmpop, val, LLConstantInt::get(val->getType(), 0, false), "tmp"); |
387 } | 536 } |
388 | |
389 ////////////////////////////////////////////////////////////////////////////////////////// | |
390 //////////////////////////// D UNION HELPER CLASS //////////////////////////////////// | |
391 ////////////////////////////////////////////////////////////////////////////////////////// | |
392 | |
393 DUnion::DUnion() | |
394 { | |
395 DUnionField* f = NULL; | |
396 IrStruct* topstruct = gIR->topstruct(); | |
397 bool unions = false; | |
398 for (IrStruct::OffsetMap::iterator i=topstruct->offsets.begin(); i!=topstruct->offsets.end(); ++i) | |
399 { | |
400 unsigned o = i->first; | |
401 IrStruct::Offset* so = &i->second; | |
402 const LLType* ft = so->init->getType(); | |
403 size_t sz = getABITypeSize(ft); | |
404 if (f == NULL) { // new field | |
405 fields.push_back(DUnionField()); | |
406 f = &fields.back(); | |
407 f->size = sz; | |
408 f->offset = o; | |
409 f->init = so->init; | |
410 f->initsize = sz; | |
411 f->types.push_back(ft); | |
412 } | |
413 else if (o == f->offset) { // same offset | |
414 if (sz > f->size) | |
415 f->size = sz; | |
416 f->types.push_back(ft); | |
417 unions = true; | |
418 } | |
419 else if (o < f->offset+f->size) { | |
420 assert((o+sz) <= (f->offset+f->size)); | |
421 unions = true; | |
422 } | |
423 else { | |
424 fields.push_back(DUnionField()); | |
425 f = &fields.back(); | |
426 f->size = sz; | |
427 f->offset = o; | |
428 f->init = so->init; | |
429 f->initsize = sz; | |
430 f->types.push_back(ft); | |
431 } | |
432 } | |
433 | |
434 ispacked = topstruct->packed; | |
435 | |
436 /*{ | |
437 LOG_SCOPE; | |
438 Logger::println("******** DUnion BEGIN"); | |
439 size_t n = fields.size(); | |
440 for (size_t i=0; i<n; ++i) { | |
441 Logger::cout()<<"field #"<<i<<" offset: "<<fields[i].offset<<" size: "<<fields[i].size<<'('<<fields[i].initsize<<")\n"; | |
442 LOG_SCOPE; | |
443 size_t nt = fields[i].types.size(); | |
444 for (size_t j=0; j<nt; ++j) { | |
445 Logger::cout()<<*fields[i].types[j]<<'\n'; | |
446 } | |
447 } | |
448 Logger::println("******** DUnion END"); | |
449 }*/ | |
450 } | |
451 | |
452 static void push_nulls(size_t nbytes, std::vector<LLConstant*>& out) | |
453 { | |
454 assert(nbytes > 0); | |
455 std::vector<LLConstant*> i(nbytes, llvm::ConstantInt::get(LLType::Int8Ty, 0, false)); | |
456 out.push_back(llvm::ConstantArray::get(llvm::ArrayType::get(LLType::Int8Ty, nbytes), i)); | |
457 } | |
458 | |
459 LLConstant* DUnion::getConst(std::vector<DUnionIdx>& in) | |
460 { | |
461 std::sort(in.begin(), in.end()); | |
462 std::vector<LLConstant*> out; | |
463 | |
464 size_t nin = in.size(); | |
465 size_t nfields = fields.size(); | |
466 | |
467 size_t fi = 0; | |
468 size_t last = 0; | |
469 size_t ii = 0; | |
470 size_t os = 0; | |
471 | |
472 for(;;) | |
473 { | |
474 if (fi == nfields) break; | |
475 | |
476 bool nextSame = (ii+1 < nin) && (in[ii+1].idx == fi); | |
477 | |
478 if (ii < nin && fi == in[ii].idx) | |
479 { | |
480 size_t s = getABITypeSize(in[ii].c->getType()); | |
481 if (in[ii].idx == last) | |
482 { | |
483 size_t nos = in[ii].idxos * s; | |
484 if (nos && nos-os) { | |
485 assert(nos >= os); | |
486 push_nulls(nos-os, out); | |
487 } | |
488 os = nos + s; | |
489 } | |
490 else | |
491 { | |
492 os = s; | |
493 } | |
494 out.push_back(in[ii].c); | |
495 ii++; | |
496 if (!nextSame) | |
497 { | |
498 if (os < fields[fi].size) | |
499 push_nulls(fields[fi].size - os, out); | |
500 os = 0; | |
501 last = fi++; | |
502 } | |
503 continue; | |
504 } | |
505 | |
506 // default initialize if necessary | |
507 if (ii == nin || fi < in[ii].idx) | |
508 { | |
509 DUnionField& f = fields[fi]; | |
510 out.push_back(f.init); | |
511 if (f.initsize < f.size) | |
512 push_nulls(f.size - f.initsize, out); | |
513 last = fi++; | |
514 os = 0; | |
515 continue; | |
516 } | |
517 } | |
518 | |
519 std::vector<const LLType*> tys; | |
520 size_t nout = out.size(); | |
521 for (size_t i=0; i<nout; ++i) | |
522 tys.push_back(out[i]->getType()); | |
523 | |
524 const llvm::StructType* st = llvm::StructType::get(tys, ispacked); | |
525 return llvm::ConstantStruct::get(st, out); | |
526 } | |
527 | |
528 | |
529 | |
530 | |
531 | |
532 | |
533 | |
534 | |
535 | |
536 | |
537 | |
538 | |
539 | |
540 | |
541 | |
542 | |
543 | |
544 | |
545 | |
546 | |
547 |