diff 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
line wrap: on
line diff
--- a/gen/llvmhelpers.cpp	Sun Aug 03 16:59:28 2008 +0200
+++ b/gen/llvmhelpers.cpp	Mon Aug 04 02:59:34 2008 +0200
@@ -330,181 +330,154 @@
 // NESTED VARIABLE HELPERS
 ////////////////////////////////////////////////////////////////////////////////////////*/
 
-static const LLType* get_next_frame_ptr_type(Dsymbol* sc)
+/*
+
+got:
+
+    context pointer of 'this' function
+
+    declaration for target context's function
+
+want:
+
+    context pointer of target function in call chain
+
+*/
+
+static LLValue* dive_into_nested(Dsymbol* from, LLValue* val)
 {
-    assert(sc->isFuncDeclaration() || sc->isClassDeclaration());
-    Dsymbol* p = sc->toParent2();
-    if (!p->isFuncDeclaration() && !p->isClassDeclaration())
-        Logger::println("unexpected parent symbol found while resolving frame pointer - '%s' kind: '%s'", p->toChars(), p->kind());
-    assert(p->isFuncDeclaration() || p->isClassDeclaration());
-    if (FuncDeclaration* fd = p->isFuncDeclaration())
+    from = from->toParent2();
+
+    // parent is a function
+    if (FuncDeclaration* f = from->isFuncDeclaration())
     {
-        LLValue* v = fd->ir.irFunc->nestedVar;
-        assert(v);
-        return v->getType();
+        IrFunction* irfunc = f->ir.irFunc;
+        // parent has nested var struct
+        if (irfunc->nestedVar)
+        {
+            return DtoBitCast(val, irfunc->nestedVar->getType());
+        }
+        // parent has this argument
+        else if (irfunc->thisVar)
+        {
+            return DtoBitCast(val, irfunc->thisVar->getType()->getContainedType(0));
+        }
+        // none of the above, means no context is required, dummy.
+        else
+        {
+            return getNullPtr(getVoidPtrType());
+        }
     }
-    else if (ClassDeclaration* cd = p->isClassDeclaration())
+    // parent is a class
+    else if (ClassDeclaration* c = from->isClassDeclaration())
     {
-        return DtoType(cd->type);
+        return DtoBitCast(DtoLoad(val), DtoType(c->type));
     }
+    // parent is not valid
     else
     {
-        Logger::println("symbol: '%s' kind: '%s'", sc->toChars(), sc->kind());
-        assert(0);
-    }
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-
-static LLValue* get_frame_ptr_impl(FuncDeclaration* func, Dsymbol* sc, LLValue* v)
-{
-    LOG_SCOPE;
-    if (sc == func)
-    {
-        return v;
-    }
-    else if (FuncDeclaration* fd = sc->isFuncDeclaration())
-    {
-        Logger::println("scope is function: %s", fd->toChars());
-
-        if (fd->toParent2() == func)
-        {
-            if (!func->ir.irFunc->nestedVar)
-                return NULL;
-            return DtoBitCast(v, func->ir.irFunc->nestedVar->getType());
-        }
-
-        v = DtoBitCast(v, get_next_frame_ptr_type(fd));
-        Logger::cout() << "v = " << *v << '\n';
-
-        if (fd->toParent2()->isFuncDeclaration())
-        {
-            v = DtoGEPi(v, 0,0, "tmp");
-            v = DtoLoad(v);
-        }
-        else if (ClassDeclaration* cd = fd->toParent2()->isClassDeclaration())
-        {
-            v = DtoGEPi(v,0,2+cd->vthis->ir.irField->index,"tmp");
-            v = DtoLoad(v);
-        }
-        else
-        {
-            assert(0);
-        }
-        return get_frame_ptr_impl(func, fd->toParent2(), v);
-    }
-    else if (ClassDeclaration* cd = sc->isClassDeclaration())
-    {
-        Logger::println("scope is class: %s", cd->toChars());
-        return get_frame_ptr_impl(func, cd->toParent2(), v);
-    }
-    else
-    {
-        Logger::println("symbol: '%s'", sc->toPrettyChars());
-        assert(0);
+        assert(0 && "!(class|function)");
     }
 }
 
-//////////////////////////////////////////////////////////////////////////////////////////
-
-static LLValue* get_frame_ptr(FuncDeclaration* func)
-{
-    Logger::println("Resolving context pointer for nested function: '%s'", func->toPrettyChars());
-    LOG_SCOPE;
-    IrFunction* irfunc = gIR->func();
-
-    // in the right scope already
-    if (func == irfunc->decl)
-        return irfunc->decl->ir.irFunc->nestedVar;
-
-    // use the 'this' pointer
-    LLValue* ptr = irfunc->decl->ir.irFunc->thisVar;
-    assert(ptr);
-
-    // return the fully resolved frame pointer
-    ptr = get_frame_ptr_impl(func, irfunc->decl, ptr);
-    if (ptr) Logger::cout() << "Found context!" << *ptr;
-    else Logger::cout() << "NULL context!\n";
-
-    return ptr;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-
 LLValue* DtoNestedContext(FuncDeclaration* func)
 {
-    // resolve frame ptr
-    LLValue* ptr = get_frame_ptr(func);
-    Logger::cout() << "Nested context ptr = ";
-    if (ptr) Logger::cout() << *ptr;
-    else Logger::cout() << "NULL";
-    Logger::cout() << '\n';
-    return ptr;
-}
+    Logger::println("listing context frame list for funcdecl '%s'", func->toPrettyChars());
+    LOG_SCOPE;
+
+    int level = 0;
 
-//////////////////////////////////////////////////////////////////////////////////////////
+    IrFunction* irfunc = gIR->func();
+    Dsymbol* current = irfunc->decl;
 
-static void print_frame_worker(VarDeclaration* vd, Dsymbol* par)
-{
-    if (vd->toParent2() == par)
+    // this context ?
+    if (current == func)
     {
-        Logger::println("found: '%s' kind: '%s'", par->toChars(), par->kind());
-        return;
+        return irfunc->nestedVar;
     }
 
-    Logger::println("diving into: '%s' kind: '%s'", par->toChars(), par->kind());
-    LOG_SCOPE;
-    print_frame_worker(vd, par->toParent2());
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
+    // otherwise use the context argument
+    LLValue* val = dive_into_nested(current, irfunc->thisVar);
+    current = current->toParent2();
+    assert(val);
 
-static void print_nested_frame_list(VarDeclaration* vd, Dsymbol* par)
-{
-    Logger::println("Frame pointer list for nested var: '%s'", vd->toPrettyChars());
-    LOG_SCOPE;
-    if (vd->toParent2() != par)
-        print_frame_worker(vd, par);
-    else
-        Logger::println("Found at level 0");
-    Logger::println("Done");
+    for (;;)
+    {
+        Logger::cout() << "context: " << *val << '\n';
+        Logger::println("(%d) looking in: %s (%s)", level, current->toPrettyChars(), current->kind());
+        if (FuncDeclaration* f = current->isFuncDeclaration())
+        {
+            if (f == func)
+            {
+                Logger::println("-> found <-");
+                Logger::cout() << "-> val: " << *val << '\n';
+                return val;
+            }
+            else
+            {
+                val = DtoLoad(DtoGEPi(val,0,0));
+            }
+        }
+        else if (ClassDeclaration* c = current->isClassDeclaration())
+        {
+            val = DtoLoad(DtoGEPi(val, 0, 2+c->vthis->ir.irField->index));
+            val = dive_into_nested(current, val);
+        }
+        else
+        {
+            Logger::cout() << "val: " << *val << '\n';
+            assert(0 && "!(class|function)");
+        }
+        current = current->toParent2();
+        ++level;
+    }
+
+    assert(0);
+    return val;
 }
 
-//////////////////////////////////////////////////////////////////////////////////////////
-
-LLValue* DtoNestedVariable(VarDeclaration* vd)
+DValue* DtoNestedVariable(Type* astype, VarDeclaration* vd)
 {
-    // log the frame list
     IrFunction* irfunc = gIR->func();
-    if (Logger::enabled())
-        print_nested_frame_list(vd, irfunc->decl);
+
+    // var parent (the scope we're looking for)
+    Dsymbol* varParent = vd->toParent2();
 
-    // resolve frame ptr
-    FuncDeclaration* func = vd->toParent2()->isFuncDeclaration();
-    assert(func);
-    LLValue* ptr = DtoNestedContext(func);
-    assert(ptr && "nested var, but no context");
-
-    // if there is no nestedVar the context itself is what we're after
-    if (!func->ir.irFunc->nestedVar)
+    // on level 0
+    if (varParent == irfunc->decl)
     {
-        return ptr;
+        LLValue* nest = irfunc->nestedVar;
+        LLValue* v = DtoGEPi(nest, 0, vd->ir.irLocal->nestedIndex, "tmp");
+        // references must be loaded to get the variable address
+        if (vd->isParameter() && (vd->isRef() || vd->isOut() || DtoIsPassedByRef(vd->type)))
+            v = DtoLoad(v);
+        return new DVarValue(astype, vd, v, true);
     }
 
-    // handle a "normal" nested variable
+    // on level n != 0
+    FuncDeclaration* varFunc = varParent->isFuncDeclaration();
+    assert(varFunc);
 
-    // we must cast here to be sure. nested classes just have a void*
-    ptr = DtoBitCast(ptr, func->ir.irFunc->nestedVar->getType());
+    // get context of variable
+    LLValue* ctx = DtoNestedContext(varFunc);
+
+    // if no local var, it's the context itself (class this)
+    if (!vd->ir.irLocal)
+        return new DImValue(astype, ctx);
 
-    // index nested var and load (if necessary)
-    LLValue* v = DtoGEPi(ptr, 0, vd->ir.irLocal->nestedIndex, "tmp");
-    // references must be loaded, for normal variables this IS already the variable storage!!!
+    // extract variable
+    IrLocal* local = vd->ir.irLocal;
+    assert(local);
+    assert(local->nestedIndex >= 0);
+    LLValue* val = DtoGEPi(ctx, 0, local->nestedIndex);
+
+    // references must be loaded to get the variable address
     if (vd->isParameter() && (vd->isRef() || vd->isOut() || DtoIsPassedByRef(vd->type)))
-        v = DtoLoad(v);
+        val = DtoLoad(val);
 
-    // log and return
-    Logger::cout() << "Nested var ptr = " << *v << '\n';
-    return v;
+    Logger::cout() << "value: " << *val << '\n';
+
+    return new DVarValue(astype, vd, val, true);
 }
 
 /****************************************************************************************/
@@ -576,19 +549,12 @@
     }
     else if (t->ty == Tclass) {
         assert(t2->ty == Tclass);
-        // assignment to this in constructor special case
-        if (lhs->isThis()) {
-            LLValue* tmp = rhs->getRVal();
-            FuncDeclaration* fdecl = gIR->func()->decl;
-            // respecify the this param
-            if (!llvm::isa<llvm::AllocaInst>(fdecl->ir.irFunc->thisVar))
-                fdecl->ir.irFunc->thisVar = new llvm::AllocaInst(tmp->getType(), "newthis", gIR->topallocapoint());
-            DtoStore(tmp, fdecl->ir.irFunc->thisVar);
-        }
-        // regular class ref -> class ref assignment
-        else {
-            DtoStore(rhs->getRVal(), lhs->getLVal());
-        }
+        LLValue* l = lhs->getLVal();
+        LLValue* r = rhs->getRVal();
+        Logger::cout() << "l : " << *l << '\n';
+        Logger::cout() << "r : " << *r << '\n';
+        r = DtoBitCast(r, l->getType()->getContainedType(0));
+        DtoStore(r, l);
     }
     else if (t->iscomplex()) {
         assert(!lhs->isComplex());
@@ -1540,6 +1506,8 @@
     else if (ty == Tpointer || ty == Tclass) {
         LLValue* val = dval->getRVal();
         LLValue* zero = LLConstant::getNullValue(val->getType());
+        Logger::cout() << "val:  " << *val << '\n';
+        Logger::cout() << "zero: " << *zero << '\n';
         return gIR->ir->CreateICmpNE(val, zero, "tmp");
     }
     // dynamic array