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);