Added code to the TopDown pass to signal to SAFECode/SVA that a pointer needs
a run-time check because values from the same kernel pool (kmem_cache_t in
Linux) return values of different types.
Added code to handle the llva_do_index instruction.

llvm-svn: 86991
diff --git a/poolalloc/include/dsa/DSNode.h b/poolalloc/include/dsa/DSNode.h
index 4dfd75a..8487d9c 100644
--- a/poolalloc/include/dsa/DSNode.h
+++ b/poolalloc/include/dsa/DSNode.h
@@ -159,8 +159,9 @@
     Array       = 1 << 7,   // This node is treated like an array
     External    = 1 << 8,   // This node comes from an external source
     IONode      = 1 << 9,   // This node comes from an external source
+    CheckAnyway = 1 << 10,  // This node may be type-safe but check it anyway
     //#ifndef NDEBUG
-    DEAD        = 1 << 10,   // This node is dead and should not be pointed to
+    DEAD        = 1 << 11,   // This node is dead and should not be pointed to
     //#endif
 
     Composition = AllocaNode | HeapNode | GlobalNode | IONode | UnknownNode
@@ -421,11 +422,13 @@
   bool isDeadNode() const   { return NodeType & DEAD; }
   bool isExternalNode() const { return NodeType & External; }
   bool isIONode() const       { return NodeType & IONode; }
+  bool isCheckAnyway() const  { return NodeType & CheckAnyway; }
 
   DSNode *setAllocaNodeMarker()  { NodeType |= AllocaNode;  return this; }
   DSNode *setHeapNodeMarker()    { NodeType |= HeapNode;    return this; }
   DSNode *setGlobalNodeMarker()  { NodeType |= GlobalNode;  return this; }
   DSNode *setIONodeMarker()      { NodeType |= IONode;      return this; }
+  DSNode *setCheckAnywayNodeMarker()  { NodeType |= CheckAnyway; return this; }
   DSNode *setUnknownNodeMarker(); // { ++stat_unknown; NodeType |= UnknownNode; return this; }
 
   DSNode *setExternalMarker()   { NodeType |= External;   return this; }
diff --git a/poolalloc/lib/DSA/Local.cpp b/poolalloc/lib/DSA/Local.cpp
index e823716..85cd2dc 100644
--- a/poolalloc/lib/DSA/Local.cpp
+++ b/poolalloc/lib/DSA/Local.cpp
@@ -312,6 +312,16 @@
         } else {
           goto fail;
         }
+#ifdef LLVA_KERNEL
+      } else if (CallInst * CI = dyn_cast<CallInst>(V)) {
+        Function * F = CI->getCalledFunction();
+        if (!F) goto fail;
+        if ((F->hasName()) && (F->getName() == "llva_do_index")) {
+          tocheck.push(CI->getOperand(1));
+        } else {
+          goto fail;
+        }
+#endif
       } else {
         goto fail;
       }
diff --git a/poolalloc/lib/DSA/TopDownClosure.cpp b/poolalloc/lib/DSA/TopDownClosure.cpp
index 9098adb..61f11d6 100644
--- a/poolalloc/lib/DSA/TopDownClosure.cpp
+++ b/poolalloc/lib/DSA/TopDownClosure.cpp
@@ -163,6 +163,68 @@
   // same MetaPool.
   //
   Function* KMA = M.getNamedFunction("kmem_cache_alloc");
+#if 1
+  if (KMA) {
+    // Map from kmem_cache_t's metapool to the type of values returned from the
+    // kmem_cache_t
+    std::map<MetaPool*, DSNodeHandle> types;
+
+    for (Value::use_iterator ii = KMA->use_begin(), ee = KMA->use_end();
+         ii != ee; ++ii) {
+      CallInst* CI = dyn_cast<CallInst>(*ii);
+      if ((CI) && (CI->getCalledFunction() == KMA)) {
+        // Function in which the call statement resides
+        Function * F = CI->getParent()->getParent();
+
+        // The pointer to the kmem_cache_t
+        Value* CacheT = CI->getOperand(1);
+
+        //
+        // Get the metapool for the kmem_cache_t
+        //
+        DSNodeHandle DSCacheT = DSInfo[F]->getNodeForValue(CacheT);
+        MetaPoolHandle MPCacheT (DSCacheT.getNode()->getMP());
+
+        //
+        // Get the DSNode handle of the object being allocated.
+        //
+        DSNodeHandle DSH = DSInfo[F]->getNodeForValue(CI);
+        MetaPoolHandle MPNode (DSH.getNode()->getMP());
+
+        //
+        // Ensure that all objects allocated from this kmem_cache_t have the
+        // same type.
+        //
+        if (types[MPCacheT.getPool()].getNode()) {
+          //
+          // Get the type of the objects allocated from this kernel pool.
+          //
+          const Type * MPType = types[MPCacheT.getPool()].getNode()->getType();
+          const Type * OJType = DSH.getNode()->getType();
+
+          //
+          // If this allocation site does not allocate objects of the same
+          // type, then make both DSNodes type-unknown.
+          //
+          if (MPType != DSH.getNode()->getType()) {
+              DSH.getNode()->setCheckAnywayNodeMarker();
+              types[MPCacheT.getPool()].getNode()->setCheckAnywayNodeMarker();
+            std::cerr << "kmem_cache_alloc: 2: Folded!" << std::endl;
+          }
+        } else {
+          //
+          // Now DSNode has been associated with objects allocated from this
+          // kernel pool.  Record the first one that we have found.
+          //
+          std::cerr << "kmem_cache_alloc: Adding!" << std::endl;
+          types[MPCacheT.getPool()] = DSH;
+        }
+      }
+    }
+  }
+#endif
+
+#if 1
   if (KMA) {
     // Map from kmem_cache_t's metapool to the metapool of its return value
     std::map<MetaPool*, MetaPool*> locs;
@@ -203,6 +265,7 @@
     }
   }
 #endif
+#endif
      
   return false;
 }