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 {