Patches to make the LLVM sources more -pedantic clean. Patch provided
[oota-llvm.git] / lib / Analysis / DataStructure / DataStructure.cpp
index 904d8b10b769c53fcbea35d79376de8776d1c99b..4e326545cc5cc588a25270f6b4ccb6ae8e73a0a5 100644 (file)
@@ -26,6 +26,7 @@
 #include "llvm/ADT/SCCIterator.h"
 #include "llvm/ADT/Statistic.h"
 #include "llvm/Support/Timer.h"
+#include <iostream>
 #include <algorithm>
 using namespace llvm;
 
@@ -38,7 +39,11 @@ namespace {
   Statistic<> NumDNE            ("dsa", "Number of nodes removed by reachability");
   Statistic<> NumTrivialDNE     ("dsa", "Number of nodes trivially removed");
   Statistic<> NumTrivialGlobalDNE("dsa", "Number of globals trivially removed");
-};
+  static cl::opt<unsigned>
+  DSAFieldLimit("dsa-field-limit", cl::Hidden,
+                cl::desc("Number of fields to track before collapsing a node"),
+                cl::init(256));
+}
 
 #if 0
 #define TIME_REGION(VARNAME, DESC) \
@@ -467,7 +472,7 @@ bool DSNode::mergeTypeInfo(const Type *NewTy, unsigned Offset,
     // collapse it.  This can occur for fortran common blocks, which have stupid
     // things like { [100000000 x double], [1000000 x double] }.
     unsigned NumFields = (NewTySize+DS::PointerSize-1) >> DS::PointerShift;
-    if (NumFields > 256) {
+    if (NumFields > DSAFieldLimit) {
       foldNodeCompletely();
       return true;
     }
@@ -491,13 +496,75 @@ bool DSNode::mergeTypeInfo(const Type *NewTy, unsigned Offset,
       return true;
     }
 
-    if (Offset) {  // We could handle this case, but we don't for now...
+    // If this node would have to have an unreasonable number of fields, just
+    // collapse it.  This can occur for fortran common blocks, which have stupid
+    // things like { [100000000 x double], [1000000 x double] }.
+    unsigned NumFields = (NewTySize+Offset+DS::PointerSize-1) >> DS::PointerShift;
+    if (NumFields > DSAFieldLimit) {
+      foldNodeCompletely();
+      return true;
+    }
+
+    if (Offset) {
+      //handle some common cases:
+      // Ty:    struct { t1, t2, t3, t4, ..., tn}
+      // NewTy: struct { offset, stuff...}
+      // try merge with NewTy: struct {t1, t2, stuff...} if offset lands exactly on a field in Ty
+      if (isa<StructType>(NewTy) && isa<StructType>(Ty)) {
+        DEBUG(std::cerr << "Ty: " << *Ty << "\nNewTy: " << *NewTy << "@" << Offset << "\n");
+        unsigned O = 0;
+        const StructType *STy = cast<StructType>(Ty);
+        const StructLayout &SL = *TD.getStructLayout(STy);
+        unsigned i = SL.getElementContainingOffset(Offset);
+        //Either we hit it exactly or give up
+        if (SL.MemberOffsets[i] != Offset) {
+          if (FoldIfIncompatible) foldNodeCompletely();
+          return true;
+        }
+        std::vector<const Type*> nt;
+        for (unsigned x = 0; x < i; ++x)
+          nt.push_back(STy->getElementType(x));
+        STy = cast<StructType>(NewTy);
+        nt.insert(nt.end(), STy->element_begin(), STy->element_end());
+        //and merge
+        STy = StructType::get(nt);
+        DEBUG(std::cerr << "Trying with: " << *STy << "\n");
+        return mergeTypeInfo(STy, 0);
+      }
+
+      //Ty: struct { t1, t2, t3 ... tn}
+      //NewTy T offset x
+      //try merge with NewTy: struct : {t1, t2, T} if offset lands on a field in Ty
+      if (isa<StructType>(Ty)) {
+        DEBUG(std::cerr << "Ty: " << *Ty << "\nNewTy: " << *NewTy << "@" << Offset << "\n");
+        unsigned O = 0;
+        const StructType *STy = cast<StructType>(Ty);
+        const StructLayout &SL = *TD.getStructLayout(STy);
+        unsigned i = SL.getElementContainingOffset(Offset);
+        //Either we hit it exactly or give up
+        if (SL.MemberOffsets[i] != Offset) {
+          if (FoldIfIncompatible) foldNodeCompletely();
+          return true;
+        }
+        std::vector<const Type*> nt;
+        for (unsigned x = 0; x < i; ++x)
+          nt.push_back(STy->getElementType(x));
+        nt.push_back(NewTy);
+        //and merge
+        STy = StructType::get(nt);
+        DEBUG(std::cerr << "Trying with: " << *STy << "\n");
+        return mergeTypeInfo(STy, 0);
+      }
+
       std::cerr << "UNIMP: Trying to merge a growth type into "
                 << "offset != 0: Collapsing!\n";
+      abort();
       if (FoldIfIncompatible) foldNodeCompletely();
       return true;
+
     }
 
+
     // Okay, the situation is nice and simple, we are trying to merge a type in
     // at offset 0 that is bigger than our current type.  Implement this by
     // switching to the new type and then merge in the smaller one, which should
@@ -505,15 +572,6 @@ bool DSNode::mergeTypeInfo(const Type *NewTy, unsigned Offset,
     // ok, it will collapse the node as appropriate.
     //
 
-    // If this node would have to have an unreasonable number of fields, just
-    // collapse it.  This can occur for fortran common blocks, which have stupid
-    // things like { [100000000 x double], [1000000 x double] }.
-    unsigned NumFields = (NewTySize+DS::PointerSize-1) >> DS::PointerShift;
-    if (NumFields > 256) {
-      foldNodeCompletely();
-      return true;
-    }
-
     const Type *OldTy = Ty;
     Ty = NewTy;
     NodeType &= ~Array;
@@ -667,6 +725,9 @@ bool DSNode::mergeTypeInfo(const Type *NewTy, unsigned Offset,
 void DSNode::addEdgeTo(unsigned Offset, const DSNodeHandle &NH) {
   if (NH.isNull()) return;       // Nothing to do
 
+  if (isNodeCompletelyFolded())
+    Offset = 0;
+
   DSNodeHandle &ExistingEdge = getLink(Offset);
   if (!ExistingEdge.isNull()) {
     // Merge the two nodes...