[vmkit-commits] [vmkit] r69039 - /vmkit/trunk/lib/Mvm/Compiler/EscapeAnalysis.cpp

Nicolas Geoffray nicolas.geoffray at lip6.fr
Tue Apr 14 05:23:42 PDT 2009


Author: geoffray
Date: Tue Apr 14 07:23:39 2009
New Revision: 69039

URL: http://llvm.org/viewvc/llvm-project?rev=69039&view=rev
Log:
Improve escape analysis pass with NoCapture and loop handling.


Modified:
    vmkit/trunk/lib/Mvm/Compiler/EscapeAnalysis.cpp

Modified: vmkit/trunk/lib/Mvm/Compiler/EscapeAnalysis.cpp
URL: http://llvm.org/viewvc/llvm-project/vmkit/trunk/lib/Mvm/Compiler/EscapeAnalysis.cpp?rev=69039&r1=69038&r2=69039&view=diff

==============================================================================
--- vmkit/trunk/lib/Mvm/Compiler/EscapeAnalysis.cpp (original)
+++ vmkit/trunk/lib/Mvm/Compiler/EscapeAnalysis.cpp Tue Apr 14 07:23:39 2009
@@ -1,6 +1,6 @@
 //===------EscapeAnalysis.cpp - Simple LLVM escape analysis ---------------===//
 //
-//                     The Micro Virtual Machine
+//                     The VMKit project
 //
 // This file is distributed under the University of Illinois Open Source 
 // License. See LICENSE.TXT for details.
@@ -15,6 +15,7 @@
 #include "llvm/Pass.h"
 #include "llvm/Instructions.h"
 #include "llvm/Analysis/LoopInfo.h"
+#include "llvm/Support/CallSite.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/Debug.h"
 
@@ -42,7 +43,7 @@
     virtual bool runOnFunction(Function &F);
 
   private:
-    bool processMalloc(Instruction* I, Value* Size, Value* VT);
+    bool processMalloc(Instruction* I, Value* Size, Value* VT, Loop* CurLoop);
   };
 
   char EscapeAnalysis::ID = 0;
@@ -58,22 +59,47 @@
   for (Function::iterator BI = F.begin(), BE = F.end(); BI != BE; BI++) { 
     BasicBlock *Cur = BI;
    
-    // Don't bother if we're in a loop. We rely on the memory manager to
-    // allocate with a bump pointer allocator. Sure we could analyze more
-    // to see if the object could in fact be stack allocated, but just be
-    // lazy for now.
-    if (LI->getLoopFor(Cur)) continue;
+    // Get the parent loop if there is one. If the allocation happens in a loop
+    // we must make sure that the allocated value is not used outside of
+    // the loop. If the allocation does not escape and it is only used inside
+    // the loop, we will hoist the allocation in the pre-header of the loop.
+    Loop* CurLoop = LI->getLoopFor(Cur);
+    if (CurLoop) {
+      Loop* NextLoop = CurLoop->getParentLoop();
+      while (NextLoop) {
+        CurLoop = NextLoop;
+        NextLoop = CurLoop->getParentLoop();
+      }
+    }
 
     for (BasicBlock::iterator II = Cur->begin(), IE = Cur->end(); II != IE;) {
       Instruction *I = II;
       II++;
-      if (CallInst *CI = dyn_cast<CallInst>(I)) {
-        if (CI->getOperand(0) == Allocator) {
-          Changed |= processMalloc(CI, CI->getOperand(1), CI->getOperand(2));
-        }
-      } else if (InvokeInst *CI = dyn_cast<InvokeInst>(I)) {
-        if (CI->getOperand(0) == Allocator) {
-          Changed |= processMalloc(CI, CI->getOperand(3), CI->getOperand(4));
+      CallSite Call = CallSite::get(I);
+      if (Call.getInstruction() && Call.getCalledValue() == Allocator) {
+
+        if (CurLoop) {
+          bool escapesLoop = false;
+          for (Value::use_iterator U = I->use_begin(), E = I->use_end();
+               U != E; ++U) {
+            if (Instruction* II = dyn_cast<Instruction>(U)) {
+              BasicBlock* BBU = II->getParent();
+              if (!CurLoop->contains(BBU)) {
+                escapesLoop = true;
+                break;
+              }
+            }
+          }
+
+          if (escapesLoop) continue;
+        }
+
+        if (CallInst *CI = dyn_cast<CallInst>(I)) {
+          Changed |= processMalloc(CI, CI->getOperand(1), CI->getOperand(2),
+                                   CurLoop);
+        } else if (InvokeInst *CI = dyn_cast<InvokeInst>(I)) {
+          Changed |= processMalloc(CI, CI->getOperand(3), CI->getOperand(4),
+                                   CurLoop);
         }
       }
     }
@@ -88,16 +114,22 @@
   for (Value::use_iterator I = Ins->use_begin(), E = Ins->use_end(); 
        I != E; ++I) {
     if (Instruction* II = dyn_cast<Instruction>(I)) {
-      if (CallInst* CI = dyn_cast<CallInst>(II)) {
-        if (!CI->onlyReadsMemory()) return true;
-      }
-      else if (InvokeInst* CI = dyn_cast<InvokeInst>(II)) {
-        if (!CI->onlyReadsMemory()) return true;
-      }
-      else if (dyn_cast<BitCastInst>(II)) {
+      if (II->getOpcode() == Instruction::Call || 
+          II->getOpcode() == Instruction::Invoke) {
+        
+        CallSite CS = CallSite::get(II);
+        if (!CS.onlyReadsMemory()) return true;
+        
+        CallSite::arg_iterator B = CS.arg_begin(), E = CS.arg_end();
+        for (CallSite::arg_iterator A = B; A != E; ++A) {
+          if (A->get() == Ins && 
+              !CS.paramHasAttr(A - B + 1, Attribute::NoCapture)) {
+            return true;
+          }
+        }
+      } else if (dyn_cast<BitCastInst>(II)) {
         if (escapes(II, visited)) return true;
-      }
-      else if (StoreInst* SI = dyn_cast<StoreInst>(II)) {
+      } else if (StoreInst* SI = dyn_cast<StoreInst>(II)) {
         if (AllocaInst * AI = dyn_cast<AllocaInst>(SI->getOperand(1))) {
           if (!visited[AI]) {
             visited[AI] = true;
@@ -106,17 +138,15 @@
         } else if (SI->getOperand(0) == Ins) {
           return true;
         }
-      }
-      else if (dyn_cast<LoadInst>(II)) {
+      } else if (dyn_cast<LoadInst>(II)) {
         if (isa<PointerType>(II->getType())) {
           if (escapes(II, visited)) return true; // allocas
         }
-      }
-      else if (dyn_cast<GetElementPtrInst>(II)) {
+      } else if (dyn_cast<GetElementPtrInst>(II)) {
         if (escapes(II, visited)) return true;
-      }
-      else if (dyn_cast<ReturnInst>(II)) return true;
-      else if (dyn_cast<PHINode>(II)) {
+      } else if (dyn_cast<ReturnInst>(II)) {
+        return true;
+      } else if (dyn_cast<PHINode>(II)) {
         if (!visited[II]) {
           visited[II] = true;
           if (escapes(II, visited)) return true;
@@ -129,7 +159,8 @@
   return false;
 }
 
-bool EscapeAnalysis::processMalloc(Instruction* I, Value* Size, Value* VT) {
+bool EscapeAnalysis::processMalloc(Instruction* I, Value* Size, Value* VT,
+                                   Loop* CurLoop) {
   Instruction* Alloc = I;
   
   ConstantInt* CI = dyn_cast<ConstantInt>(Size);
@@ -154,6 +185,14 @@
   } else {
     return false;
   }
+
+  // The object does not have a finalizer and is never used. Remove the
+  // allocation as it will not have side effects.
+  if (!hasFinalizer && !Alloc->getNumUses()) {
+    DOUT << "Escape analysis removes instruction " << *Alloc << ": ";
+    Alloc->eraseFromParent();
+    return true;
+  }
   
   uint64_t NSize = CI->getZExtValue();
   // If the class has a finalize method, do not stack allocate the object.
@@ -161,6 +200,19 @@
     std::map<Instruction*, bool> visited;
     bool esc = escapes(Alloc, visited);
     if (!esc) {
+
+      if (CurLoop) {
+        // The object does not escape and is only used in the loop where it
+        // is allocated. We hoist the allocation in the pre-header so that
+        // we don't end up with tons of allocations on the stack.
+        BasicBlock* BB = CurLoop->getLoopPreheader();
+        assert(BB && "No Preheader!");
+        DOUT << "Escape analysis hoisting to " << BB->getName() << ": ";
+        DOUT << *Alloc;
+        Alloc->removeFromParent();
+        BB->getInstList().insert(BB->getTerminator(), Alloc);
+      }
+
       AllocaInst* AI = new AllocaInst(Type::Int8Ty, Size, "", Alloc);
       BitCastInst* BI = new BitCastInst(AI, Alloc->getType(), "", Alloc);
       DOUT << "escape" << Alloc->getParent()->getParent()->getName() << "\n";





More information about the vmkit-commits mailing list