changeset 1223:5f340a6dc749

Fix nested functions. My last patch was a little over-zealous in passing `undef`, it always passed `undef` to inner functions expecting a single context frame.
author Frits van Bommel <fvbommel wxs.nl>
date Fri, 17 Apr 2009 13:50:01 +0200
parents b6370749ec8d
children 919fafcc505c 6ef97d65ca60
files gen/nested.cpp ir/irfunction.cpp ir/irfunction.h
diffstat 3 files changed, 40 insertions(+), 33 deletions(-) [+]
line wrap: on
line diff
--- a/gen/nested.cpp	Fri Apr 17 03:47:56 2009 +0200
+++ b/gen/nested.cpp	Fri Apr 17 13:50:01 2009 +0200
@@ -5,6 +5,7 @@
 #include "gen/llvmhelpers.h"
 #include "gen/logger.h"
 #include "gen/tollvm.h"
+#include "gen/functions.h"
 
 #include "llvm/Support/CommandLine.h"
 namespace cl = llvm::cl;
@@ -237,39 +238,43 @@
         return llvm::UndefValue::get(getVoidPtrType());
     }
     if (nestedCtx == NCHybrid) {
-        // If sym is a nested function, and it's parent context is different than the
-        // one we got, adjust it.
-        
-        if (FuncDeclaration* fd = getParentFunc(sym->isFuncDeclaration(), true)) {
+        if (FuncDeclaration* symfd = sym->isFuncDeclaration()) {
+            // Make sure we've had a chance to analyze nested context usage
+            DtoDefineFunction(symfd);
+            
             // if this is for a function that doesn't access variables from
             // enclosing scopes, it doesn't matter what we pass.
             // Tell LLVM about it by passing an 'undef'.
-            if (fd->ir.irFunc->depth == 0)
+            if (symfd && symfd->ir.irFunc->depth == -1)
                 return llvm::UndefValue::get(getVoidPtrType());
             
-            Logger::println("For nested function, parent is %s", fd->toChars());
-            FuncDeclaration* ctxfd = irfunc->decl;
-            Logger::println("Current function is %s", ctxfd->toChars());
-            if (fromParent) {
-                ctxfd = getParentFunc(ctxfd, true);
-                assert(ctxfd && "Context from outer function, but no outer function?");
-            }
-            Logger::println("Context is from %s", ctxfd->toChars());
-            
-            unsigned neededDepth = fd->ir.irFunc->depth;
-            unsigned ctxDepth = ctxfd->ir.irFunc->depth;
-            
-            Logger::cout() << "Needed depth: " << neededDepth << '\n';
-            Logger::cout() << "Context depth: " << ctxDepth << '\n';
-            
-            if (neededDepth >= ctxDepth) {
-                assert(neededDepth <= ctxDepth + 1 && "How are we going more than one nesting level up?");
-                // fd needs the same context as we do, so all is well
-                Logger::println("Calling sibling function or directly nested function");
-            } else {
-                val = DtoBitCast(val, LLPointerType::getUnqual(ctxfd->ir.irFunc->frameType));
-                val = DtoGEPi(val, 0, neededDepth);
-                val = DtoAlignedLoad(val, (std::string(".frame.") + fd->toChars()).c_str());
+            // If sym is a nested function, and it's parent context is different than the
+            // one we got, adjust it.
+            if (FuncDeclaration* fd = getParentFunc(symfd, true)) {
+                Logger::println("For nested function, parent is %s", fd->toChars());
+                FuncDeclaration* ctxfd = irfunc->decl;
+                Logger::println("Current function is %s", ctxfd->toChars());
+                if (fromParent) {
+                    ctxfd = getParentFunc(ctxfd, true);
+                    assert(ctxfd && "Context from outer function, but no outer function?");
+                }
+                Logger::println("Context is from %s", ctxfd->toChars());
+                
+                unsigned neededDepth = fd->ir.irFunc->depth;
+                unsigned ctxDepth = ctxfd->ir.irFunc->depth;
+                
+                Logger::cout() << "Needed depth: " << neededDepth << '\n';
+                Logger::cout() << "Context depth: " << ctxDepth << '\n';
+                
+                if (neededDepth >= ctxDepth) {
+                    assert(neededDepth <= ctxDepth + 1 && "How are we going more than one nesting level up?");
+                    // fd needs the same context as we do, so all is well
+                    Logger::println("Calling sibling function or directly nested function");
+                } else {
+                    val = DtoBitCast(val, LLPointerType::getUnqual(ctxfd->ir.irFunc->frameType));
+                    val = DtoGEPi(val, 0, neededDepth);
+                    val = DtoAlignedLoad(val, (std::string(".frame.") + fd->toChars()).c_str());
+                }
             }
         }
     }
@@ -376,15 +381,15 @@
             // start with adding all enclosing parent frames until a static parent is reached
             
             const LLStructType* innerFrameType = NULL;
-            unsigned depth = 0;
+            unsigned depth = -1;
             if (!fd->isStatic()) {
                 if (FuncDeclaration* parfd = getParentFunc(fd, true)) {
                     innerFrameType = parfd->ir.irFunc->frameType;
                     if (innerFrameType)
-                        depth = parfd->ir.irFunc->depth + 1;
+                        depth = parfd->ir.irFunc->depth;
                 }
             }
-            fd->ir.irFunc->depth = depth;
+            fd->ir.irFunc->depth = ++depth;
             
             Logger::cout() << "Function " << fd->toChars() << " has depth " << depth << '\n';
             
--- a/ir/irfunction.cpp	Fri Apr 17 03:47:56 2009 +0200
+++ b/ir/irfunction.cpp	Fri Apr 17 13:50:01 2009 +0200
@@ -112,7 +112,7 @@
 
     nestedVar = NULL;
     frameType = NULL;
-    depth = 0;
+    depth = -1;
     
     _arguments = NULL;
     _argptr = NULL;
--- a/ir/irfunction.h	Fri Apr 17 03:47:56 2009 +0200
+++ b/ir/irfunction.h	Fri Apr 17 13:50:01 2009 +0200
@@ -46,7 +46,9 @@
     
     llvm::Value* nestedVar; // nested var alloca
     const llvm::StructType* frameType; // type of nested context (not for -nested-ctx=array)
-    unsigned depth; // number of enclosing functions with variables accessed by nested functions
+    // number of enclosing functions with variables accessed by nested functions
+    // (-1 if neither this function nor any enclosing ones access variables from enclosing functions)
+    int depth;
     
     llvm::Value* _arguments;
     llvm::Value* _argptr;