Mercurial > projects > ldc
comparison gen/arrays.cpp @ 914:a65a6996922f
Fixed bug #191 by rewriting DtoConstArrayInitializer, patch unfortunately caused regressions, hopefully this doesn't :P
author | Tomas Lindquist Olsen <tomas.l.olsen@gmail.com> |
---|---|
date | Sun, 01 Feb 2009 23:30:36 +0100 |
parents | a70ddd449e7d |
children | 5e3bb0c3ea8b |
comparison
equal
deleted
inserted
replaced
913:29c0d1194033 | 914:a65a6996922f |
---|---|
214 DtoStore(ptr, DtoGEPi(arr,0,1)); | 214 DtoStore(ptr, DtoGEPi(arr,0,1)); |
215 } | 215 } |
216 | 216 |
217 ////////////////////////////////////////////////////////////////////////////////////////// | 217 ////////////////////////////////////////////////////////////////////////////////////////// |
218 | 218 |
219 // FIXME: this looks like it could use a cleanup | |
220 | |
221 LLConstant* DtoConstArrayInitializer(ArrayInitializer* arrinit) | 219 LLConstant* DtoConstArrayInitializer(ArrayInitializer* arrinit) |
222 { | 220 { |
223 Logger::println("DtoConstArrayInitializer: %s | %s", arrinit->toChars(), arrinit->type->toChars()); | 221 Logger::println("DtoConstArrayInitializer: %s | %s", arrinit->toChars(), arrinit->type->toChars()); |
224 LOG_SCOPE; | 222 LOG_SCOPE; |
225 | 223 |
226 Type* arrinittype = arrinit->type->toBasetype(); | 224 assert(arrinit->value.dim == arrinit->index.dim); |
227 | 225 |
228 Type* t; | 226 // get base array type |
229 integer_t tdim; | 227 Type* arrty = arrinit->type->toBasetype(); |
230 if (arrinittype->ty == Tsarray) { | 228 size_t arrlen = arrinit->dim; |
231 Logger::println("static array"); | 229 |
232 TypeSArray* tsa = (TypeSArray*)arrinittype; | 230 // for statis arrays, dmd does not include any trailing default |
233 tdim = tsa->dim->toInteger(); | 231 // initialized elements in the value/index lists |
234 t = tsa; | 232 if (arrty->ty == Tsarray) |
235 } | 233 { |
236 else if (arrinittype->ty == Tarray) { | 234 TypeSArray* tsa = (TypeSArray*)arrty; |
237 Logger::println("dynamic array"); | 235 arrlen = (size_t)tsa->dim->toInteger(); |
238 t = arrinittype; | 236 } |
239 tdim = arrinit->dim; | 237 |
240 } | 238 // make sure the number of initializers is sane |
239 if (arrinit->index.dim > arrlen || arrinit->dim > arrlen) | |
240 { | |
241 error(arrinit->loc, "too many initializers, %d, for array[%d]", arrinit->index.dim, arrlen); | |
242 fatal(); | |
243 } | |
244 | |
245 // get elem type | |
246 Type* elemty = arrty->nextOf(); | |
247 const LLType* llelemty = DtoType(elemty); | |
248 | |
249 // true if array elements differ in type, can happen with array of unions | |
250 bool mismatch = false; | |
251 | |
252 // allocate room for initializers | |
253 std::vector<LLConstant*> initvals(arrlen, NULL); | |
254 | |
255 // go through each initializer, they're not sorted by index by the frontend | |
256 size_t j = 0; | |
257 for (size_t i = 0; i < arrinit->index.dim; i++) | |
258 { | |
259 // get index | |
260 Expression* idx = (Expression*)arrinit->index.data[i]; | |
261 | |
262 // idx can be null, then it's just the next element | |
263 if (idx) | |
264 j = idx->toInteger(); | |
265 assert(j < arrlen); | |
266 | |
267 // get value | |
268 Initializer* val = (Initializer*)arrinit->value.data[i]; | |
269 assert(val); | |
270 | |
271 // error check from dmd | |
272 if (initvals[j] != NULL) | |
273 { | |
274 error(arrinit->loc, "duplicate initialization for index %d", j); | |
275 } | |
276 | |
277 LLConstant* c = DtoConstInitializer(val->loc, elemty, val); | |
278 assert(c); | |
279 if (c->getType() != llelemty) | |
280 mismatch = true; | |
281 | |
282 initvals[j] = c; | |
283 j++; | |
284 } | |
285 | |
286 // die now if there was errors | |
287 if (global.errors) | |
288 fatal(); | |
289 | |
290 // fill out any null entries still left with default values | |
291 | |
292 // element default initializer | |
293 LLConstant* defelem = elemty->defaultInit(arrinit->loc)->toConstElem(gIR); | |
294 bool mismatch2 = (defelem->getType() != llelemty); | |
295 | |
296 for (size_t i = 0; i < arrlen; i++) | |
297 { | |
298 if (initvals[i] != NULL) | |
299 continue; | |
300 | |
301 initvals[i] = defelem; | |
302 | |
303 if (mismatch2) | |
304 mismatch = true; | |
305 } | |
306 | |
307 LLConstant* constarr; | |
308 if (mismatch) | |
309 constarr = LLConstantStruct::get(initvals); | |
241 else | 310 else |
242 assert(0); | 311 constarr = LLConstantArray::get(LLArrayType::get(llelemty, arrlen), initvals); |
243 | 312 |
244 if(arrinit->dim > tdim) | 313 // std::cout << "constarr: " << *constarr << std::endl; |
245 error(arrinit->loc, "array initializer for %s is too long (%d)", arrinit->type->toChars(), arrinit->dim); | 314 |
246 | 315 // if the type is a static array, we're done |
247 Logger::println("dim = %u", tdim); | 316 if (arrty->ty == Tsarray) |
248 | |
249 std::vector<LLConstant*> inits(tdim, NULL); | |
250 | |
251 Type* arrnext = arrinittype->nextOf(); | |
252 const LLType* elemty = DtoType(arrinittype->nextOf()); | |
253 | |
254 // true if there is a mismatch with one of the initializers | |
255 bool mismatch = false; | |
256 | |
257 assert(arrinit->index.dim == arrinit->value.dim); | |
258 for (unsigned i=0,j=0; i < tdim; ++i) | |
259 { | |
260 Initializer* init = 0; | |
261 Expression* idx; | |
262 | |
263 if (j < arrinit->index.dim) | |
264 idx = (Expression*)arrinit->index.data[j]; | |
265 else | |
266 idx = NULL; | |
267 | |
268 LLConstant* v = NULL; | |
269 | |
270 if (idx) | |
271 { | |
272 Logger::println("%d has idx", i); | |
273 // this is pretty weird :/ idx->type turned out NULL for the initializer: | |
274 // const in6_addr IN6ADDR_ANY = { s6_addr8: [0] }; | |
275 // in std.c.linux.socket | |
276 if (idx->type) { | |
277 Logger::println("has idx->type", i); | |
278 //integer_t k = idx->toInteger(); | |
279 //Logger::println("getting value for exp: %s | %s", idx->toChars(), arrnext->toChars()); | |
280 LLConstant* cc = idx->toConstElem(gIR); | |
281 Logger::println("value gotten"); | |
282 assert(cc != NULL); | |
283 LLConstantInt* ci = llvm::dyn_cast<LLConstantInt>(cc); | |
284 assert(ci != NULL); | |
285 uint64_t k = ci->getZExtValue(); | |
286 if (i == k) | |
287 { | |
288 init = (Initializer*)arrinit->value.data[j]; | |
289 assert(init); | |
290 ++j; | |
291 } | |
292 } | |
293 } | |
294 else | |
295 { | |
296 if (j < arrinit->value.dim) { | |
297 init = (Initializer*)arrinit->value.data[j]; | |
298 ++j; | |
299 } | |
300 else | |
301 v = arrnext->defaultInit()->toConstElem(gIR); | |
302 } | |
303 | |
304 if (!v) | |
305 v = DtoConstInitializer(arrinit->loc, t->nextOf(), init); | |
306 assert(v); | |
307 | |
308 // global arrays of unions might have type mismatch for each element | |
309 // if there is any mismatch at all, we need to use a struct instead :/ | |
310 if (v->getType() != elemty) | |
311 mismatch = true; | |
312 | |
313 inits[i] = v; | |
314 if (Logger::enabled()) | |
315 Logger::cout() << "llval: " << *v << '\n'; | |
316 } | |
317 | |
318 Logger::println("building constant array"); | |
319 | |
320 LLConstant* constarr; | |
321 const LLArrayType* arrty = LLArrayType::get(elemty,tdim); | |
322 | |
323 if (mismatch) | |
324 { | |
325 constarr = LLConstantStruct::get(inits); | |
326 } | |
327 else | |
328 { | |
329 constarr = LLConstantArray::get(arrty, inits); | |
330 } | |
331 | |
332 #if 0 | |
333 if (Logger::enabled()) | |
334 { | |
335 Logger::cout() << "array type: " << *arrty << '\n'; | |
336 size_t n = inits.size(); | |
337 for (size_t i=0; i<n; i++) | |
338 Logger::cout() << " init " << i << " = " << *inits[i] << '\n'; | |
339 } | |
340 #endif | |
341 | |
342 if (arrinittype->ty == Tsarray) | |
343 return constarr; | 317 return constarr; |
344 else | 318 |
345 assert(arrinittype->ty == Tarray); | 319 // for dynamic array we need to make a global with the data, so we have a pointer for the dynamic array |
346 | 320 LLGlobalVariable* gvar = new LLGlobalVariable(constarr->getType(), true, LLGlobalValue::InternalLinkage, constarr, ".constarray", gIR->module); |
347 LLGlobalVariable* gvar = new LLGlobalVariable(constarr->getType(),true,LLGlobalValue::InternalLinkage,constarr,".constarray",gIR->module); | |
348 LLConstant* idxs[2] = { DtoConstUint(0), DtoConstUint(0) }; | 321 LLConstant* idxs[2] = { DtoConstUint(0), DtoConstUint(0) }; |
349 | 322 |
350 LLConstant* gep = llvm::ConstantExpr::getGetElementPtr(gvar,idxs,2); | 323 LLConstant* gep = llvm::ConstantExpr::getGetElementPtr(gvar,idxs,2); |
351 gep = llvm::ConstantExpr::getBitCast(gvar, getPtrToType(elemty)); | 324 gep = llvm::ConstantExpr::getBitCast(gvar, getPtrToType(llelemty)); |
352 | 325 |
353 return DtoConstSlice(DtoConstSize_t(tdim),gep); | 326 return DtoConstSlice(DtoConstSize_t(arrlen),gep); |
354 } | 327 } |
355 | 328 |
356 ////////////////////////////////////////////////////////////////////////////////////////// | 329 ////////////////////////////////////////////////////////////////////////////////////////// |
357 static LLValue* get_slice_ptr(DSliceValue* e, LLValue*& sz) | 330 static LLValue* get_slice_ptr(DSliceValue* e, LLValue*& sz) |
358 { | 331 { |