Mercurial > projects > ldc
comparison gen/llvmhelpers.cpp @ 468:45a67b6f1310
Removed the 'needsstorage' thing from Dsymbol. Arguments are not always given storage when applicable. This is not longer treat specially
in this regard. Code for accessing nested variables and contexts rewritten. Probably more. Fairly well tested.
author | Tomas Lindquist Olsen <tomas.l.olsen@gmail.com> |
---|---|
date | Mon, 04 Aug 2008 02:59:34 +0200 |
parents | 60332cd85308 |
children | 672eb4893b55 |
comparison
equal
deleted
inserted
replaced
467:261b05cf4d1c | 468:45a67b6f1310 |
---|---|
328 /****************************************************************************************/ | 328 /****************************************************************************************/ |
329 /*//////////////////////////////////////////////////////////////////////////////////////// | 329 /*//////////////////////////////////////////////////////////////////////////////////////// |
330 // NESTED VARIABLE HELPERS | 330 // NESTED VARIABLE HELPERS |
331 ////////////////////////////////////////////////////////////////////////////////////////*/ | 331 ////////////////////////////////////////////////////////////////////////////////////////*/ |
332 | 332 |
333 static const LLType* get_next_frame_ptr_type(Dsymbol* sc) | 333 /* |
334 { | 334 |
335 assert(sc->isFuncDeclaration() || sc->isClassDeclaration()); | 335 got: |
336 Dsymbol* p = sc->toParent2(); | 336 |
337 if (!p->isFuncDeclaration() && !p->isClassDeclaration()) | 337 context pointer of 'this' function |
338 Logger::println("unexpected parent symbol found while resolving frame pointer - '%s' kind: '%s'", p->toChars(), p->kind()); | 338 |
339 assert(p->isFuncDeclaration() || p->isClassDeclaration()); | 339 declaration for target context's function |
340 if (FuncDeclaration* fd = p->isFuncDeclaration()) | 340 |
341 { | 341 want: |
342 LLValue* v = fd->ir.irFunc->nestedVar; | 342 |
343 assert(v); | 343 context pointer of target function in call chain |
344 return v->getType(); | 344 |
345 } | 345 */ |
346 else if (ClassDeclaration* cd = p->isClassDeclaration()) | 346 |
347 { | 347 static LLValue* dive_into_nested(Dsymbol* from, LLValue* val) |
348 return DtoType(cd->type); | 348 { |
349 } | 349 from = from->toParent2(); |
350 | |
351 // parent is a function | |
352 if (FuncDeclaration* f = from->isFuncDeclaration()) | |
353 { | |
354 IrFunction* irfunc = f->ir.irFunc; | |
355 // parent has nested var struct | |
356 if (irfunc->nestedVar) | |
357 { | |
358 return DtoBitCast(val, irfunc->nestedVar->getType()); | |
359 } | |
360 // parent has this argument | |
361 else if (irfunc->thisVar) | |
362 { | |
363 return DtoBitCast(val, irfunc->thisVar->getType()->getContainedType(0)); | |
364 } | |
365 // none of the above, means no context is required, dummy. | |
366 else | |
367 { | |
368 return getNullPtr(getVoidPtrType()); | |
369 } | |
370 } | |
371 // parent is a class | |
372 else if (ClassDeclaration* c = from->isClassDeclaration()) | |
373 { | |
374 return DtoBitCast(DtoLoad(val), DtoType(c->type)); | |
375 } | |
376 // parent is not valid | |
350 else | 377 else |
351 { | 378 { |
352 Logger::println("symbol: '%s' kind: '%s'", sc->toChars(), sc->kind()); | 379 assert(0 && "!(class|function)"); |
353 assert(0); | 380 } |
354 } | 381 } |
355 } | 382 |
356 | 383 LLValue* DtoNestedContext(FuncDeclaration* func) |
357 ////////////////////////////////////////////////////////////////////////////////////////// | 384 { |
358 | 385 Logger::println("listing context frame list for funcdecl '%s'", func->toPrettyChars()); |
359 static LLValue* get_frame_ptr_impl(FuncDeclaration* func, Dsymbol* sc, LLValue* v) | |
360 { | |
361 LOG_SCOPE; | 386 LOG_SCOPE; |
362 if (sc == func) | 387 |
363 { | 388 int level = 0; |
364 return v; | 389 |
365 } | 390 IrFunction* irfunc = gIR->func(); |
366 else if (FuncDeclaration* fd = sc->isFuncDeclaration()) | 391 Dsymbol* current = irfunc->decl; |
367 { | 392 |
368 Logger::println("scope is function: %s", fd->toChars()); | 393 // this context ? |
369 | 394 if (current == func) |
370 if (fd->toParent2() == func) | 395 { |
371 { | 396 return irfunc->nestedVar; |
372 if (!func->ir.irFunc->nestedVar) | 397 } |
373 return NULL; | 398 |
374 return DtoBitCast(v, func->ir.irFunc->nestedVar->getType()); | 399 // otherwise use the context argument |
375 } | 400 LLValue* val = dive_into_nested(current, irfunc->thisVar); |
376 | 401 current = current->toParent2(); |
377 v = DtoBitCast(v, get_next_frame_ptr_type(fd)); | 402 assert(val); |
378 Logger::cout() << "v = " << *v << '\n'; | 403 |
379 | 404 for (;;) |
380 if (fd->toParent2()->isFuncDeclaration()) | 405 { |
381 { | 406 Logger::cout() << "context: " << *val << '\n'; |
382 v = DtoGEPi(v, 0,0, "tmp"); | 407 Logger::println("(%d) looking in: %s (%s)", level, current->toPrettyChars(), current->kind()); |
408 if (FuncDeclaration* f = current->isFuncDeclaration()) | |
409 { | |
410 if (f == func) | |
411 { | |
412 Logger::println("-> found <-"); | |
413 Logger::cout() << "-> val: " << *val << '\n'; | |
414 return val; | |
415 } | |
416 else | |
417 { | |
418 val = DtoLoad(DtoGEPi(val,0,0)); | |
419 } | |
420 } | |
421 else if (ClassDeclaration* c = current->isClassDeclaration()) | |
422 { | |
423 val = DtoLoad(DtoGEPi(val, 0, 2+c->vthis->ir.irField->index)); | |
424 val = dive_into_nested(current, val); | |
425 } | |
426 else | |
427 { | |
428 Logger::cout() << "val: " << *val << '\n'; | |
429 assert(0 && "!(class|function)"); | |
430 } | |
431 current = current->toParent2(); | |
432 ++level; | |
433 } | |
434 | |
435 assert(0); | |
436 return val; | |
437 } | |
438 | |
439 DValue* DtoNestedVariable(Type* astype, VarDeclaration* vd) | |
440 { | |
441 IrFunction* irfunc = gIR->func(); | |
442 | |
443 // var parent (the scope we're looking for) | |
444 Dsymbol* varParent = vd->toParent2(); | |
445 | |
446 // on level 0 | |
447 if (varParent == irfunc->decl) | |
448 { | |
449 LLValue* nest = irfunc->nestedVar; | |
450 LLValue* v = DtoGEPi(nest, 0, vd->ir.irLocal->nestedIndex, "tmp"); | |
451 // references must be loaded to get the variable address | |
452 if (vd->isParameter() && (vd->isRef() || vd->isOut() || DtoIsPassedByRef(vd->type))) | |
383 v = DtoLoad(v); | 453 v = DtoLoad(v); |
384 } | 454 return new DVarValue(astype, vd, v, true); |
385 else if (ClassDeclaration* cd = fd->toParent2()->isClassDeclaration()) | 455 } |
386 { | 456 |
387 v = DtoGEPi(v,0,2+cd->vthis->ir.irField->index,"tmp"); | 457 // on level n != 0 |
388 v = DtoLoad(v); | 458 FuncDeclaration* varFunc = varParent->isFuncDeclaration(); |
389 } | 459 assert(varFunc); |
390 else | 460 |
391 { | 461 // get context of variable |
392 assert(0); | 462 LLValue* ctx = DtoNestedContext(varFunc); |
393 } | 463 |
394 return get_frame_ptr_impl(func, fd->toParent2(), v); | 464 // if no local var, it's the context itself (class this) |
395 } | 465 if (!vd->ir.irLocal) |
396 else if (ClassDeclaration* cd = sc->isClassDeclaration()) | 466 return new DImValue(astype, ctx); |
397 { | 467 |
398 Logger::println("scope is class: %s", cd->toChars()); | 468 // extract variable |
399 return get_frame_ptr_impl(func, cd->toParent2(), v); | 469 IrLocal* local = vd->ir.irLocal; |
400 } | 470 assert(local); |
401 else | 471 assert(local->nestedIndex >= 0); |
402 { | 472 LLValue* val = DtoGEPi(ctx, 0, local->nestedIndex); |
403 Logger::println("symbol: '%s'", sc->toPrettyChars()); | 473 |
404 assert(0); | 474 // references must be loaded to get the variable address |
405 } | |
406 } | |
407 | |
408 ////////////////////////////////////////////////////////////////////////////////////////// | |
409 | |
410 static LLValue* get_frame_ptr(FuncDeclaration* func) | |
411 { | |
412 Logger::println("Resolving context pointer for nested function: '%s'", func->toPrettyChars()); | |
413 LOG_SCOPE; | |
414 IrFunction* irfunc = gIR->func(); | |
415 | |
416 // in the right scope already | |
417 if (func == irfunc->decl) | |
418 return irfunc->decl->ir.irFunc->nestedVar; | |
419 | |
420 // use the 'this' pointer | |
421 LLValue* ptr = irfunc->decl->ir.irFunc->thisVar; | |
422 assert(ptr); | |
423 | |
424 // return the fully resolved frame pointer | |
425 ptr = get_frame_ptr_impl(func, irfunc->decl, ptr); | |
426 if (ptr) Logger::cout() << "Found context!" << *ptr; | |
427 else Logger::cout() << "NULL context!\n"; | |
428 | |
429 return ptr; | |
430 } | |
431 | |
432 ////////////////////////////////////////////////////////////////////////////////////////// | |
433 | |
434 LLValue* DtoNestedContext(FuncDeclaration* func) | |
435 { | |
436 // resolve frame ptr | |
437 LLValue* ptr = get_frame_ptr(func); | |
438 Logger::cout() << "Nested context ptr = "; | |
439 if (ptr) Logger::cout() << *ptr; | |
440 else Logger::cout() << "NULL"; | |
441 Logger::cout() << '\n'; | |
442 return ptr; | |
443 } | |
444 | |
445 ////////////////////////////////////////////////////////////////////////////////////////// | |
446 | |
447 static void print_frame_worker(VarDeclaration* vd, Dsymbol* par) | |
448 { | |
449 if (vd->toParent2() == par) | |
450 { | |
451 Logger::println("found: '%s' kind: '%s'", par->toChars(), par->kind()); | |
452 return; | |
453 } | |
454 | |
455 Logger::println("diving into: '%s' kind: '%s'", par->toChars(), par->kind()); | |
456 LOG_SCOPE; | |
457 print_frame_worker(vd, par->toParent2()); | |
458 } | |
459 | |
460 ////////////////////////////////////////////////////////////////////////////////////////// | |
461 | |
462 static void print_nested_frame_list(VarDeclaration* vd, Dsymbol* par) | |
463 { | |
464 Logger::println("Frame pointer list for nested var: '%s'", vd->toPrettyChars()); | |
465 LOG_SCOPE; | |
466 if (vd->toParent2() != par) | |
467 print_frame_worker(vd, par); | |
468 else | |
469 Logger::println("Found at level 0"); | |
470 Logger::println("Done"); | |
471 } | |
472 | |
473 ////////////////////////////////////////////////////////////////////////////////////////// | |
474 | |
475 LLValue* DtoNestedVariable(VarDeclaration* vd) | |
476 { | |
477 // log the frame list | |
478 IrFunction* irfunc = gIR->func(); | |
479 if (Logger::enabled()) | |
480 print_nested_frame_list(vd, irfunc->decl); | |
481 | |
482 // resolve frame ptr | |
483 FuncDeclaration* func = vd->toParent2()->isFuncDeclaration(); | |
484 assert(func); | |
485 LLValue* ptr = DtoNestedContext(func); | |
486 assert(ptr && "nested var, but no context"); | |
487 | |
488 // if there is no nestedVar the context itself is what we're after | |
489 if (!func->ir.irFunc->nestedVar) | |
490 { | |
491 return ptr; | |
492 } | |
493 | |
494 // handle a "normal" nested variable | |
495 | |
496 // we must cast here to be sure. nested classes just have a void* | |
497 ptr = DtoBitCast(ptr, func->ir.irFunc->nestedVar->getType()); | |
498 | |
499 // index nested var and load (if necessary) | |
500 LLValue* v = DtoGEPi(ptr, 0, vd->ir.irLocal->nestedIndex, "tmp"); | |
501 // references must be loaded, for normal variables this IS already the variable storage!!! | |
502 if (vd->isParameter() && (vd->isRef() || vd->isOut() || DtoIsPassedByRef(vd->type))) | 475 if (vd->isParameter() && (vd->isRef() || vd->isOut() || DtoIsPassedByRef(vd->type))) |
503 v = DtoLoad(v); | 476 val = DtoLoad(val); |
504 | 477 |
505 // log and return | 478 Logger::cout() << "value: " << *val << '\n'; |
506 Logger::cout() << "Nested var ptr = " << *v << '\n'; | 479 |
507 return v; | 480 return new DVarValue(astype, vd, val, true); |
508 } | 481 } |
509 | 482 |
510 /****************************************************************************************/ | 483 /****************************************************************************************/ |
511 /*//////////////////////////////////////////////////////////////////////////////////////// | 484 /*//////////////////////////////////////////////////////////////////////////////////////// |
512 // ASSIGNMENT HELPER (store this in that) | 485 // ASSIGNMENT HELPER (store this in that) |
574 DtoAggrCopy(l, r); | 547 DtoAggrCopy(l, r); |
575 } | 548 } |
576 } | 549 } |
577 else if (t->ty == Tclass) { | 550 else if (t->ty == Tclass) { |
578 assert(t2->ty == Tclass); | 551 assert(t2->ty == Tclass); |
579 // assignment to this in constructor special case | 552 LLValue* l = lhs->getLVal(); |
580 if (lhs->isThis()) { | 553 LLValue* r = rhs->getRVal(); |
581 LLValue* tmp = rhs->getRVal(); | 554 Logger::cout() << "l : " << *l << '\n'; |
582 FuncDeclaration* fdecl = gIR->func()->decl; | 555 Logger::cout() << "r : " << *r << '\n'; |
583 // respecify the this param | 556 r = DtoBitCast(r, l->getType()->getContainedType(0)); |
584 if (!llvm::isa<llvm::AllocaInst>(fdecl->ir.irFunc->thisVar)) | 557 DtoStore(r, l); |
585 fdecl->ir.irFunc->thisVar = new llvm::AllocaInst(tmp->getType(), "newthis", gIR->topallocapoint()); | |
586 DtoStore(tmp, fdecl->ir.irFunc->thisVar); | |
587 } | |
588 // regular class ref -> class ref assignment | |
589 else { | |
590 DtoStore(rhs->getRVal(), lhs->getLVal()); | |
591 } | |
592 } | 558 } |
593 else if (t->iscomplex()) { | 559 else if (t->iscomplex()) { |
594 assert(!lhs->isComplex()); | 560 assert(!lhs->isComplex()); |
595 | 561 |
596 LLValue* dst; | 562 LLValue* dst; |
1538 } | 1504 } |
1539 // pointer/class | 1505 // pointer/class |
1540 else if (ty == Tpointer || ty == Tclass) { | 1506 else if (ty == Tpointer || ty == Tclass) { |
1541 LLValue* val = dval->getRVal(); | 1507 LLValue* val = dval->getRVal(); |
1542 LLValue* zero = LLConstant::getNullValue(val->getType()); | 1508 LLValue* zero = LLConstant::getNullValue(val->getType()); |
1509 Logger::cout() << "val: " << *val << '\n'; | |
1510 Logger::cout() << "zero: " << *zero << '\n'; | |
1543 return gIR->ir->CreateICmpNE(val, zero, "tmp"); | 1511 return gIR->ir->CreateICmpNE(val, zero, "tmp"); |
1544 } | 1512 } |
1545 // dynamic array | 1513 // dynamic array |
1546 else if (ty == Tarray) | 1514 else if (ty == Tarray) |
1547 { | 1515 { |