Mercurial > projects > ldc
comparison ir/irstruct.cpp @ 1240:f295e51d2dd0
Fixed static struct initializers.
author | Tomas Lindquist Olsen <tomas.l.olsen gmail.com> |
---|---|
date | Fri, 17 Apr 2009 00:36:21 +0200 |
parents | 212ec2d9d176 |
children | 465a77c904d4 |
comparison
equal
deleted
inserted
replaced
1239:ff1b4cc2e9be | 1240:f295e51d2dd0 |
---|---|
12 #include "gen/utils.h" | 12 #include "gen/utils.h" |
13 | 13 |
14 #include "ir/irstruct.h" | 14 #include "ir/irstruct.h" |
15 #include "ir/irtypeclass.h" | 15 #include "ir/irtypeclass.h" |
16 | 16 |
17 #include <algorithm> | |
18 | |
17 ////////////////////////////////////////////////////////////////////////////// | 19 ////////////////////////////////////////////////////////////////////////////// |
18 | 20 |
19 IrStruct::IrStruct(AggregateDeclaration* aggr) | 21 IrStruct::IrStruct(AggregateDeclaration* aggr) |
20 : diCompositeType(NULL) | 22 : diCompositeType(NULL) |
21 { | 23 { |
204 ////////////////////////////////////////////////////////////////////////////// | 206 ////////////////////////////////////////////////////////////////////////////// |
205 ////////////////////////////////////////////////////////////////////////////// | 207 ////////////////////////////////////////////////////////////////////////////// |
206 | 208 |
207 // yet another rewrite of the notorious StructInitializer. | 209 // yet another rewrite of the notorious StructInitializer. |
208 | 210 |
211 typedef std::pair<VarDeclaration*, llvm::Constant*> VCPair; | |
212 | |
213 bool struct_init_data_sort(const VCPair& a, const VCPair& b) | |
214 { | |
215 return (a.first && b.first) | |
216 ? a.first->offset < b.first->offset | |
217 : false; | |
218 } | |
219 | |
209 // this time a bit more inspired by the DMD code. | 220 // this time a bit more inspired by the DMD code. |
210 | 221 |
211 LLConstant * IrStruct::createStructInitializer(StructInitializer * si) | 222 LLConstant * IrStruct::createStructInitializer(StructInitializer * si) |
212 { | 223 { |
213 IF_LOG Logger::println("Building StructInitializer of type %s", si->ad->toPrettyChars()); | 224 IF_LOG Logger::println("Building StructInitializer of type %s", si->ad->toPrettyChars()); |
216 // sanity check | 227 // sanity check |
217 assert(si->ad == aggrdecl && "struct type mismatch"); | 228 assert(si->ad == aggrdecl && "struct type mismatch"); |
218 assert(si->vars.dim == si->value.dim && "inconsistent StructInitializer"); | 229 assert(si->vars.dim == si->value.dim && "inconsistent StructInitializer"); |
219 | 230 |
220 // array of things to build | 231 // array of things to build |
221 typedef std::pair<VarDeclaration*, llvm::Constant*> VCPair; | |
222 llvm::SmallVector<VCPair, 16> data(aggrdecl->fields.dim); | 232 llvm::SmallVector<VCPair, 16> data(aggrdecl->fields.dim); |
223 | 233 |
224 // start by creating a map from initializer indices to field indices. | 234 // start by creating a map from initializer indices to field indices. |
225 // I have no fucking clue why dmd represents it like this :/ | 235 // I have no fucking clue why dmd represents it like this :/ |
226 size_t n = si->vars.dim; | 236 size_t n = si->vars.dim; |
252 Loc l = ini ? ini->loc : si->loc; | 262 Loc l = ini ? ini->loc : si->loc; |
253 error(l, "duplicate initialization of %s", vd->toChars()); | 263 error(l, "duplicate initialization of %s", vd->toChars()); |
254 continue; | 264 continue; |
255 } | 265 } |
256 | 266 |
267 IF_LOG Logger::println("Explicit initializer: %s @+%u", vd->toChars(), vd->offset); | |
268 LOG_SCOPE; | |
269 | |
257 data[idx].first = vd; | 270 data[idx].first = vd; |
258 data[idx].second = get_default_initializer(vd, ini); | 271 data[idx].second = get_default_initializer(vd, ini); |
259 } | 272 } |
260 | 273 |
261 // build array of constants and try to fill in default initializers | 274 // fill in implicit initializers |
262 // where there is room. | 275 n = data.size(); |
276 for (size_t i = 0; i < n; i++) | |
277 { | |
278 VarDeclaration* vd = data[i].first; | |
279 if (vd) | |
280 continue; | |
281 | |
282 vd = (VarDeclaration*)aggrdecl->fields.data[i]; | |
283 | |
284 unsigned vd_begin = vd->offset; | |
285 unsigned vd_end = vd_begin + vd->type->size(); | |
286 | |
287 // make sure it doesn't overlap any explicit initializers. | |
288 VarDeclarationIter it(aggrdecl->fields); | |
289 bool overlaps = false; | |
290 size_t j = 0; | |
291 for (; it.more(); it.next(), j++) | |
292 { | |
293 if (i == j || !data[j].first) | |
294 continue; | |
295 | |
296 unsigned f_begin = it->offset; | |
297 unsigned f_end = f_begin + it->type->size(); | |
298 | |
299 if (vd_begin >= f_end || vd_end <= f_begin) | |
300 continue; | |
301 | |
302 overlaps = true; | |
303 break; | |
304 } | |
305 // add if no overlap found | |
306 if (!overlaps) | |
307 { | |
308 IF_LOG Logger::println("Implicit initializer: %s @+%u", vd->toChars(), vd->offset); | |
309 LOG_SCOPE; | |
310 | |
311 data[i].first = vd; | |
312 data[i].second = get_default_initializer(vd, NULL); | |
313 } | |
314 } | |
315 | |
316 // stop if there were errors | |
317 if (global.errors) | |
318 { | |
319 fatal(); | |
320 } | |
321 | |
322 // sort data array by offset | |
323 std::sort(data.begin(), data.end(), struct_init_data_sort); | |
324 | |
325 // build array of constants and make sure explicit zero padding is inserted when necessary. | |
263 size_t offset = 0; | 326 size_t offset = 0; |
264 std::vector<llvm::Constant*> constants; | 327 std::vector<llvm::Constant*> constants; |
265 constants.reserve(16); | 328 constants.reserve(n); |
266 | 329 |
267 n = data.size(); | |
268 for (size_t i = 0; i < n; i++) | 330 for (size_t i = 0; i < n; i++) |
269 { | 331 { |
270 VarDeclaration* vd = data[i].first; | 332 VarDeclaration* vd = data[i].first; |
271 | 333 if (vd == NULL) |
272 // explicitly initialized? | 334 continue; |
273 if (vd != NULL) | 335 |
274 { | 336 // get next aligned offset for this field |
275 // get next aligned offset for this field | 337 size_t alignedoffset = offset; |
276 size_t alignedoffset = offset; | 338 if (!packed) |
277 if (!packed) | 339 { |
278 { | 340 size_t alignsize = vd->type->alignsize(); |
279 size_t alignsize = vd->type->alignsize(); | 341 alignedoffset = (offset + alignsize - 1) & ~(alignsize - 1); |
280 alignedoffset = (offset + alignsize - 1) & ~(alignsize - 1); | 342 } |
281 } | 343 |
282 | 344 // insert explicit padding? |
283 // insert explicit padding? | 345 if (alignedoffset < vd->offset) |
284 if (alignedoffset < vd->offset) | 346 { |
285 { | 347 size_t diff = vd->offset - alignedoffset; |
286 add_zeros(constants, vd->offset - alignedoffset); | 348 IF_LOG Logger::println("adding %zu bytes zero padding", diff); |
287 } | 349 add_zeros(constants, diff); |
288 | 350 } |
289 IF_LOG Logger::println("using field: %s", vd->toChars()); | 351 |
290 constants.push_back(data[i].second); | 352 IF_LOG Logger::println("adding field %s", vd->toChars()); |
291 offset = vd->offset + vd->type->size(); | 353 |
292 } | 354 constants.push_back(data[i].second); |
293 // not explicit! try and fit in the default initialization instead | 355 offset = vd->offset + vd->type->size(); |
294 // make sure we don't overlap with any following explicity initialized fields | |
295 else | |
296 { | |
297 vd = (VarDeclaration*)aggrdecl->fields.data[i]; | |
298 | |
299 // check all the way that we don't overlap, slow but it works! | |
300 for (size_t j = i+1; j <= n; j++) | |
301 { | |
302 if (j == n) // no overlap | |
303 { | |
304 IF_LOG Logger::println("using field default: %s", vd->toChars()); | |
305 constants.push_back(get_default_initializer(vd, NULL)); | |
306 offset = vd->offset + vd->type->size(); | |
307 break; | |
308 } | |
309 | |
310 VarDeclaration* vd2 = (VarDeclaration*)aggrdecl->fields.data[j]; | |
311 | |
312 size_t o2 = vd->offset + vd->type->size(); | |
313 | |
314 if (vd2->offset < o2 && data[i].first) | |
315 break; // overlaps | |
316 } | |
317 } | |
318 } | 356 } |
319 | 357 |
320 // tail padding? | 358 // tail padding? |
321 if (offset < aggrdecl->structsize) | 359 if (offset < aggrdecl->structsize) |
322 { | 360 { |
323 add_zeros(constants, aggrdecl->structsize - offset); | 361 size_t diff = aggrdecl->structsize - offset; |
324 } | 362 IF_LOG Logger::println("adding %zu bytes zero padding", diff); |
325 | 363 add_zeros(constants, diff); |
326 // stop if there were errors | |
327 if (global.errors) | |
328 { | |
329 fatal(); | |
330 } | 364 } |
331 | 365 |
332 // build constant | 366 // build constant |
333 assert(!constants.empty()); | 367 assert(!constants.empty()); |
334 llvm::Constant* c = llvm::ConstantStruct::get(&constants[0], constants.size(), packed); | 368 llvm::Constant* c = llvm::ConstantStruct::get(&constants[0], constants.size(), packed); |