Exemplo n.º 1
0
// -----------------------------------------------------------------------------
Graph *SpanningTree::create_spanning_tree(Graph* g, Node* root) {
   if(root == NULL)
      throw std::runtime_error("create_spanning_tree NULL exception");

   Graph *t = new Graph(FLAG_DAG);
   NodeSet visited;
   NodeStack node_stack;
   node_stack.push(root);

   while(!node_stack.empty()) {
      Node* n = node_stack.top();
      node_stack.pop();
      visited.insert(n);
      Node* tree_node1 = t->add_node_ptr(n->_value);
     
      EdgePtrIterator* eit = n->get_edges();
      Edge* e;
      while((e = eit->next()) != NULL) {
         Node* inner_node = e->traverse(n);
         if(inner_node != NULL && visited.count(inner_node) == 0) {
            Node* tree_node2 = t->add_node_ptr(inner_node->_value);
            t->add_edge(tree_node1, tree_node2, e->weight, e->label);
            node_stack.push(inner_node);
            visited.insert(inner_node);
         } 
      }
      delete eit;
   }

   return t;
}
Exemplo n.º 2
0
std::pair<NodeSet,bool>
Liveness::getAllReachingDefsRecImpl(RegisterRef RefRR, NodeAddr<RefNode*> RefA,
      NodeSet &Visited, const NodeSet &Defs, unsigned Nest, unsigned MaxNest) {
  if (Nest > MaxNest)
    return { NodeSet(), false };
  // Collect all defined registers. Do not consider phis to be defining
  // anything, only collect "real" definitions.
  RegisterAggr DefRRs(PRI);
  for (NodeId D : Defs) {
    const auto DA = DFG.addr<const DefNode*>(D);
    if (!(DA.Addr->getFlags() & NodeAttrs::PhiRef))
      DefRRs.insert(DA.Addr->getRegRef(DFG));
  }

  NodeList RDs = getAllReachingDefs(RefRR, RefA, false, true, DefRRs);
  if (RDs.empty())
    return { Defs, true };

  // Make a copy of the preexisting definitions and add the newly found ones.
  NodeSet TmpDefs = Defs;
  for (NodeAddr<NodeBase*> R : RDs)
    TmpDefs.insert(R.Id);

  NodeSet Result = Defs;

  for (NodeAddr<DefNode*> DA : RDs) {
    Result.insert(DA.Id);
    if (!(DA.Addr->getFlags() & NodeAttrs::PhiRef))
      continue;
    NodeAddr<PhiNode*> PA = DA.Addr->getOwner(DFG);
    if (Visited.count(PA.Id))
      continue;
    Visited.insert(PA.Id);
    // Go over all phi uses and get the reaching defs for each use.
    for (auto U : PA.Addr->members_if(DFG.IsRef<NodeAttrs::Use>, DFG)) {
      const auto &T = getAllReachingDefsRecImpl(RefRR, U, Visited, TmpDefs,
                                                Nest+1, MaxNest);
      if (!T.second)
        return { T.first, false };
      Result.insert(T.first.begin(), T.first.end());
    }
  }

  return { Result, true };
}
Exemplo n.º 3
0
NodeSet Liveness::getAllReachingDefsRec(RegisterRef RefRR,
      NodeAddr<RefNode*> RefA, NodeSet &Visited, const NodeSet &Defs) {
  // Collect all defined registers. Do not consider phis to be defining
  // anything, only collect "real" definitions.
  RegisterSet DefRRs;
  for (const auto D : Defs) {
    const auto DA = DFG.addr<const DefNode*>(D);
    if (!(DA.Addr->getFlags() & NodeAttrs::PhiRef))
      DefRRs.insert(DA.Addr->getRegRef());
  }

  auto RDs = getAllReachingDefs(RefRR, RefA, true, DefRRs);
  if (RDs.empty())
    return Defs;

  // Make a copy of the preexisting definitions and add the newly found ones.
  NodeSet TmpDefs = Defs;
  for (auto R : RDs)
    TmpDefs.insert(R.Id);

  NodeSet Result = Defs;

  for (NodeAddr<DefNode*> DA : RDs) {
    Result.insert(DA.Id);
    if (!(DA.Addr->getFlags() & NodeAttrs::PhiRef))
      continue;
    NodeAddr<PhiNode*> PA = DA.Addr->getOwner(DFG);
    if (Visited.count(PA.Id))
      continue;
    Visited.insert(PA.Id);
    // Go over all phi uses and get the reaching defs for each use.
    for (auto U : PA.Addr->members_if(DFG.IsRef<NodeAttrs::Use>, DFG)) {
      const auto &T = getAllReachingDefsRec(RefRR, U, Visited, TmpDefs);
      Result.insert(T.begin(), T.end());
    }
  }

  return Result;
}
Exemplo n.º 4
0
/*
 * DeleteCFG()
 *  Remove one CFG.
 */
void DeleteCFG(GraphNode *Root)
{
    NodeVec VisitStack;
    NodeSet Visited;
    
    VisitStack.push_back(Root);
    while(VisitStack.size())
    {
        GraphNode *Parent = VisitStack.back();
        VisitStack.pop_back();
        
        if (Visited.count(Parent))
            continue;
        
        Visited.insert(Parent);
        NodeVec &Child = Parent->getSuccessor();
        for (int i = 0, e = Child.size(); i < e; i++)
            VisitStack.push_back(Child[i]);
    }

    for (NodeSet::iterator I = Visited.begin(), E = Visited.end(); I != E; I++)
        delete *I;
}
Exemplo n.º 5
0
void Liveness::computePhiInfo() {
  RealUseMap.clear();

  NodeList Phis;
  NodeAddr<FuncNode*> FA = DFG.getFunc();
  auto Blocks = FA.Addr->members(DFG);
  for (NodeAddr<BlockNode*> BA : Blocks) {
    auto Ps = BA.Addr->members_if(DFG.IsCode<NodeAttrs::Phi>, DFG);
    Phis.insert(Phis.end(), Ps.begin(), Ps.end());
  }

  // phi use -> (map: reaching phi -> set of registers defined in between)
  std::map<NodeId,std::map<NodeId,RegisterSet>> PhiUp;
  std::vector<NodeId> PhiUQ;  // Work list of phis for upward propagation.

  // Go over all phis.
  for (NodeAddr<PhiNode*> PhiA : Phis) {
    // Go over all defs and collect the reached uses that are non-phi uses
    // (i.e. the "real uses").
    auto &RealUses = RealUseMap[PhiA.Id];
    auto PhiRefs = PhiA.Addr->members(DFG);

    // Have a work queue of defs whose reached uses need to be found.
    // For each def, add to the queue all reached (non-phi) defs.
    SetVector<NodeId> DefQ;
    NodeSet PhiDefs;
    for (auto R : PhiRefs) {
      if (!DFG.IsRef<NodeAttrs::Def>(R))
        continue;
      DefQ.insert(R.Id);
      PhiDefs.insert(R.Id);
    }
    for (unsigned i = 0; i < DefQ.size(); ++i) {
      NodeAddr<DefNode*> DA = DFG.addr<DefNode*>(DefQ[i]);
      NodeId UN = DA.Addr->getReachedUse();
      while (UN != 0) {
        NodeAddr<UseNode*> A = DFG.addr<UseNode*>(UN);
        if (!(A.Addr->getFlags() & NodeAttrs::PhiRef))
          RealUses[getRestrictedRegRef(A)].insert(A.Id);
        UN = A.Addr->getSibling();
      }
      NodeId DN = DA.Addr->getReachedDef();
      while (DN != 0) {
        NodeAddr<DefNode*> A = DFG.addr<DefNode*>(DN);
        for (auto T : DFG.getRelatedRefs(A.Addr->getOwner(DFG), A)) {
          uint16_t Flags = NodeAddr<DefNode*>(T).Addr->getFlags();
          // Must traverse the reached-def chain. Consider:
          //   def(D0) -> def(R0) -> def(R0) -> use(D0)
          // The reachable use of D0 passes through a def of R0.
          if (!(Flags & NodeAttrs::PhiRef))
            DefQ.insert(T.Id);
        }
        DN = A.Addr->getSibling();
      }
    }
    // Filter out these uses that appear to be reachable, but really
    // are not. For example:
    //
    // R1:0 =          d1
    //      = R1:0     u2     Reached by d1.
    //   R0 =          d3
    //      = R1:0     u4     Still reached by d1: indirectly through
    //                        the def d3.
    //   R1 =          d5
    //      = R1:0     u6     Not reached by d1 (covered collectively
    //                        by d3 and d5), but following reached
    //                        defs and uses from d1 will lead here.
    auto HasDef = [&PhiDefs] (NodeAddr<DefNode*> DA) -> bool {
      return PhiDefs.count(DA.Id);
    };
    for (auto UI = RealUses.begin(), UE = RealUses.end(); UI != UE; ) {
      // For each reached register UI->first, there is a set UI->second, of
      // uses of it. For each such use, check if it is reached by this phi,
      // i.e. check if the set of its reaching uses intersects the set of
      // this phi's defs.
      auto &Uses = UI->second;
      for (auto I = Uses.begin(), E = Uses.end(); I != E; ) {
        auto UA = DFG.addr<UseNode*>(*I);
        NodeList RDs = getAllReachingDefs(UI->first, UA);
        if (std::any_of(RDs.begin(), RDs.end(), HasDef))
          ++I;
        else
          I = Uses.erase(I);
      }
      if (Uses.empty())
        UI = RealUses.erase(UI);
      else
        ++UI;
    }

    // If this phi reaches some "real" uses, add it to the queue for upward
    // propagation.
    if (!RealUses.empty())
      PhiUQ.push_back(PhiA.Id);

    // Go over all phi uses and check if the reaching def is another phi.
    // Collect the phis that are among the reaching defs of these uses.
    // While traversing the list of reaching defs for each phi use, collect
    // the set of registers defined between this phi (Phi) and the owner phi
    // of the reaching def.
    for (auto I : PhiRefs) {
      if (!DFG.IsRef<NodeAttrs::Use>(I))
        continue;
      NodeAddr<UseNode*> UA = I;
      auto &UpMap = PhiUp[UA.Id];
      RegisterSet DefRRs;
      for (NodeAddr<DefNode*> DA : getAllReachingDefs(UA)) {
        if (DA.Addr->getFlags() & NodeAttrs::PhiRef)
          UpMap[DA.Addr->getOwner(DFG).Id] = DefRRs;
        else
          DefRRs.insert(DA.Addr->getRegRef());
      }
    }
  }

  if (Trace) {
    dbgs() << "Phi-up-to-phi map:\n";
    for (auto I : PhiUp) {
      dbgs() << "phi " << Print<NodeId>(I.first, DFG) << " -> {";
      for (auto R : I.second)
        dbgs() << ' ' << Print<NodeId>(R.first, DFG)
               << Print<RegisterSet>(R.second, DFG);
      dbgs() << " }\n";
    }
  }

  // Propagate the reached registers up in the phi chain.
  //
  // The following type of situation needs careful handling:
  //
  //   phi d1<R1:0>  (1)
  //        |
  //   ... d2<R1>
  //        |
  //   phi u3<R1:0>  (2)
  //        |
  //   ... u4<R1>
  //
  // The phi node (2) defines a register pair R1:0, and reaches a "real"
  // use u4 of just R1. The same phi node is also known to reach (upwards)
  // the phi node (1). However, the use u4 is not reached by phi (1),
  // because of the intervening definition d2 of R1. The data flow between
  // phis (1) and (2) is restricted to R1:0 minus R1, i.e. R0.
  //
  // When propagating uses up the phi chains, get the all reaching defs
  // for a given phi use, and traverse the list until the propagated ref
  // is covered, or until or until reaching the final phi. Only assume
  // that the reference reaches the phi in the latter case.

  for (unsigned i = 0; i < PhiUQ.size(); ++i) {
    auto PA = DFG.addr<PhiNode*>(PhiUQ[i]);
    auto &RealUses = RealUseMap[PA.Id];
    for (auto U : PA.Addr->members_if(DFG.IsRef<NodeAttrs::Use>, DFG)) {
      NodeAddr<UseNode*> UA = U;
      auto &UpPhis = PhiUp[UA.Id];
      for (auto UP : UpPhis) {
        bool Changed = false;
        auto &MidDefs = UP.second;
        // Collect the set UpReached of uses that are reached by the current
        // phi PA, and are not covered by any intervening def between PA and
        // the upward phi UP.
        RegisterSet UpReached;
        for (auto T : RealUses) {
          if (!isRestricted(PA, UA, T.first))
            continue;
          if (!RAI.covers(MidDefs, T.first))
            UpReached.insert(T.first);
        }
        if (UpReached.empty())
          continue;
        // Update the set PRUs of real uses reached by the upward phi UP with
        // the actual set of uses (UpReached) that the UP phi reaches.
        auto &PRUs = RealUseMap[UP.first];
        for (auto R : UpReached) {
          unsigned Z = PRUs[R].size();
          PRUs[R].insert(RealUses[R].begin(), RealUses[R].end());
          Changed |= (PRUs[R].size() != Z);
        }
        if (Changed)
          PhiUQ.push_back(UP.first);
      }
    }
  }

  if (Trace) {
    dbgs() << "Real use map:\n";
    for (auto I : RealUseMap) {
      dbgs() << "phi " << Print<NodeId>(I.first, DFG);
      NodeAddr<PhiNode*> PA = DFG.addr<PhiNode*>(I.first);
      NodeList Ds = PA.Addr->members_if(DFG.IsRef<NodeAttrs::Def>, DFG);
      if (!Ds.empty()) {
        RegisterRef RR = NodeAddr<DefNode*>(Ds[0]).Addr->getRegRef();
        dbgs() << '<' << Print<RegisterRef>(RR, DFG) << '>';
      } else {
        dbgs() << "<noreg>";
      }
      dbgs() << " -> " << Print<RefMap>(I.second, DFG) << '\n';
    }
  }
}
Exemplo n.º 6
0
void Liveness::computePhiInfo() {
  RealUseMap.clear();

  NodeList Phis;
  NodeAddr<FuncNode*> FA = DFG.getFunc();
  NodeList Blocks = FA.Addr->members(DFG);
  for (NodeAddr<BlockNode*> BA : Blocks) {
    auto Ps = BA.Addr->members_if(DFG.IsCode<NodeAttrs::Phi>, DFG);
    Phis.insert(Phis.end(), Ps.begin(), Ps.end());
  }

  // phi use -> (map: reaching phi -> set of registers defined in between)
  std::map<NodeId,std::map<NodeId,RegisterAggr>> PhiUp;
  std::vector<NodeId> PhiUQ;  // Work list of phis for upward propagation.

  // Go over all phis.
  for (NodeAddr<PhiNode*> PhiA : Phis) {
    // Go over all defs and collect the reached uses that are non-phi uses
    // (i.e. the "real uses").
    RefMap &RealUses = RealUseMap[PhiA.Id];
    NodeList PhiRefs = PhiA.Addr->members(DFG);

    // Have a work queue of defs whose reached uses need to be found.
    // For each def, add to the queue all reached (non-phi) defs.
    SetVector<NodeId> DefQ;
    NodeSet PhiDefs;
    for (NodeAddr<RefNode*> R : PhiRefs) {
      if (!DFG.IsRef<NodeAttrs::Def>(R))
        continue;
      DefQ.insert(R.Id);
      PhiDefs.insert(R.Id);
    }

    // Collect the super-set of all possible reached uses. This set will
    // contain all uses reached from this phi, either directly from the
    // phi defs, or (recursively) via non-phi defs reached by the phi defs.
    // This set of uses will later be trimmed to only contain these uses that
    // are actually reached by the phi defs.
    for (unsigned i = 0; i < DefQ.size(); ++i) {
      NodeAddr<DefNode*> DA = DFG.addr<DefNode*>(DefQ[i]);
      // Visit all reached uses. Phi defs should not really have the "dead"
      // flag set, but check it anyway for consistency.
      bool IsDead = DA.Addr->getFlags() & NodeAttrs::Dead;
      NodeId UN = !IsDead ? DA.Addr->getReachedUse() : 0;
      while (UN != 0) {
        NodeAddr<UseNode*> A = DFG.addr<UseNode*>(UN);
        uint16_t F = A.Addr->getFlags();
        if ((F & (NodeAttrs::Undef | NodeAttrs::PhiRef)) == 0) {
          RegisterRef R = PRI.normalize(A.Addr->getRegRef(DFG));
          RealUses[R.Reg].insert({A.Id,R.Mask});
        }
        UN = A.Addr->getSibling();
      }
      // Visit all reached defs, and add them to the queue. These defs may
      // override some of the uses collected here, but that will be handled
      // later.
      NodeId DN = DA.Addr->getReachedDef();
      while (DN != 0) {
        NodeAddr<DefNode*> A = DFG.addr<DefNode*>(DN);
        for (auto T : DFG.getRelatedRefs(A.Addr->getOwner(DFG), A)) {
          uint16_t Flags = NodeAddr<DefNode*>(T).Addr->getFlags();
          // Must traverse the reached-def chain. Consider:
          //   def(D0) -> def(R0) -> def(R0) -> use(D0)
          // The reachable use of D0 passes through a def of R0.
          if (!(Flags & NodeAttrs::PhiRef))
            DefQ.insert(T.Id);
        }
        DN = A.Addr->getSibling();
      }
    }
    // Filter out these uses that appear to be reachable, but really
    // are not. For example:
    //
    // R1:0 =          d1
    //      = R1:0     u2     Reached by d1.
    //   R0 =          d3
    //      = R1:0     u4     Still reached by d1: indirectly through
    //                        the def d3.
    //   R1 =          d5
    //      = R1:0     u6     Not reached by d1 (covered collectively
    //                        by d3 and d5), but following reached
    //                        defs and uses from d1 will lead here.
    auto InPhiDefs = [&PhiDefs] (NodeAddr<DefNode*> DA) -> bool {
      return PhiDefs.count(DA.Id);
    };
    for (auto UI = RealUses.begin(), UE = RealUses.end(); UI != UE; ) {
      // For each reached register UI->first, there is a set UI->second, of
      // uses of it. For each such use, check if it is reached by this phi,
      // i.e. check if the set of its reaching uses intersects the set of
      // this phi's defs.
      NodeRefSet &Uses = UI->second;
      for (auto I = Uses.begin(), E = Uses.end(); I != E; ) {
        auto UA = DFG.addr<UseNode*>(I->first);
        // Undef flag is checked above.
        assert((UA.Addr->getFlags() & NodeAttrs::Undef) == 0);
        RegisterRef R(UI->first, I->second);
        NodeList RDs = getAllReachingDefs(R, UA);
        // If none of the reaching defs of R are from this phi, remove this
        // use of R.
        I = any_of(RDs, InPhiDefs) ? std::next(I) : Uses.erase(I);
      }
      UI = Uses.empty() ? RealUses.erase(UI) : std::next(UI);
    }

    // If this phi reaches some "real" uses, add it to the queue for upward
    // propagation.
    if (!RealUses.empty())
      PhiUQ.push_back(PhiA.Id);

    // Go over all phi uses and check if the reaching def is another phi.
    // Collect the phis that are among the reaching defs of these uses.
    // While traversing the list of reaching defs for each phi use, accumulate
    // the set of registers defined between this phi (PhiA) and the owner phi
    // of the reaching def.
    NodeSet SeenUses;

    for (auto I : PhiRefs) {
      if (!DFG.IsRef<NodeAttrs::Use>(I) || SeenUses.count(I.Id))
        continue;
      NodeAddr<PhiUseNode*> PUA = I;
      if (PUA.Addr->getReachingDef() == 0)
        continue;

      RegisterRef UR = PUA.Addr->getRegRef(DFG);
      NodeList Ds = getAllReachingDefs(UR, PUA, true, false, NoRegs);
      RegisterAggr DefRRs(PRI);

      for (NodeAddr<DefNode*> D : Ds) {
        if (D.Addr->getFlags() & NodeAttrs::PhiRef) {
          NodeId RP = D.Addr->getOwner(DFG).Id;
          std::map<NodeId,RegisterAggr> &M = PhiUp[PUA.Id];
          auto F = M.find(RP);
          if (F == M.end())
            M.insert(std::make_pair(RP, DefRRs));
          else
            F->second.insert(DefRRs);
        }
        DefRRs.insert(D.Addr->getRegRef(DFG));
      }

      for (NodeAddr<PhiUseNode*> T : DFG.getRelatedRefs(PhiA, PUA))
        SeenUses.insert(T.Id);
    }
  }

  if (Trace) {
    dbgs() << "Phi-up-to-phi map with intervening defs:\n";
    for (auto I : PhiUp) {
      dbgs() << "phi " << Print<NodeId>(I.first, DFG) << " -> {";
      for (auto R : I.second)
        dbgs() << ' ' << Print<NodeId>(R.first, DFG)
               << Print<RegisterAggr>(R.second, DFG);
      dbgs() << " }\n";
    }
  }

  // Propagate the reached registers up in the phi chain.
  //
  // The following type of situation needs careful handling:
  //
  //   phi d1<R1:0>  (1)
  //        |
  //   ... d2<R1>
  //        |
  //   phi u3<R1:0>  (2)
  //        |
  //   ... u4<R1>
  //
  // The phi node (2) defines a register pair R1:0, and reaches a "real"
  // use u4 of just R1. The same phi node is also known to reach (upwards)
  // the phi node (1). However, the use u4 is not reached by phi (1),
  // because of the intervening definition d2 of R1. The data flow between
  // phis (1) and (2) is restricted to R1:0 minus R1, i.e. R0.
  //
  // When propagating uses up the phi chains, get the all reaching defs
  // for a given phi use, and traverse the list until the propagated ref
  // is covered, or until reaching the final phi. Only assume that the
  // reference reaches the phi in the latter case.

  for (unsigned i = 0; i < PhiUQ.size(); ++i) {
    auto PA = DFG.addr<PhiNode*>(PhiUQ[i]);
    NodeList PUs = PA.Addr->members_if(DFG.IsRef<NodeAttrs::Use>, DFG);
    RefMap &RUM = RealUseMap[PA.Id];

    for (NodeAddr<UseNode*> UA : PUs) {
      std::map<NodeId,RegisterAggr> &PUM = PhiUp[UA.Id];
      RegisterRef UR = PRI.normalize(UA.Addr->getRegRef(DFG));
      for (const std::pair<NodeId,RegisterAggr> &P : PUM) {
        bool Changed = false;
        const RegisterAggr &MidDefs = P.second;

        // Collect the set PropUp of uses that are reached by the current
        // phi PA, and are not covered by any intervening def between the
        // currently visited use UA and the the upward phi P.

        if (MidDefs.hasCoverOf(UR))
          continue;

        // General algorithm:
        //   for each (R,U) : U is use node of R, U is reached by PA
        //     if MidDefs does not cover (R,U)
        //       then add (R-MidDefs,U) to RealUseMap[P]
        //
        for (const std::pair<RegisterId,NodeRefSet> &T : RUM) {
          RegisterRef R = DFG.restrictRef(RegisterRef(T.first), UR);
          if (!R)
            continue;
          for (std::pair<NodeId,LaneBitmask> V : T.second) {
            RegisterRef S = DFG.restrictRef(RegisterRef(R.Reg, V.second), R);
            if (!S)
              continue;
            if (RegisterRef SS = MidDefs.clearIn(S)) {
              NodeRefSet &RS = RealUseMap[P.first][SS.Reg];
              Changed |= RS.insert({V.first,SS.Mask}).second;
            }
          }
        }

        if (Changed)
          PhiUQ.push_back(P.first);
      }
    }
  }

  if (Trace) {
    dbgs() << "Real use map:\n";
    for (auto I : RealUseMap) {
      dbgs() << "phi " << Print<NodeId>(I.first, DFG);
      NodeAddr<PhiNode*> PA = DFG.addr<PhiNode*>(I.first);
      NodeList Ds = PA.Addr->members_if(DFG.IsRef<NodeAttrs::Def>, DFG);
      if (!Ds.empty()) {
        RegisterRef RR = NodeAddr<DefNode*>(Ds[0]).Addr->getRegRef(DFG);
        dbgs() << '<' << Print<RegisterRef>(RR, DFG) << '>';
      } else {
        dbgs() << "<noreg>";
      }
      dbgs() << " -> " << Print<RefMap>(I.second, DFG) << '\n';
    }
  }
}
PointerAnalysis::ArgumentAttributes 
PointerAnalysis::objectPass(Function *funct, PointerAnalysis::ArgumentAttributes argAttrs)
{
	ArgumentAttributes ret(1);
	ret[0] = UNBOUND_ATTR;
	ArgumentAttributes UNBOUND(1);
	ret[0] = UNBOUND_ATTR;

	WorkList<Node> worklist;
	NodeSet visits;
	ValueMap exactOut, boundOut;

	ValueSet exactArgs, boundArgs;
	BoundMap exactBounds;
	
	llvm::DataLayout DL(module);

	// how to test no funct body?
	if (funct->begin() == funct->end())
		return ret;

	for (auto &globalVal: module->globals()) {
		GlobalVariable *gv = dyn_cast<GlobalVariable>(&globalVal);
		exactBounds[gv] = globalBounds[gv];
	}

	auto args = funct->arg_begin();
	for (size_t i = 0; i < funct->arg_size(); i++) {
		if (argAttrs[i] == UNBOUND_ATTR) {
			++args;
			continue;
		}

		Value *arg = &(*args);
		boundArgs.insert( arg );
		if (argAttrs[i] != DYNBOUND_ATTR) {
			exactArgs.insert( arg );
			exactBounds[arg] = argAttrs[i];
		}
		++args;
	}
	
	outs() << "********** visiting " << funct->getName() << " **********\n";
	printX(argAttrs);
	printX(exactArgs);
	printX(boundArgs);

	Node entry = &funct->getEntryBlock();
	worklist.enqueue(entry);

	std::unordered_set<Node> exits;
	for (auto &bb: *funct)
		if ( llvm::succ_begin(&bb) == llvm::succ_end(&bb) )
			exits.insert(&bb);

	while (!worklist.empty()) {
		Node next = worklist.dequeue();
		bool changed = false;
	
		bool visited = (visits.count(next) != 0);
		visits.insert(next);

		outs() << "visiting " << next->getName() << "\n";

		ValueSet oldExact = getOrInsert(next, exactOut), oldBound = getOrInsert(next, boundOut);
		ValueSet exactTemp, boundTemp;

		if (next == entry) {
			exactTemp = merge( exactTemp, exactArgs );
			exactTemp = merge( exactTemp, globals );
			boundTemp = merge( boundTemp, boundArgs );
			boundTemp = merge( boundTemp, globals );
		} else {
			for (auto i = pred_begin(next); i != pred_end(next); ++i) {
				exactTemp = merge( exactTemp, getOrInsert(*i, exactOut) );
				boundTemp = merge( boundTemp, getOrInsert(*i, boundOut) );
			}
		}

		for (auto &i : *next) {
			Instruction *inst = &i;

			if (isa<CallInst>(inst)) {
				// do inter-procedual analysis
				// what if I am calling some external library: handle that either
				// if (is a well-known exteral function) {
					// some external library
					// analyze it at best effort
				// } else {
					// not an external function
					// compare the args to the last time we enter this callsite
					// if they are the same, skip (TODO: pull out what we've got last time)
					// otherwise analyze it again
				// }

				CallInst *call_inst = dyn_cast<CallInst> (inst);
				Function *callee = call_inst->getCalledFunction();
				if (callee == nullptr)
					continue;

				if (isExternalLibrary(inst)) {
					bool isAlloca = isAllocation(inst);
					int allocaSize = getConstantAllocSize(inst);
					if (isAlloca) {
						boundTemp.insert(inst);
						if (allocaSize) {
							exactTemp.insert(inst);
							exactBounds[inst] = allocaSize;
						}
					}

					if (isaPointer(inst)) {
						if ( lookupName(retArg0Funcs, callee->getName().data()) ) {
							Value *arg0 = call_inst->getArgOperand(0);
							if (test(arg0, boundTemp)) {
								boundTemp.insert(inst);
							}
							if (test(arg0, exactTemp)) {
								exactTemp.insert(inst);
								exactBounds[inst] = exactBounds[arg0];
							}
						}

						if ( lookupName(retArg1Funcs, callee->getName().data()) ) {
							Value *arg1 = call_inst->getArgOperand(1);
							if (test(arg1, boundTemp)) {
								boundTemp.insert(inst);
							}
							if (test(arg1, exactTemp)) {
								exactTemp.insert(inst);
								exactBounds[inst] = exactBounds[arg1];
							}
						}

						if ( lookupName(retArg2Funcs, callee->getName().data()) ) {
							Value *arg2 = call_inst->getArgOperand(2);
							if (test(arg2, boundTemp)) {
								boundTemp.insert(inst);
							}
							if (test(arg2, exactTemp)) {
								exactTemp.insert(inst);
								exactBounds[inst] = exactBounds[arg2];
							}
						}
					}

				} else if ( !callee->isVarArg()) {
					bool first = (callsites.count(call_inst) == 0);
					
					callsites.insert(call_inst);
					auto oldArgs = argsCall[call_inst];
					
					ArgumentAttributes args(call_inst->getNumArgOperands());
					for (unsigned i = 0; i < call_inst->getNumArgOperands(); i++) {
						Value *argi = call_inst->getArgOperand(i);
						if (exactTemp.count(argi))
							args[i] = exactBounds[argi];
						else if (boundTemp.count(argi))
							args[i] = DYNBOUND_ATTR;
						else
							args[i] = UNBOUND_ATTR;
							
					}

					outs() << ">>> begin call\n";
					bool changed = first || ( unEqual(args, oldArgs) );
					ArgumentAttributes r;
					if (changed) {
						argsCall[call_inst] = args;
						retCall[call_inst] = UNBOUND;

						r = objectPass(callee, args);
						retCall[call_inst] = r;
					} else {
						r = retCall[call_inst];
					}

					assert("r must have size 1" && r.size() == 1);
					outs() << ">>> return from call\n";

					if (r[0] == DYNBOUND_ATTR)
						boundTemp.insert( inst );
					else if (r[0] != UNBOUND_ATTR) {
						boundTemp.insert( inst );
						exactTemp.insert( inst );
						exactBounds[inst] = r[0];
					}
				}				

				continue;
				
			}
			
			if (!isaPointer(inst))
				continue;

			Type* deRefTy = inst->getType()->getContainedType(0);
			uint64_t deBound = sizeOf(deRefTy, DL);

			// handle a Pointer
			if ( isa<AllocaInst>(inst) ) {
				AllocaInst *alloca_inst = dyn_cast<AllocaInst>(inst);
				Type *allocatedTy = alloca_inst->getAllocatedType();
				uint64_t stride = sizeOf(allocatedTy, DL);
				uint64_t length = getAllocaArraySize(alloca_inst);
				boundTemp.insert(inst);
				if (length) {
					exactTemp.insert(inst);
					exactBounds[inst] = stride * length;
				}
				
			}

			if ( isa<PHINode>(inst) ) {
				// possibly an inbound, but never transitive
				const PHINode *phi = dyn_cast<PHINode>(inst);
				bool allInbound = true;
				for (unsigned i = 0; i < phi->getNumIncomingValues(); i++) {
					Value *iv = phi->getIncomingValue(i);
					if (!test(iv, boundTemp)) {
						allInbound = false;
						break;
					}
				}
				if (allInbound) {
					boundTemp.insert(inst);
				}
				
			}

			if ( isa<GetElementPtrInst>(inst) ) {
				// inbound && exact && offset in range => inbound && transitive
				GetElementPtrInst *gep_inst = dyn_cast<GetElementPtrInst>(inst);
				Value *basePtr = gep_inst->getPointerOperand();
				uint64_t origBound = exactBounds[basePtr];
				APInt offset(64, false);
				bool testB = test(basePtr, boundTemp);
				bool testE = test(basePtr, exactTemp);
				bool testC = gep_inst->accumulateConstantOffset(DL, offset);
				// should I convert to byte count? A: NO.
				uint64_t intOff = offset.getLimitedValue();
				// outs() << "getelementptr: " << inst->getName() << ", offset=" << intOff << "\n";
				bool testR = testC && (origBound > 0) && (intOff + deBound <= origBound);
				if ( testB && testE && testR ) {
					boundTemp.insert(inst);
					exactTemp.insert(inst);
					exactBounds[inst] = exactBounds[basePtr] - (intOff);
				}
			}

			if ( isa<CastInst>(inst) ) {
				// inbound && transitive && bound decreased => inbound && transitive
				CastInst *cast_inst = dyn_cast<CastInst>(inst);
				if (cast_inst->getSrcTy()->isPointerTy()) {
					Value *srcPtr = cast_inst->getOperand(0);
					bool testB = test(srcPtr, boundTemp);
					bool testE = test(srcPtr, exactTemp);
					uint64_t origBound = exactBounds[srcPtr];
					bool testR = (origBound > 0) && (deBound <= origBound);
					if ( testB && testE && testR ) {
						boundTemp.insert(inst);
						exactTemp.insert(inst);
						exactBounds[inst] = origBound;
					}
				}
			
			}

			// TODO: handle load/store
			// default case: nothing change
		}
			
		changed = !visited || unEqual(exactTemp, oldExact) || unEqual(boundTemp, oldBound);

		if (changed) {
			for (auto i = succ_begin(next); i != succ_end(next); ++i) {
				worklist.enqueue(*i);
			}
		}

		exactOut[next] = exactTemp;
		boundOut[next] = boundTemp;
	}

	ArgumentAttributes retSet(exits.size());
	bool hasUnbound = false, hasDynbound = false;
	outs() << "<<< " << funct->getName() << " Returns :\n";
	int i = 0;
	for (auto bb: exits) {
		outs() << bb->getName() << ":\t";
		joinWith(boundOut[bb], funct);
		printX(boundOut[bb]);

		Instruction *term_inst = bb->getTerminator();
		ReturnInst *ret_inst = dyn_cast<ReturnInst>(term_inst);
		if (ret_inst != nullptr) {
			Value *retVal = ret_inst->getReturnValue();
			if ( retVal == nullptr || (!exactOut[bb].count(retVal) && !boundOut[bb].count(retVal)) ) {
				hasUnbound = true;
				break;
			}

			if (exactOut[bb].count(retVal))
				retSet[i++] = exactBounds[retVal];
			else {
				retSet[i++] = DYNBOUND_ATTR;
				hasDynbound = true;
			}
		}
	}
	outs() << "<<<\n";

	ArgumentAttribute ret0 = retSet[0];
	for (int i = 0; i < retSet.size(); i++)
		if (retSet[i] != ret0)
			hasDynbound = true;

	if (hasUnbound)
		ret[0] = UNBOUND_ATTR;
	else if (hasDynbound)
		ret[0] = DYNBOUND_ATTR;
	else {
		ret[0] = ret0;
	}

	if (!funct->getReturnType()->isPointerTy()) {
		//assert( "If is not pointer muxt be unbound" &&
		//	(ret[0] == UNBOUND_ATTR) );
		ret[0] = UNBOUND_ATTR;
	}

	printX(ret);

	return ret;
}