[llvm-commits] CVS: llvm-poolalloc/lib/Macroscopic/DeadFieldElimination.cpp Makefile README.txt StructureFieldVisitor.cpp StructureFieldVisitor.h

John Criswell criswell at cs.uiuc.edu
Wed May 18 12:56:41 PDT 2005



Changes in directory llvm-poolalloc/lib/Macroscopic:

DeadFieldElimination.cpp updated: 1.2 -> 1.3
Makefile updated: 1.2 -> 1.3
README.txt updated: 1.2 -> 1.3
StructureFieldVisitor.cpp updated: 1.4 -> 1.5
StructureFieldVisitor.h updated: 1.5 -> 1.6
---
Log message:

Bring all of these files back from the "release_15" merge.








---
Diffs of the changes:  (+1481 -0)

 DeadFieldElimination.cpp  |  248 ++++++++++++
 Makefile                  |   12 
 README.txt                |    5 
 StructureFieldVisitor.cpp |  939 ++++++++++++++++++++++++++++++++++++++++++++++
 StructureFieldVisitor.h   |  277 +++++++++++++
 5 files changed, 1481 insertions(+)


Index: llvm-poolalloc/lib/Macroscopic/DeadFieldElimination.cpp
diff -u /dev/null llvm-poolalloc/lib/Macroscopic/DeadFieldElimination.cpp:1.3
--- /dev/null	Wed May 18 14:56:37 2005
+++ llvm-poolalloc/lib/Macroscopic/DeadFieldElimination.cpp	Wed May 18 14:56:26 2005
@@ -0,0 +1,248 @@
+//===-- DeadFieldElimination.cpp - Dead Field Elimination Pass ------------===//
+// 
+//                     The LLVM Compiler Infrastructure
+//
+// This file was developed by the LLVM research group and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+// 
+//===----------------------------------------------------------------------===//
+//
+// This file implements the -rds-deadfieldelim pass, which implements
+// Macroscopic Dead Field Elimination.
+//
+//===----------------------------------------------------------------------===//
+
+#define DEBUG_TYPE "rds-deadfieldelim"
+#include "StructureFieldVisitor.h"
+#include "llvm/Analysis/DataStructure/DataStructure.h"
+#include "llvm/Analysis/DataStructure/DSGraph.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Timer.h"
+using namespace llvm;
+using namespace llvm::Macroscopic;
+
+namespace {
+  /// DeadFieldElim - This class implements the dead field elimination
+  /// optimization.  This transformation is a very simple macroscopic
+  /// optimization whose high-level algorithm works like this:
+  ///
+  /// 1. Identify all type-homogenous data structures that only contain HGS
+  ///    composition bits.
+  /// 2. For each data structure, visit every load of fields in the node.
+  ///    Keep track of whether a field is ever loaded.
+  /// 3. If we found fields that are never loaded from, rewrite the affected 
+  ///    data structures, deleting the dead fields!
+  ///
+  class DeadFieldElim : public ModulePass {
+
+    bool runOnModule(Module &M);
+
+    void getAnalysisUsage(AnalysisUsage &AU) const {
+      // Need information from DSA.
+      AU.addRequired<EquivClassGraphs>();
+      AU.addPreserved<EquivClassGraphs>();
+    }
+  };
+  RegisterOpt<DeadFieldElim>
+  X("rds-deadfieldelim", "Macroscopic Dead Field Elimination");
+}  // end anonymous namespace
+
+
+namespace {
+  /// DeadFieldElimLattice - This is the most trivial lattice possible: it
+  /// consists of two states, dead (the default) and alive (overdefined,
+  /// bottom).  Because it has only two states, it does not need to maintain any
+  /// actual state.
+  struct DeadFieldElimLattice : public LatticeValue {
+    DeadFieldElimLattice(DSNode *Node, const std::vector<unsigned> &Idxs,
+                         const Type *FieldTy)
+      : LatticeValue(Node, Idxs, FieldTy) {}
+
+    // getInterestingEvents - We only care about reads from memory?
+    static unsigned getInterestingEvents() { return Macroscopic::Visit::Loads; }
+
+    virtual void dump() const {
+      LatticeValue::dump();
+      std::cerr << "  DEAD FIELD!\n";
+    }
+
+    // create - Return a dataflow fact for this field, initialized to top.
+    static DeadFieldElimLattice *create(DSNode *Node,
+                                        const std::vector<unsigned> &Idxs,
+                                        const Type *FieldTy) {
+      return new DeadFieldElimLattice(Node, Idxs, FieldTy);      
+    }
+
+    virtual bool mergeInValue(const LatticeValue *RHS) {
+      return false;  // Neither LHS nor RHS are overdefined.
+    }
+
+    // VisitLoad - Load events always move us to bottom.
+    virtual bool visitLoad(LoadInst &LI) {
+      return true;  // Bottom!
+    }
+  };
+}
+
+
+#include "llvm/Constants.h"
+#include "llvm/Instructions.h"
+namespace {
+  /// ConstPropLattice - This is the standard 3-level constant propagation
+  /// lattice.  When CstVal is null it is undefined, when it is non-null it is
+  /// defined to that constant, and it hits bottom of set to something
+  /// unanalyzable or multiple values.
+  struct ConstPropLattice : public LatticeValue {
+    Constant *CstVal;
+
+    ConstPropLattice(DSNode *Node, const std::vector<unsigned> &Idxs,
+                     const Type *FieldTy)
+      : LatticeValue(Node, Idxs, FieldTy), CstVal(0) {}
+
+    // getInterestingEvents - We only care about reads from memory?
+    static unsigned getInterestingEvents() { return Macroscopic::Visit::Stores;}
+
+    // create - Return a dataflow fact for this field, initialized to top.
+    static ConstPropLattice *create(DSNode *Node,
+                                    const std::vector<unsigned> &Idxs,
+                                    const Type *FieldTy) {
+      return new ConstPropLattice(Node, Idxs, FieldTy);      
+    }
+
+    bool mergeInValue(Constant *V) {
+      if (V == 0 || isa<UndefValue>(V)) return false;
+      if (CstVal == 0)
+        CstVal = V;
+      else if (CstVal != V)
+        return true;
+      return false;
+    }
+
+    virtual void dump() const {
+      LatticeValue::dump();
+      if (CstVal)
+        std::cerr << "  CONSTANT VALUE = " << *CstVal << "\n";
+      else
+        std::cerr << "  FIELD NEVER DEFINED!\n";
+    }
+
+    virtual bool mergeInValue(const LatticeValue *RHSLV) {
+      const ConstPropLattice *RHS = static_cast<const ConstPropLattice*>(RHSLV);
+      return mergeInValue(RHS->CstVal);
+    }
+
+    virtual bool visitStore(StoreInst &SI) {
+      if (Constant *CV = dyn_cast<Constant>(SI.getOperand(0)))
+        return mergeInValue(CV);
+      return true;  // Bottom!
+    }
+
+    bool visitGlobalInit(Constant *InitVal) {
+      return mergeInValue(InitVal);
+    }
+
+    virtual bool visitMemSet(CallInst &I) {
+      if (Constant *C = dyn_cast<Constant>(I.getOperand(2)))
+        if (C->isNullValue()) {
+          std::cerr << "HANDLED MEMSET: " << I;
+          return mergeInValue(Constant::getNullValue(getFieldType()));
+        }
+      return true;
+    }
+  };
+}
+
+
+
+bool DeadFieldElim::runOnModule(Module &M) {
+  EquivClassGraphs &ECG = getAnalysis<EquivClassGraphs>();
+
+  // Step #1: Identify all type-homogenous HGS (non-U) data structure nodes.
+  std::set<DSNode*> Nodes;
+
+  { NamedRegionTimer XX("Dead Fields");
+
+  FindAllDataStructures(Nodes, 0 /*nothing required*/,
+                        DSNode::UnknownNode, true /*typesafe*/, ECG);
+
+  DEBUG(std::cerr << "DeadFieldElim: Found " << Nodes.size()
+                  << " eligible data structure nodes.\n");
+
+  // Step #2: For each data structure, visit every load of fields in the node.
+  // Keep track of whether a field is ever loaded.  The visitor returns a set of
+  // lattice values that have not reached bottom (in this case, that means it
+  // returns a set of dead fields).
+  std::set<DeadFieldElimLattice*> DeadFields =
+    StructureFieldVisitor<DeadFieldElimLattice>(ECG).visit(Nodes);
+
+  DEBUG(std::cerr << "DeadFieldElim: Found " << DeadFields.size()
+        << " dead fields!\n");
+  for (std::set<DeadFieldElimLattice*>::iterator I = DeadFields.begin(),
+         E = DeadFields.end(); I != E; ++I) {
+    DEBUG((*I)->dump());
+    delete *I;
+  }
+  DEBUG(std::cerr << "\n");
+  }
+  //return true;
+
+  { NamedRegionTimer XX("Constants");
+
+  Nodes.clear();
+  FindAllDataStructures(Nodes, 0 /*nothing required*/,
+                        DSNode::UnknownNode, true /*typesafe*/, ECG);
+
+  // Step #2: For each data structure, visit every stores to fields in the node.
+  // Keep track of whether a field is always constant.  The visitor returns a
+  // set of lattice values that have not reached bottom (in this case, that
+  // means they are either undefined or overdefined.
+  std::set<ConstPropLattice*> ConstantFields =
+    StructureFieldVisitor<ConstPropLattice>(ECG).visit(Nodes);
+
+  DEBUG(std::cerr << "ConstProp: Found " << ConstantFields.size()
+        << " constant or uninitialized fields!\n");
+  for (std::set<ConstPropLattice*>::iterator I = ConstantFields.begin(),
+         E = ConstantFields.end(); I != E; ++I) {
+    DEBUG((*I)->dump());
+    delete *I;
+  }
+  DEBUG(std::cerr << "\n");
+
+  }
+
+  return true;
+
+  // NOTE: We could do a simple thing that checks for fields whose loads are
+  // immediately casted to something smaller, and stores that are casted from
+  // something smaller to shrink them.
+
+
+  { NamedRegionTimer XX("Combined");
+
+  Nodes.clear();
+  FindAllDataStructures(Nodes, 0 /*nothing required*/,
+                        DSNode::UnknownNode, true /*typesafe*/, ECG);
+
+  typedef CombinedLatticeValue<DeadFieldElimLattice,ConstPropLattice>
+    CombinedLattice;
+
+  // Step #2: For each data structure, visit every stores to fields in the node.
+  // Keep track of whether a field is always constant.  The visitor returns a
+  // set of lattice values that have not reached bottom (in this case, that
+  // means they are either undefined or overdefined.
+  std::set<CombinedLattice*> CombinedFields =
+    StructureFieldVisitor<CombinedLattice>(ECG).visit(Nodes);
+
+  DEBUG(std::cerr << "Combined: Found " << CombinedFields.size()
+        << " interesting fields!\n");
+  for (std::set<CombinedLattice*>::iterator I = CombinedFields.begin(),
+         E = CombinedFields.end(); I != E; ++I) {
+    DEBUG((*I)->dump());
+    delete *I;
+  }
+  DEBUG(std::cerr << "\n");
+
+  }
+
+  return true;
+}


Index: llvm-poolalloc/lib/Macroscopic/Makefile
diff -u /dev/null llvm-poolalloc/lib/Macroscopic/Makefile:1.3
--- /dev/null	Wed May 18 14:56:41 2005
+++ llvm-poolalloc/lib/Macroscopic/Makefile	Wed May 18 14:56:26 2005
@@ -0,0 +1,12 @@
+# Indicate where we are relative to the top of the source tree.
+LEVEL=../..
+
+# Give the name of a library.  This will build a dynamic version.
+SHARED_LIBRARY=1
+LOADABLE_MODULE = 1
+DONT_BUILD_RELINKED=1
+LIBRARYNAME=macroscopic
+
+# Include Makefile.common so we know what to do.
+include $(LEVEL)/Makefile.common
+


Index: llvm-poolalloc/lib/Macroscopic/README.txt
diff -u /dev/null llvm-poolalloc/lib/Macroscopic/README.txt:1.3
--- /dev/null	Wed May 18 14:56:41 2005
+++ llvm-poolalloc/lib/Macroscopic/README.txt	Wed May 18 14:56:26 2005
@@ -0,0 +1,5 @@
+//===- llvm-poolalloc/lib/Macroscopic -------------------------------------===//
+
+This directory contains an experimental implementation of several ideas for
+Macroscopic analyses and transformations, which may eventually include
+reimplementation of the pool allocator and other passes.


Index: llvm-poolalloc/lib/Macroscopic/StructureFieldVisitor.cpp
diff -u /dev/null llvm-poolalloc/lib/Macroscopic/StructureFieldVisitor.cpp:1.5
--- /dev/null	Wed May 18 14:56:41 2005
+++ llvm-poolalloc/lib/Macroscopic/StructureFieldVisitor.cpp	Wed May 18 14:56:26 2005
@@ -0,0 +1,939 @@
+//===-- StructureFieldVisitor.cpp - Implement StructureFieldVisitor -------===//
+// 
+//                     The LLVM Compiler Infrastructure
+//
+// This file was developed by the LLVM research group and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+// 
+//===----------------------------------------------------------------------===//
+//
+// This file implements the StructureFieldVisitor and related classes.
+//
+//===----------------------------------------------------------------------===//
+
+#include "StructureFieldVisitor.h"
+#include "llvm/Constants.h"
+#include "llvm/DerivedTypes.h"
+#include "llvm/Analysis/DataStructure/DataStructure.h"
+#include "llvm/Analysis/DataStructure/DSGraph.h"
+#include "llvm/Intrinsics.h"
+#include "llvm/Support/InstVisitor.h"
+#include <algorithm>
+#include <iostream>
+
+using namespace llvm::Macroscopic;
+using namespace llvm;
+
+/// FindAllDataStructures - Inspect the program specified by ECG, adding to
+/// 'Nodes' all of the data structures node in the program that contain the
+/// "IncludeFlags" and do not contain "ExcludeFlags" node flags.  If
+/// OnlyHomogenous is true, only type-homogenous nodes are considered.
+void FindAllDataStructures(std::set<DSNode*> &Nodes, unsigned IncludeFlags,
+                           unsigned ExcludeFlags, bool OnlyHomogenous,
+                           EquivClassGraphs &ECG) {
+  // Loop over all of the graphs in ECG, finding nodes that are not incomplete
+  // and do not have any of the flags specified by Flags.
+  ExcludeFlags |= DSNode::Incomplete;
+
+  /// FIXME: nodes in the global graph should not be marked incomplete in main!!
+  for (hash_map<const Function*, DSGraph*>::iterator GI = ECG.DSInfo.begin(),
+         E = ECG.DSInfo.end(); GI != E; ++GI) {
+    assert(GI->second && "Null graph pointer?");
+    DSGraph &G = *GI->second;
+    for (DSGraph::node_iterator I = G.node_begin(), E = G.node_end();
+         I != E; ++I)
+      // If this node matches our constraints, include it.
+      if ((I->getNodeFlags() & IncludeFlags) == IncludeFlags &&
+          (I->getNodeFlags() & ExcludeFlags) == 0)
+        if (!OnlyHomogenous || !I->isNodeCompletelyFolded())
+          Nodes.insert(I);
+  }
+}
+
+//===----------------------------------------------------------------------===//
+// LatticeValue class implementation
+//
+
+DSGraph &LatticeValue::getParentGraph() const {
+  DSGraph *PG = getNode()->getParentGraph();
+  assert(PG && "Node doesn't have a parent, is it a GlobalGraph node?");
+  return *PG;
+}
+
+/// getFieldOffset - Return the offset of this field from the start of the node.
+///
+unsigned LatticeValue::getFieldOffset() const {
+  const TargetData &TD = getNode()->getParentGraph()->getTargetData();
+
+  unsigned Offset = 0;
+  const Type *Ty = Node->getType();
+  for (unsigned i = 0, e = Idxs.size(); i != e; ++i)
+    if (const StructType *STy = dyn_cast<StructType>(Ty)) {
+      const StructLayout *SL = TD.getStructLayout(STy);
+      Offset += SL->MemberOffsets[Idxs[i]];
+      Ty = STy->getElementType(Idxs[i]);
+    } else {
+      const SequentialType *STy = cast<SequentialType>(Ty);
+      Ty = STy->getElementType();
+      --i;   // This doesn't index a struct.
+    }
+  return Offset;
+}
+
+
+
+void LatticeValue::dump() const {
+  std::cerr << "\nFunction: " << Node->getParentGraph()->getFunctionNames()
+            << "\n";
+  Node->dump();
+  if (!Idxs.empty()) {
+    std::cerr << "Field: ";
+    for (unsigned i = 0, e = Idxs.size(); i != e; ++i)
+      std::cerr << Idxs[i] << ".";
+  }
+  std::cerr << "\n";
+}
+
+bool LatticeValue::visitLoad(LoadInst &) {
+  std::cerr << "ERROR: Client requested load visitation, but did not "
+            << "overload visitLoad!\n";
+  dump();
+  return true;
+}
+bool LatticeValue::visitStore(StoreInst &) {
+  std::cerr << "ERROR: Client requested store visitation, but did not "
+            << "overload visitStore!\n";
+  dump();
+  return true;
+}
+
+bool LatticeValue::visitGlobalInit(Constant *) {
+  std::cerr << "ERROR: Client requested store visitation, but did not "
+            << "overload visitGlobalInit!\n";
+  dump();
+  return true;
+}
+
+//===----------------------------------------------------------------------===//
+// SFVInstVisitor class implementation
+//
+
+namespace {
+  /// SFVInstVisitor - This visitor is used to do the actual visitation of
+  /// memory instructions in the program.
+  ///
+  struct SFVInstVisitor : public InstVisitor<SFVInstVisitor, bool> {
+    DSGraph &DSG;
+    const unsigned Callbacks;
+    std::multimap<DSNode*, LatticeValue*> &NodeLVs;
+
+    // DirectCallSites - When we see call sites, we don't process them, but we
+    // do remember them if they are direct calls.
+    std::set<Instruction*> DirectCallSites;
+
+    SFVInstVisitor(DSGraph &dsg, unsigned CBs,
+                   std::multimap<DSNode*, LatticeValue*> &LVs)
+      : DSG(dsg), Callbacks(CBs), NodeLVs(LVs) {}
+
+    // Methods used by visitation methods.
+    LatticeValue *getLatticeValueForField(Value *Ptr);
+    bool RemoveLatticeValueAtBottom(LatticeValue *LV);
+
+    /// Visitation methods - These methods should return true when a lattice
+    /// value is driven to 'bottom' and removed from NodeLVs.
+    bool visitLoadInst(LoadInst &LI);
+    bool visitStoreInst(StoreInst &SI);
+
+    /// These are not implemented yet.
+    bool visitGetElementPtrInst(GetElementPtrInst &GEPI) { return false; }
+    bool visitMallocInst(MallocInst &MI) { return false; }
+    bool visitAllocaInst(AllocaInst &AI) { return false; }
+    bool visitFreeInst(FreeInst &FI) { return false; }
+    bool visitPHINode(PHINode &PN) { return false; }
+    bool visitSelectInst(SelectInst &SI) { return false; }
+    bool visitSetCondInst(SetCondInst &SCI) { return false; }
+    bool visitCastInst(CastInst &CI) { return false; }
+    bool visitReturnInst(ReturnInst &RI) { return false; }
+    
+    // visitCallInst/visitInvokeInst - Call and invoke are handled specially, so
+    // they are just noops here.
+    bool visitCallInst(CallInst &CI) { return visitCallSite(CI); }
+    bool visitInvokeInst(InvokeInst &II) { return visitCallSite(II); }
+    bool visitCallSite(Instruction &I) {
+      // Remember direct function calls.
+      if (isa<Function>(I.getOperand(0))) DirectCallSites.insert(&I);
+      return false;
+    }
+
+    bool visitInstruction(Instruction &I) {
+#ifndef NDEBUG
+      // Check to make sure this instruction really isn't using anything we the
+      // client needs to know about.
+      assert(getLatticeValueForField(&I) == 0 && "Inst should be handled!");
+      for (unsigned i = 0, e = I.getNumOperands(); i != e; ++i)
+        assert(getLatticeValueForField(I.getOperand(i)) == 0 &&
+               "Inst should be handled by visitor!");
+#endif
+      return false;
+    }
+  };
+}
+
+static void ComputeStructureFieldIndices(const Type *Ty, unsigned Offset,
+                                         std::vector<unsigned> &Idxs,
+                                         const TargetData &TD) {
+  if (Ty->isFirstClassType()) {
+    assert(Offset == 0 && "Illegal structure index!");
+    return;
+  }
+
+  if (const SequentialType *STy = dyn_cast<SequentialType>(Ty)) {
+    ComputeStructureFieldIndices(STy->getElementType(), Offset, Idxs, TD);
+  } else if (const StructType *STy = dyn_cast<StructType>(Ty)) {
+    const StructLayout *SL = TD.getStructLayout(STy);
+    
+    std::vector<uint64_t>::const_iterator SI =
+      std::upper_bound(SL->MemberOffsets.begin(), SL->MemberOffsets.end(),
+                       Offset);
+    assert(SI != SL->MemberOffsets.begin() && "Offset not in structure type!");
+    --SI;
+    assert(*SI <= Offset && "upper_bound didn't work");
+    assert((SI == SL->MemberOffsets.begin() || *(SI-1) < Offset) &&
+           (SI+1 == SL->MemberOffsets.end() || *(SI+1) > Offset) &&
+           "Upper bound didn't work!");
+    Offset -= *SI;   // Skip over the offset to this structure field.
+    unsigned Idx = SI - SL->MemberOffsets.begin();
+    assert(Idx < STy->getNumElements() && "Illegal structure index");
+    Idxs.push_back(Idx);
+    ComputeStructureFieldIndices(STy->getElementType(Idx), Offset, Idxs, TD);
+  } else {
+    assert(0 && "Unknown type to index into!");
+  }  
+}
+
+LatticeValue *SFVInstVisitor::getLatticeValueForField(Value *Ptr) {
+  if (!isa<PointerType>(Ptr->getType()) ||
+      isa<ConstantPointerNull>(Ptr)) return 0;
+
+  const DSNodeHandle *NH = &DSG.getNodeForValue(Ptr);
+  DSNode *Node = NH->getNode();
+  assert(Node && "Pointer doesn't have node??");
+
+  std::multimap<DSNode*, LatticeValue*>::iterator I = NodeLVs.find(Node);
+  if (I == NodeLVs.end()) return 0;  // Not a node we are still tracking.
+
+  // Okay, next convert the node offset to a field index expression.
+  std::vector<unsigned> Idxs;
+  ComputeStructureFieldIndices(Node->getType(), NH->getOffset(), Idxs,
+                               Node->getParentGraph()->getTargetData());
+
+  for (; I != NodeLVs.end() && I->first == Node; ++I)
+    if (I->second->getIndices() == Idxs)
+      return I->second;
+  return 0;
+}
+
+/// RemoveLatticeValueAtBottom - When analysis determines that LV hit bottom,
+/// this method is used to remove it from the NodeLVs map.  This method always
+/// returns true to simplify caller code.
+///
+bool SFVInstVisitor::RemoveLatticeValueAtBottom(LatticeValue *LV) {
+  for (std::multimap<DSNode*, LatticeValue*>::iterator I
+         = NodeLVs.find(LV->getNode());; ++I) {
+    assert(I != NodeLVs.end() && "Lattice value not in map??");
+    if (I->second == LV) {
+      NodeLVs.erase(I);
+      return true;
+    }
+  }
+}
+
+
+bool SFVInstVisitor::visitLoadInst(LoadInst &LI) {
+  if ((Callbacks & Visit::Loads) == 0) return false;
+
+  if (LatticeValue *LV = getLatticeValueForField(LI.getOperand(0)))
+    if (LV->visitLoad(LI))
+      return RemoveLatticeValueAtBottom(LV);
+
+  return false;
+}
+
+bool SFVInstVisitor::visitStoreInst(StoreInst &SI) {
+  if ((Callbacks & Visit::Stores) == 0) return false;
+
+  if (LatticeValue *LV = getLatticeValueForField(SI.getOperand(1)))
+    if (LV->visitStore(SI))
+      return RemoveLatticeValueAtBottom(LV);
+
+  return false;
+}
+
+
+//===----------------------------------------------------------------------===//
+// StructureFieldVisitorBase class implementation
+//
+
+void StructureFieldVisitorBase::
+AddLatticeValuesForFields(DSNode *Node, const Type *Ty,
+                          const std::vector<unsigned> &Idxs,
+                          std::set<LatticeValue*> &Values) {
+  if (Ty->isFirstClassType()) {
+    if (LatticeValue *LV = createLatticeValue(Node, Idxs, Ty))
+      Values.insert(LV);
+    return;
+  }
+
+  const StructType *STy = dyn_cast<StructType>(Ty);
+  if (STy == 0) return;  // Not handling arrays yet!
+
+  std::vector<unsigned> NextIdxs(Idxs);
+  NextIdxs.push_back(0);
+  for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) {
+    NextIdxs.back() = i;
+    AddLatticeValuesForFields(Node, STy->getElementType(i), NextIdxs, Values);
+  }
+}
+
+void StructureFieldVisitorBase::
+AddLatticeValuesForNode(DSNode *N, std::set<LatticeValue*> &Values) {
+  if (N->isNodeCompletelyFolded() ||
+      N->getType() == Type::VoidTy) return;  // Can't analyze node.
+  std::vector<unsigned> Idxs;
+  AddLatticeValuesForFields(N, N->getType(), Idxs, Values);
+}
+
+
+/// visitNodes - This is a simple wrapper around visitFields that creates a
+/// lattice value for every field in the specified collection of nodes.
+///
+std::set<LatticeValue*> StructureFieldVisitorBase::
+visitNodes(const std::set<DSNode*> &Nodes) {
+  std::set<LatticeValue*> Result;
+
+  // Create lattice values for all of the fields in these nodes.
+  for (std::set<DSNode*>::const_iterator I = Nodes.begin(), E = Nodes.end();
+       I != E; ++I)
+    AddLatticeValuesForNode(*I, Result);
+
+  // Now that we have the lattice values, just use visitFields to do the grunt
+  // work.
+  visitFields(Result);
+  return Result;
+}
+
+
+/// VisitGlobalInit - The specified lattice value corresponds to a field (or
+/// several) in the specified global.  Merge all of the overlapping initializer
+/// values into LV (up-to and until it becomes overdefined).
+///
+static bool VisitGlobalInit(LatticeValue *LV, Constant *Init,
+                            unsigned FieldOffset) {
+  const TargetData &TD = LV->getParentGraph().getTargetData();
+
+  if (Init->isNullValue())
+    return LV->visitGlobalInit(Constant::getNullValue(LV->getFieldType()));
+  if (isa<UndefValue>(Init))
+    return LV->visitGlobalInit(UndefValue::get(LV->getFieldType()));
+
+  if (LV->getNode()->isArray() &&
+      TD.getTypeSize(Init->getType()) > LV->getNode()->getSize()) {
+    ConstantArray *CA = cast<ConstantArray>(Init);
+    for (unsigned i = 0, e = CA->getNumOperands(); i != e; ++i)
+      if (VisitGlobalInit(LV, CA->getOperand(i), FieldOffset))
+        return true;
+    return false;
+  }
+
+NextStep:  // Manual tail recursion
+
+  if (Init->isNullValue())
+    return LV->visitGlobalInit(Constant::getNullValue(LV->getFieldType()));
+  if (isa<UndefValue>(Init))
+    return LV->visitGlobalInit(UndefValue::get(LV->getFieldType()));
+  if (Init->getType()->isFirstClassType()) {
+    assert(FieldOffset == 0 && "GV Init mismatch!");
+    return LV->visitGlobalInit(Init);
+  }
+  
+  if (const StructType *STy = dyn_cast<StructType>(Init->getType())) {
+    const StructLayout *SL = TD.getStructLayout(STy);
+    unsigned Field = SL->getElementContainingOffset(FieldOffset);
+    FieldOffset -= SL->MemberOffsets[Field];
+    Init = cast<ConstantStruct>(Init)->getOperand(Field);
+    goto NextStep;
+  } else if (const ArrayType *ATy = dyn_cast<ArrayType>(Init->getType())) {
+    unsigned ElSz = TD.getTypeSize(ATy->getElementType());
+    unsigned Idx = FieldOffset / ElSz;
+    FieldOffset -= Idx*ElSz;
+    Init = cast<ConstantArray>(Init)->getOperand(Idx);
+    goto NextStep;
+  } else {
+    assert(0 && "Unexpected initializer type!");
+    return true;
+  }
+}
+
+
+/// visitFields - Visit all uses of the specified fields, updating the lattice
+/// values as appropriate.
+///
+void StructureFieldVisitorBase::visitFields(std::set<LatticeValue*> &Fields) {
+  // Now that we added all of the initial nodes, find out what graphs these
+  // nodes are rooted in.  For efficiency, handle batches of nodes in the same
+  // function together at the same time.  To do this, pull everything out of
+  // Fields and put it into FieldsByGraph.
+  std::multimap<DSGraph*, LatticeValue*> FieldsByGraph;
+  while (!Fields.empty()) {
+    LatticeValue *LV = *Fields.begin();
+    Fields.erase(Fields.begin());
+    FieldsByGraph.insert(std::make_pair(&LV->getParentGraph(), LV));
+  }
+
+  // Now that everything is grouped by graph, process a graph worth of nodes at
+  // a time, moving the results back to Fields if they are not overdefined.
+  while (!FieldsByGraph.empty()) {
+    // NodeLVs - Inspect all of the lattice values that are active in this
+    // graph.
+    std::multimap<DSNode*, LatticeValue*> NodeLVs;
+    DSGraph &DSG = *FieldsByGraph.begin()->first;
+
+    // Pull out all nodes in this graph, putting them into NodeLVs.
+    while (FieldsByGraph.begin()->first == &DSG) {
+      LatticeValue *LV = FieldsByGraph.begin()->second;
+      FieldsByGraph.erase(FieldsByGraph.begin());
+      NodeLVs.insert(std::make_pair(LV->getNode(), LV));
+    }
+
+    // Visit all operations in this graph, looking at how these lattice values
+    // are used!
+    visitGraph(DSG, NodeLVs);
+
+    if (NodeLVs.empty()) continue;
+
+    // If any of the nodes have globals, and if we are inspecting stores, make
+    // sure to notice the global variable initializers.
+    if (Callbacks & Visit::Stores) {
+      for (std::multimap<DSNode*, LatticeValue*>::iterator I = NodeLVs.begin();
+           I != NodeLVs.end(); ) {
+        // If this node has globals, incorporate them.
+        bool LVisOverdefined = false;
+        std::vector<GlobalValue*> GVs;
+        I->first->addFullGlobalsList(GVs);
+        for (unsigned i = 0, e = GVs.size(); i != e; ++i)
+          if (GlobalVariable *GV = dyn_cast<GlobalVariable>(GVs[i])) {
+            assert(GV->hasInitializer() && "Should not be analyzing this GV!");
+            if (VisitGlobalInit(I->second, GV->getInitializer(),
+                                I->second->getFieldOffset())) {
+              LVisOverdefined = true;
+              break;
+            }
+          }
+
+        if (LVisOverdefined)
+          NodeLVs.erase(I++);
+        else
+          ++I;
+      }
+      if (NodeLVs.empty()) continue;
+    }
+
+    // Okay, final check.  If we have any dataflow facts about nodes that are
+    // reachable from global variable nodes, we must make sure to check every
+    // function in the program that uses the global for uses of the node.
+    // Because of the globals graph, we might not have all of the information we
+    // need with our (potentially) truncated call graph traversal.
+    ProcessNodesReachableFromGlobals(DSG, NodeLVs);
+
+    // Everything that survived goes into Fields now that we processed it.
+    while (!NodeLVs.empty()) {
+      Fields.insert(NodeLVs.begin()->second);
+      NodeLVs.erase(NodeLVs.begin());
+    }
+  }
+}
+
+/// ComputeInverseGraphFrom - Perform a simple depth-first search of the
+/// DSGraph, recording the inverse of all of the edges in the graph.
+///
+static void ComputeInverseGraphFrom(DSNode *N,
+                         std::set<std::pair<DSNode*,DSNode*> > &InverseGraph) {
+  for (DSNode::edge_iterator I = N->edge_begin(), E = N->edge_end(); I != E;++I)
+    if (DSNode *Target = I->getNode())
+      if (InverseGraph.insert(std::make_pair(Target, N)).second)
+        ComputeInverseGraphFrom(Target, InverseGraph);
+}
+
+
+/// ComputeNodesReacahbleFrom - Compute the set of nodes in the specified
+/// inverse graph that are reachable from N.  This is a simple depth first
+/// search.
+///
+static void ComputeNodesReachableFrom(DSNode *N,
+                            std::set<std::pair<DSNode*,DSNode*> > &InverseGraph,
+                                      hash_set<const DSNode*> &Reachable) {
+  if (!Reachable.insert(N).second) return;  // Already visited!
+  
+  std::set<std::pair<DSNode*,DSNode*> >::iterator I = 
+    InverseGraph.lower_bound(std::make_pair(N, (DSNode*)0));
+  for (; I != InverseGraph.end() && I->first == N; ++I)
+    ComputeNodesReachableFrom(I->second, InverseGraph, Reachable);
+}
+
+/// ProcessNodesReachableFromGlobals - If we inferred anything about nodes
+/// reachable from globals, we have to make sure that we incorporate data for
+/// all graphs that include those globals due to the nature of the globals
+/// graph.
+///
+void StructureFieldVisitorBase::
+ProcessNodesReachableFromGlobals(DSGraph &DSG,
+                                 std::multimap<DSNode*,LatticeValue*> &NodeLVs){
+  // Start by marking all nodes reachable from globals.
+  DSScalarMap &SM = DSG.getScalarMap();
+  if (SM.global_begin() == SM.global_end()) return;
+
+  hash_set<const DSNode*> Reachable;
+  for (DSScalarMap::global_iterator GI = SM.global_begin(),
+         E = SM.global_end(); GI != E; ++GI)
+    SM[*GI].getNode()->markReachableNodes(Reachable);
+  if (Reachable.empty()) return;
+  
+  // If any of the nodes with dataflow facts are reachable from the globals
+  // graph, we have to do the GG processing step.
+  bool MustProcessThroughGlobalsGraph = false;
+  for (std::multimap<DSNode*, LatticeValue*>::iterator I = NodeLVs.begin(),
+         E = NodeLVs.end(); I != E; ++I)
+    if (Reachable.count(I->first)) {
+      MustProcessThroughGlobalsGraph = true;
+      break;
+    }
+  
+  if (!MustProcessThroughGlobalsGraph) return;
+  Reachable.clear();
+
+  // Compute the mapping from DSG to the globals graph.
+  DSGraph::NodeMapTy DSGToGGMap;
+  DSG.computeGToGGMapping(DSGToGGMap);
+
+  // Most of the times when we find facts about things reachable from globals we
+  // we are in the main graph.  This means that we have *all* of the globals
+  // graph in this DSG.  To be efficient, we compute the minimum set of globals
+  // that can reach any of the NodeLVs facts.
+  //
+  // I'm not aware of any wonderful way of computing the set of globals that
+  // points to the set of nodes in NodeLVs that is not N^2 in either NodeLVs or
+  // the number of globals, except to compute the inverse of DSG.  As such, we
+  // compute the inverse graph of DSG, which basically has the edges going from
+  // pointed to nodes to pointing nodes.  Because we only care about one
+  // connectedness properties, we ignore field info.  In addition, we only
+  // compute inverse of the portion of the graph reachable from the globals.
+  std::set<std::pair<DSNode*,DSNode*> > InverseGraph;
+
+  for (DSScalarMap::global_iterator GI = SM.global_begin(),
+         E = SM.global_end(); GI != E; ++GI)
+    ComputeInverseGraphFrom(SM[*GI].getNode(), InverseGraph);
+
+  // Okay, now that we have our bastardized inverse graph, compute the set of
+  // globals nodes reachable from our lattice nodes.
+  for (std::multimap<DSNode*, LatticeValue*>::iterator I = NodeLVs.begin(),
+         E = NodeLVs.end(); I != E; ++I)
+    ComputeNodesReachableFrom(I->first, InverseGraph, Reachable);
+ 
+  // Now that we know which nodes point to the data flow facts, figure out which
+  // globals point to the data flow facts.
+  std::set<GlobalValue*> Globals;
+  for (hash_set<const DSNode*>::iterator I = Reachable.begin(),
+         E = Reachable.end(); I != E; ++I)
+    Globals.insert((*I)->globals_begin(), (*I)->globals_end());
+
+  // Finally, loop over all of the DSGraphs for the program, computing
+  // information for the graph if not done already, mapping the result into our
+  // context.
+  for (hash_map<const Function*, DSGraph*>::iterator GI = ECG.DSInfo.begin(),
+         E = ECG.DSInfo.end(); GI != E; ++GI) {
+    DSGraph &FG = *GI->second;
+    // Graphs can contain multiple functions, only process the graph once.
+    if (GI->first != FG.retnodes_begin()->first ||
+        // Also, do not bother reprocessing DSG.
+        &FG == &DSG)
+      continue;
+
+    bool GraphUsesGlobal = false;
+    for (std::set<GlobalValue*>::iterator I = Globals.begin(),
+           E = Globals.end(); I != E; ++I)
+      if (FG.getScalarMap().count(*I)) {
+        GraphUsesGlobal = true;
+        break;
+      }
+
+    // If this graph does not contain the global at all, there is no reason to
+    // even think about it.
+    if (!GraphUsesGlobal) continue;
+
+    // Otherwise, compute the full set of dataflow effects of the function.
+    std::multimap<DSNode*, LatticeValue*> &FGF = getCalleeFacts(FG);
+    //std::cerr << "Computed: " << FG.getFunctionNames() << "\n";
+
+#if 0
+    for (std::multimap<DSNode*, LatticeValue*>::iterator I = FGF.begin(),
+           E = FGF.end(); I != E; ++I)
+      I->second->dump();
+#endif
+    // Compute the mapping of nodes in the globals graph to the function's
+    // graph.  Note that this function graph may not have nodes (or may have
+    // fragments of full nodes) in the globals graph, and we don't want this to
+    // pessimize the analysis.
+    std::multimap<const DSNode*, std::pair<DSNode*,int> > GraphMap;
+    DSGraph::NodeMapTy GraphToGGMap;
+    FG.computeGToGGMapping(GraphToGGMap);
+
+    // "Invert" the mapping.  We compute the mapping from the start of a global
+    // graph node to a place in the graph's node.  Note that not all of the GG
+    // node may be present in the graphs node, so there may be a negative offset
+    // involved.
+    while (!GraphToGGMap.empty()) {
+      DSNode *GN = const_cast<DSNode*>(GraphToGGMap.begin()->first);
+      DSNodeHandle &GGNH = GraphToGGMap.begin()->second;
+      GraphMap.insert(std::make_pair(GGNH.getNode(),
+                                     std::make_pair(GN, -GGNH.getOffset())));
+      GraphToGGMap.erase(GraphToGGMap.begin());
+    }
+
+    // Loop over all of the dataflow facts that we have computed, mapping them
+    // to the globals graph.
+    for (std::multimap<DSNode*, LatticeValue*>::iterator I = NodeLVs.begin(),
+           E = NodeLVs.end(); I != E; ) {
+      bool FactHitBottom = false;
+
+      //I->second->dump();
+
+      assert(I->first->getParentGraph() == &DSG);
+      assert(I->second->getNode()->getParentGraph() == &DSG);
+
+      // Node is in the GG?
+      DSGraph::NodeMapTy::iterator DSGToGGMapI = DSGToGGMap.find(I->first);
+      if (DSGToGGMapI != DSGToGGMap.end()) {
+        DSNodeHandle &GGNH = DSGToGGMapI->second;
+        const DSNode *GGNode = GGNH.getNode();
+        unsigned DSGToGGOffset = GGNH.getOffset();
+
+        // See if there is a node in FG that corresponds to this one.  If not,
+        // no information will be computed in this scope, as the memory is not
+        // accessed.
+        std::multimap<const DSNode*, std::pair<DSNode*,int> >::iterator GMI =
+          GraphMap.find(GGNode);
+
+        // LatticeValOffset - The offset from the start of the GG Node to the
+        // start of the field we are interested in.
+        unsigned LatticeValOffset = I->second->getFieldOffset()+DSGToGGOffset;
+
+        // Loop over all of the nodes in FG that correspond to this single node
+        // in the GG.
+        for (; GMI != GraphMap.end() && GMI->first == GGNode; ++GMI) {
+          // Compute the offset to the field in the user graph.
+          unsigned FieldOffset = LatticeValOffset - GMI->second.second;
+
+          // If the field is within the amount of memory accessed by this scope,
+          // then there must be a corresponding lattice value.
+          DSNode *FGNode = GMI->second.first;
+          if (FieldOffset < FGNode->getSize()) {
+            LatticeValue *CorrespondingLV = 0;
+
+            std::multimap<DSNode*, LatticeValue*>::iterator FGFI =
+              FGF.find(FGNode);
+            for (; FGFI != FGF.end() && FGFI->first == FGNode; ++FGFI)
+              if (FGFI->second->getFieldOffset() == FieldOffset) {
+                CorrespondingLV = FGFI->second;
+                break;
+              }
+
+            // Finally, if either there was no corresponding fact (because it
+            // hit bottom in this scope), or if merging the two pieces of
+            // information makes it hit bottom, remember this.
+            if (CorrespondingLV == 0 ||
+                I->second->mergeInValue(CorrespondingLV))
+              FactHitBottom = true;
+          }
+        }
+      }
+
+      if (FactHitBottom) {
+        delete I->second;
+        NodeLVs.erase(I++);
+        if (NodeLVs.empty()) return;
+      } else {
+        ++I;
+      }
+    }
+  }
+}
+
+
+/// getCalleeFacts - Compute the data flow effect that calling one of the
+/// functions in this graph has on the caller.  This information is cached after
+/// it is computed for a function the first time.
+///
+std::multimap<DSNode*, LatticeValue*> &
+StructureFieldVisitorBase::getCalleeFacts(DSGraph &DSG) {
+  // Already computed?
+  std::map<DSGraph*, std::multimap<DSNode*,LatticeValue*> >::iterator
+    I = CalleeFnFacts.find(&DSG);
+  if (I != CalleeFnFacts.end())
+    return I->second;   // We already computed stuff for this fn!
+  
+  std::multimap<DSNode*, LatticeValue*> &Result = CalleeFnFacts[&DSG];
+
+  std::set<LatticeValue*> LVs;
+  for (DSGraph::node_iterator NI = DSG.node_begin(), E = DSG.node_end();
+       NI != E; ++NI)
+    AddLatticeValuesForNode(NI, LVs);
+
+  while (!LVs.empty()) {
+    Result.insert(std::make_pair((*LVs.begin())->getNode(), *LVs.begin()));
+    LVs.erase(LVs.begin());
+  }
+
+  if (!Result.empty())
+    visitGraph(DSG, Result);
+  return Result;
+}
+
+
+/// NodeCanPossiblyBeInteresting - Return true if the specified node can
+/// potentially be interesting to a client that is only interested in
+/// VisitFlags events.  This is used to reduce the cost of interprocedural
+/// analysis by not traversing the call graph through portions that the DSGraph
+/// can answer immediately.
+///
+static bool NodeCanPossiblyBeInteresting(const DSNode *N, unsigned VisitFlags) {
+  // No fields are accessed in this context.
+  if (N->getType() == Type::VoidTy) return false;
+  
+  // This node is possibly interesting if we are looking for reads and it is
+  // read, we're looking for writes and it is modified, etc.
+  if ((VisitFlags & Visit::Loads) && N->isRead()) return true;
+  if ((VisitFlags & Visit::Stores) && N->isModified()) return true;
+
+  assert((VisitFlags & ~(Visit::Loads|Visit::Stores)) == 0 &&
+         "Unknown visitation type!");
+
+  // Otherwise, this node is not interesting to the current client.
+  return false;
+}
+
+/// visitGraph - Visit the functions in the specified graph, updating the
+/// specified lattice values for all of their uses.
+///
+void StructureFieldVisitorBase::
+visitGraph(DSGraph &DSG, std::multimap<DSNode*, LatticeValue*> &NodeLVs) {
+  assert(!NodeLVs.empty() && "No lattice values to compute!");
+
+  // To visit a graph, first step, we visit the instruction making up each
+  // function in the graph, but ignore calls when processing them.  We handle
+  // call nodes explicitly by looking at call nodes in the graph if needed.  We
+  // handle instructions before calls to avoid interprocedural analysis if we
+  // can drive lattice values to bottom early.
+  //
+  SFVInstVisitor IV(DSG, Callbacks, NodeLVs);
+
+  for (DSGraph::retnodes_iterator FI = DSG.retnodes_begin(),
+         E = DSG.retnodes_end(); FI != E; ++FI)
+    for (Function::iterator BB = FI->first->begin(), E = FI->first->end();
+         BB != E; ++BB)
+      for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I)
+        if (IV.visit(*I) && NodeLVs.empty())
+          return;  // Nothing left to analyze.
+
+  // Keep track of which actual direct callees are handled.
+  std::set<Function*> CalleesHandled;
+
+  // Once we have visited all of the instructions in the function bodies, if
+  // there are lattice values that have not been driven to bottom, see if any of
+  // the nodes involved are passed into function calls.  If so, we potentially
+  // have to recursively traverse the call graph.
+  for (DSGraph::fc_iterator CS = DSG.fc_begin(), E = DSG.fc_end();
+       CS != E; ++CS) {
+    // Figure out the mapping from a node in the caller (potentially several)
+    // nodes in the callee.
+    DSGraph::NodeMapTy CallNodeMap;
+
+    Instruction *TheCall = CS->getCallSite().getInstruction();
+
+    // If this is an indirect function call, assume nothing gets passed through
+    // it. FIXME: THIS IS BROKEN!  Just get the ECG for the fn ptr if it's not
+    // direct.
+    if (CS->isIndirectCall())
+      continue;
+
+    // If this is an external function call, it cannot be involved with this
+    // node, because otherwise the node would be marked incomplete!
+    if (CS->getCalleeFunc()->isExternal())
+      continue;
+
+    // If we can handle this function call, remove it from the set of direct
+    // calls found by the visitor.
+    CalleesHandled.insert(CS->getCalleeFunc());
+
+    std::vector<DSNodeHandle> Args;
+
+    DSGraph *CG = &ECG.getDSGraph(*CS->getCalleeFunc());
+    CG->getFunctionArgumentsForCall(CS->getCalleeFunc(), Args);
+
+    if (!CS->getRetVal().isNull())
+      DSGraph::computeNodeMapping(Args[0], CS->getRetVal(), CallNodeMap);
+    for (unsigned i = 0, e = CS->getNumPtrArgs(); i != e; ++i) {
+      if (i == Args.size()-1) break;
+      DSGraph::computeNodeMapping(Args[i+1], CS->getPtrArg(i), CallNodeMap);
+    }
+    Args.clear();
+
+    // The mapping we just computed maps from nodes in the callee to nodes in
+    // the caller, so we can't query it efficiently.  Instead of going through
+    // the trouble of inverting the map to do this (linear time with the size of
+    // the mapping), we just do a linear search to see if any affected nodes are
+    // passed into this call.
+    bool CallCanModifyDataFlow = false;
+    for (DSGraph::NodeMapTy::iterator MI = CallNodeMap.begin(),
+           E = CallNodeMap.end(); MI != E; ++MI)
+      if (NodeLVs.count(MI->second.getNode()))
+        // Okay, the node is passed in, check to see if the call might do
+        // something interesting to it (i.e. if analyzing the call can produce
+        // anything other than "top").
+        if ((CallCanModifyDataFlow = NodeCanPossiblyBeInteresting(MI->first,
+                                                                  Callbacks)))
+          break;
+
+    // If this function call cannot impact the analysis (either because the
+    // nodes we are tracking are not passed into the call, or the DSGraph for
+    // the callee tells us that analysis of the callee can't provide interesting
+    // information), ignore it.
+    if (!CallCanModifyDataFlow)
+      continue;
+
+    // Okay, either compute analysis results for the callee function, or reuse
+    // results previously computed.
+    std::multimap<DSNode*, LatticeValue*> &CalleeFacts = getCalleeFacts(*CG);
+
+    // Merge all of the facts for the callee into the facts for the caller.  If
+    // this reduces anything in the caller to 'bottom', remove them.
+    for (DSGraph::NodeMapTy::iterator MI = CallNodeMap.begin(),
+           E = CallNodeMap.end(); MI != E; ++MI) {
+      // If we have Lattice facts in the caller for this node in the callee,
+      // merge any information from the callee into the caller.
+
+      // If the node is not accessed in the callee at all, don't update.
+      if (MI->first->getType() == Type::VoidTy)
+        continue;
+
+      // If there are no data-flow facts live in the caller for this node, don't
+      // both processing it.
+      std::multimap<DSNode*, LatticeValue*>::iterator NLVI =
+        NodeLVs.find(MI->second.getNode());
+      if (NLVI == NodeLVs.end()) continue;
+          
+          
+      // Iterate over all of the lattice values that have corresponding fields
+      // in the callee, merging in information as we go.  Be careful about the
+      // fact that the callee may get passed the address of a substructure and
+      // other funny games.
+      //if (CalleeFacts.count(const_cast<DSNode*>(MI->first)) == 0) {
+
+      DSNode *CalleeNode = const_cast<DSNode*>(MI->first);
+
+      unsigned CalleeNodeOffset = MI->second.getOffset();
+      while (NLVI->first == MI->second.getNode()) {
+        // Figure out what offset in the callee this field would land.
+        unsigned FieldOff = NLVI->second->getFieldOffset()+CalleeNodeOffset;
+
+        // If the field is not within the callee node, ignore it.
+        if (FieldOff >= CalleeNode->getSize()) {
+          ++NLVI;
+          continue;
+        }
+
+        // Okay, check to see if we have a lattice value for the field at offset
+        // FieldOff in the callee node.
+        const LatticeValue *CalleeLV = 0;
+
+        std::multimap<DSNode*, LatticeValue*>::iterator CFI = 
+          CalleeFacts.lower_bound(CalleeNode);
+        for (; CFI != CalleeFacts.end() && CFI->first == CalleeNode; ++CFI)
+          if (CFI->second->getFieldOffset() == FieldOff) {
+            CalleeLV = CFI->second;   // Found it!
+            break;
+          }
+        
+        // If we don't, the lattice value hit bottom and we should remove the
+        // lattice value in the caller.
+        if (!CalleeLV) {
+          delete NLVI->second;   // The lattice value hit bottom.
+          NodeLVs.erase(NLVI++);
+          continue;
+        }
+
+        // Finally, if we did find a corresponding entry, merge the information
+        // into the caller's lattice value and keep going.
+        if (NLVI->second->mergeInValue(CalleeLV)) {
+          // Okay, merging these two caused the caller value to hit bottom.
+          // Remove it.
+          delete NLVI->second;   // The lattice value hit bottom.
+          NodeLVs.erase(NLVI++);
+        }
+
+        ++NLVI;  // We successfully merged in some information!
+      }
+
+      // If we ran out of facts to prove, just exit.
+      if (NodeLVs.empty()) return;
+    }
+  }
+
+  // The local analysis pass inconveniently discards many local function calls
+  // from the graph if they are to known functions.  Loop over direct function
+  // calls not handled above and visit them as appropriate.
+  while (!IV.DirectCallSites.empty()) {
+    Instruction *Call = *IV.DirectCallSites.begin();
+    IV.DirectCallSites.erase(IV.DirectCallSites.begin());
+
+    // Is this one actually handled by DSA?
+    if (CalleesHandled.count(cast<Function>(Call->getOperand(0))))
+      continue;
+
+    // Collect the pointers involved in this call.    
+    std::vector<Value*> Pointers;
+    if (isa<PointerType>(Call->getType()))
+      Pointers.push_back(Call);
+    for (unsigned i = 1, e = Call->getNumOperands(); i != e; ++i)
+      if (isa<PointerType>(Call->getOperand(i)->getType()))
+        Pointers.push_back(Call->getOperand(i));
+
+    // If this is an intrinsic function call, figure out which one.
+    unsigned IID = cast<Function>(Call->getOperand(0))->getIntrinsicID();
+
+    for (unsigned i = 0, e = Pointers.size(); i != e; ++i) {
+      // If any of our lattice values are passed into this call, which is
+      // specially handled by the local analyzer, inform the lattice function.
+      DSNode *N = DSG.getNodeForValue(Pointers[i]).getNode();
+      for (std::multimap<DSNode*, LatticeValue*>::iterator LVI =
+             NodeLVs.lower_bound(N); LVI != NodeLVs.end() && LVI->first == N;) {
+        bool AtBottom = false;
+        switch (IID) {
+        default:
+          AtBottom = LVI->second->visitRecognizedCall(*Call);
+          break;
+        case Intrinsic::memset:
+          if (Callbacks & Visit::Stores)
+            AtBottom = LVI->second->visitMemSet(*cast<CallInst>(Call));
+          break;
+        }
+
+        if (AtBottom) {
+          delete LVI->second;
+          NodeLVs.erase(LVI++);
+        } else {
+          ++LVI;
+        }
+      }
+    }
+  }
+}


Index: llvm-poolalloc/lib/Macroscopic/StructureFieldVisitor.h
diff -u /dev/null llvm-poolalloc/lib/Macroscopic/StructureFieldVisitor.h:1.6
--- /dev/null	Wed May 18 14:56:41 2005
+++ llvm-poolalloc/lib/Macroscopic/StructureFieldVisitor.h	Wed May 18 14:56:27 2005
@@ -0,0 +1,277 @@
+//===-- StructureFieldVisitor.h - Macroscopic DS inspector ------*- C++ -*-===//
+// 
+//                     The LLVM Compiler Infrastructure
+//
+// This file was developed by the LLVM research group and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+// 
+//===----------------------------------------------------------------------===//
+//
+// This file defines the public interface to the LatticeValue and
+// StructureFieldVisitor classes.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MACROSCOPIC_STRUCTUREFIELDVISITOR_H
+#define MACROSCOPIC_STRUCTUREFIELDVISITOR_H
+
+#include <set>
+#include <map>
+#include <vector>
+
+namespace llvm {
+  class Type;
+  class Constant;
+  class Instruction;
+  class LoadInst;
+  class CallInst;
+  class StoreInst;
+  class EquivClassGraphs;
+  class DSNode;
+  class DSGraph;
+
+namespace Macroscopic {
+
+/// FindAllDataStructures - Inspect the program specified by ECG, adding to
+/// 'Nodes' all of the data structures node in the program that contain the
+/// "IncludeFlags" and do not contain "ExcludeFlags" node flags.  If
+/// OnlyHomogenous is true, only type-homogenous nodes are considered.
+void FindAllDataStructures(std::set<DSNode*> &Nodes, unsigned IncludeFlags,
+                           unsigned ExcludeFlags, bool OnlyHomogenous,
+                           EquivClassGraphs &ECG);
+
+//===----------------------------------------------------------------------===//
+/// Visit types - This describes an enum specifying which methods are
+/// overloaded in the concrete implementation of the LatticeValue class.
+namespace Visit {
+  enum {
+    Loads = 1,
+    Stores = 2,
+    Allocs = 4,
+    Deallocs = 8,
+    // ...
+  };
+}
+
+//===----------------------------------------------------------------------===//
+/// LatticeValue - Describe.
+///
+class LatticeValue {
+  DSNode *Node;
+  std::vector<unsigned> Idxs;  // The index path to get to this field.
+  const Type *FieldTy;         // The type of this field.
+public:
+  LatticeValue(DSNode *N, const std::vector<unsigned> &I,
+               const Type *Ty) : Node(N), Idxs(I), FieldTy(Ty) {}
+  virtual ~LatticeValue() {}
+
+  DSNode *getNode() const { return Node; }
+  DSGraph &getParentGraph() const;
+
+  const std::vector<unsigned> &getIndices() const { return Idxs; }
+  const Type *getFieldType() const { return FieldTy; }
+
+  /// getFieldOffset - Get the byte offset of this field from the start of the
+  /// node.
+  ///
+  unsigned getFieldOffset() const;
+
+  /// dump - Print debugging information about this class.
+  ///
+  virtual void dump() const;
+
+  /// mergeInValue - Merge the information from the RHS lattice value (which is
+  /// guaranteed to be the same dynamic type as 'this') into this lattice value.
+  /// If the resultant value hits bottom, return true.  This is used for
+  /// interprocedural analysis.
+  ///
+  virtual bool mergeInValue(const LatticeValue *RHS) {
+    return true;
+  }
+  
+  //===--------------------------------------------------------------------===//
+  // Visitation methods - These methods update the current lattice state
+  // based on the information in the operation.  If the lattice value reaches
+  // bottom, the method implementation should return true so that analysis
+  // can be stopped as early as possible.  Visitation methods are grouped by
+  // their Visitation class.
+
+  // All lattice values must implement these.
+
+  /// visitRecognizedCall - The node for this lattice value is passed into some
+  /// external function that is "known" by the Local analysis pass (e.g. atoi).
+  /// By default, this stops any analysis of the node.
+  ///
+  virtual bool visitRecognizedCall(Instruction &I) {
+    return true;
+  }
+  
+  // Load Vistation methods.
+  virtual bool visitLoad(LoadInst &);
+
+  // Store Visitation methods.
+  virtual bool visitStore(StoreInst &);
+  virtual bool visitGlobalInit(Constant *InitVal);
+  virtual bool visitMemSet(CallInst &I) {
+    return visitRecognizedCall((Instruction&)I);
+  }
+};
+
+//===----------------------------------------------------------------------===//
+/// CombinedLatticeValue - Describe.
+///
+template<typename L1, typename L2>
+class CombinedLatticeValue : public LatticeValue {
+  L1 LV1; L2 LV2;
+  bool LV1Bottom, LV2Bottom;
+public:
+  CombinedLatticeValue(DSNode *Node, const std::vector<unsigned> &Idxs,
+                       const Type *FieldTy)
+    : LatticeValue(Node, Idxs, FieldTy), LV1(Node, Idxs, FieldTy),
+      LV2(Node, Idxs, FieldTy), LV1Bottom(false), LV2Bottom(false) {}
+      
+  static unsigned getInterestingEvents() {
+    return L1::getInterestingEvents() | L2::getInterestingEvents();
+  }
+
+  static CombinedLatticeValue *create(DSNode *Node,
+                                      const std::vector<unsigned> &Idxs,
+                                      const Type *FieldTy) {
+    return new CombinedLatticeValue(Node, Idxs, FieldTy);      
+  }
+
+  void dump() const {
+    if (!LV1Bottom) LV1.dump();
+    if (!LV2Bottom) LV2.dump();
+  }
+
+  virtual bool mergeInValue(const LatticeValue *RHSLV) {
+    const CombinedLatticeValue *RHS =
+      static_cast<const CombinedLatticeValue *>(RHSLV);
+    LV1Bottom |= RHS->LV1Bottom;
+    LV2Bottom |= RHS->LV2Bottom;
+    if (!LV1Bottom) LV1Bottom = LV1.mergeInValue(&RHS->LV1);
+    if (!LV2Bottom) LV2Bottom = LV2.mergeInValue(&RHS->LV2);
+    return LV1Bottom & LV2Bottom;
+  }
+  
+  virtual bool visitRecognizedCall(Instruction &I) {
+    if (!LV1Bottom) LV1Bottom = LV1.visitRecognizedCall(I);
+    if (!LV2Bottom) LV2Bottom = LV2.visitRecognizedCall(I);
+    return LV1Bottom & LV2Bottom;
+  }
+  
+  // Load Vistation methods.
+  virtual bool visitLoad(LoadInst &LI) {
+    if (!LV1Bottom && (L1::getInterestingEvents() & Visit::Loads))
+      LV1Bottom = LV1.visitLoad(LI);
+    if (!LV2Bottom && (L2::getInterestingEvents() & Visit::Loads))
+      LV2Bottom = LV2.visitLoad(LI);
+    return LV1Bottom & LV2Bottom;
+  }
+
+  // Store Visitation methods.
+  virtual bool visitStore(StoreInst &SI) {
+    if (!LV1Bottom && (L1::getInterestingEvents() & Visit::Stores))
+      LV1Bottom = LV1.visitStore(SI);
+    if (!LV2Bottom && (L2::getInterestingEvents() & Visit::Stores))
+      LV2Bottom = LV2.visitStore(SI);
+    return LV1Bottom & LV2Bottom;
+  }
+
+  virtual bool visitGlobalInit(Constant *InitVal) {
+    if (!LV1Bottom && (L1::getInterestingEvents() & Visit::Stores))
+      LV1Bottom = LV1.visitGlobalInit(InitVal);
+    if (!LV2Bottom && (L2::getInterestingEvents() & Visit::Stores))
+      LV2Bottom = LV2.visitGlobalInit(InitVal);
+    return LV1Bottom & LV2Bottom;
+  }
+
+  virtual bool visitMemSet(CallInst &I) {
+    if (!LV1Bottom && (L1::getInterestingEvents() & Visit::Stores))
+      LV1Bottom = LV1.visitMemSet(I);
+    if (!LV2Bottom && (L2::getInterestingEvents() & Visit::Stores))
+      LV2Bottom = LV2.visitMemSet(I);
+    return LV1Bottom & LV2Bottom;
+  }
+};
+
+
+//===----------------------------------------------------------------------===//
+/// StructureFieldVisitorBase - This implements all of the heavy lifting
+/// for the StructureFieldVisitor class.  This class should not be used
+/// directly, see it (below) for usage.
+///
+class StructureFieldVisitorBase {
+  unsigned Callbacks;     // Bitfield containing bits from Macroscopic::Visit
+  EquivClassGraphs &ECG;
+  
+  std::map<DSGraph*, std::multimap<DSNode*,LatticeValue*> > CalleeFnFacts;
+
+  // createLatticeValue - Provide a virtual ctor for the concrete lattice value.
+  virtual LatticeValue* createLatticeValue(DSNode *Node,
+                                           const std::vector<unsigned> &Idxs,
+                                           const Type *FieldTy) = 0;
+protected:
+  // Only allow this to be subclassed.
+  StructureFieldVisitorBase(unsigned CB, EquivClassGraphs &ecg)
+    : Callbacks(CB), ECG(ecg) {}
+  virtual ~StructureFieldVisitorBase() {}
+  
+  
+  std::set<LatticeValue*> visitNodes(const std::set<DSNode*> &Nodes);
+  void visitFields(std::set<LatticeValue*> &Fields);
+
+private:
+  void visitGraph(DSGraph &DSG, std::multimap<DSNode*, LatticeValue*> &NodeLVs);
+  std::multimap<DSNode*, LatticeValue*> &getCalleeFacts(DSGraph &DSG);
+
+  void AddLatticeValuesForFields(DSNode *N, const Type *Ty,
+                                 const std::vector<unsigned> &Idxs,
+                                 std::set<LatticeValue*> &Values);
+  void AddLatticeValuesForNode(DSNode *N, std::set<LatticeValue*> &Values);
+  void ProcessNodesReachableFromGlobals(DSGraph &DSG,
+                             std::multimap<DSNode*,LatticeValue*> &NodeLVs);
+
+};
+
+
+
+//===----------------------------------------------------------------------===//
+/// FIXME: Describe
+template<typename ConcLatticeVal>
+class StructureFieldVisitor : public StructureFieldVisitorBase {
+public:
+  // FIXME: We really want to be able to infer which methods LatticeVal
+  // overloads from the base class using template metaprogramming techniques.
+  StructureFieldVisitor(EquivClassGraphs &ECG)
+    : StructureFieldVisitorBase(ConcLatticeVal::getInterestingEvents(), ECG) {}
+
+  /// visit - Visit the specified set of data structure nodes, recursively
+  /// visiting all accesses to structure fields defined in those nodes.  This
+  /// method returns a set of lattice values that have not reached bottom.
+  std::set<ConcLatticeVal*> visit(const std::set<DSNode*> &Nodes) {
+    std::set<LatticeValue*> ResultVals = visitNodes(Nodes);
+
+    // Convert the result set to the appropriate lattice type.
+    std::set<ConcLatticeVal*> Result;
+    while (!ResultVals.empty()) {
+      Result.insert(static_cast<ConcLatticeVal*>(*ResultVals.begin()));
+      ResultVals.erase(ResultVals.begin());
+    }
+    return Result;
+  }
+
+
+private:  // Virtual method implementations for the base class.
+  virtual LatticeValue* createLatticeValue(DSNode *N,
+                                           const std::vector<unsigned> &Idxs,
+                                           const Type *FieldTy) {
+    return ConcLatticeVal::create(N, Idxs, FieldTy);
+  }
+};
+
+}  // End Macroscopic namespace
+}  // End llvm namespace
+
+#endif






More information about the llvm-commits mailing list