InsInfo::InsInfo(const Instruction *i, const ptr::PointsToSets &PS,
                 const mods::Modifies &MOD) : ins(i), sliced(true) {
  typedef ptr::PointsToSets::PointsToSet PTSet;

  if (const LoadInst *LI = dyn_cast<const LoadInst>(i)) {
    addDEF(Pointee(i, -1));

    const Value *op = elimConstExpr(LI->getPointerOperand());
    if (isa<ConstantPointerNull>(op)) {
      errs() << "ERROR in analysed code -- reading from address 0 at " <<
        i->getParent()->getParent()->getName() << ":\n";
      i->print(errs());
    } else if (isa<ConstantInt>(op)) {
    } else {
      addREF(Pointee(op, -1));
      if (hasExtraReference(op)) {
	addREF(Pointee(op, 0));
      } else {
	const PTSet &S = getPointsToSet(op,PS);
	for (PTSet::const_iterator I = S.begin(), E = S.end(); I != E; ++I)
	  addREF(*I);
      }
    }
  } else if (const StoreInst *SI = dyn_cast<const StoreInst>(i)) {
    const Value *l = elimConstExpr(SI->getPointerOperand());
    if (isa<ConstantPointerNull>(l)) {
      errs() << "ERROR in analysed code -- writing to address 0 at " <<
        i->getParent()->getParent()->getName() << ":\n";
      i->print(errs());
    } else if (isa<ConstantInt>(l)) {
    } else {
      if (hasExtraReference(l)) {
        addDEF(Pointee(l, 0));
      } else {
        const PTSet &S = getPointsToSet(l, PS);

        for (PTSet::const_iterator I = S.begin(), E = S.end(); I != E; ++I)
          addDEF(*I);
      }

      if (!l->getType()->isIntegerTy())
        addREF(Pointee(l, -1));
      const Value *r = elimConstExpr(SI->getValueOperand());
      if (!hasExtraReference(r) && !isConstantValue(r))
        addREF(Pointee(r, -1));
    }
  } else if (const GetElementPtrInst *gep =
             dyn_cast<const GetElementPtrInst>(i)) {
    addDEF(Pointee(i, -1));

    addREF(Pointee(gep->getPointerOperand(), -1));

    for (unsigned i = 1, e = gep->getNumOperands(); i != e; ++i) {
      Value *op = gep->getOperand(i);
      if (!isConstantValue(op))
	addREF(Pointee(op, -1));
    }
  } else if (CallInst const* const C = dyn_cast<const CallInst>(i)) {
    const Value *cv = C->getCalledValue();

    if (isInlineAssembly(C)) {
     errs() << "ERROR: Inline assembler detected in " <<
          i->getParent()->getParent()->getName() << ", ignoring\n";
    } else if (isMemoryAllocation(cv)) {
      if (!isConstantValue(C->getArgOperand(0)))
	addREF(Pointee(C->getArgOperand(0), -1));
      addDEF(Pointee(i, -1));
    } else if (isMemoryDeallocation(cv)) {
    } else if (isMemoryCopy(cv) || isMemoryMove(cv) || isMemorySet(cv)) {
      const Value *len = elimConstExpr(C->getArgOperand(2));
      uint64_t lenConst = getSizeOfMem(len);

      const Value *l = elimConstExpr(C->getOperand(0));
      addDEFArray(PS, l, lenConst);
      addREF(Pointee(l, -1));

      const Value *r = elimConstExpr(C->getOperand(1));
      /* memset has a constant/variable there */
      if (isMemoryCopy(cv) || isMemoryMove(cv))
	addREFArray(PS, r, lenConst);
      addREF(Pointee(r, -1));

      /* memcpy/memset wouldn't work with len being 'undef' */
      if (!isConstantValue(len))
	addREF(Pointee(len, -1));
    } else {
      typedef std::vector<const llvm::Function *> CalledVec;

      /* did we miss something? */
      assert(!memoryManStuff(cv));

      if (const Function *F = dyn_cast<Function>(cv))
	handleVariousFuns(PS, C, F);
      else
	addREF(Pointee(cv, -1));

      CalledVec CV;
      getCalledFunctions(C, PS, std::back_inserter(CV));
      for (CalledVec::const_iterator f = CV.begin(); f != CV.end(); ++f) {
        mods::Modifies::mapped_type const& M = getModSet(*f, MOD);
        for (mods::Modifies::mapped_type::const_iterator v = M.begin();
             v != M.end(); ++v)
          addDEF(*v);
      }

      if (!callToVoidFunction(C))
          addDEF(Pointee(C, -1));
    }
  } else if (isa<const ReturnInst>(i)) {
  } else if (const BinaryOperator *BO = dyn_cast<const BinaryOperator>(i)) {
    addDEF(Pointee(i, -1));

    if (!isConstantValue(BO->getOperand(0)))
      addREF(Pointee(BO->getOperand(0), -1));
    if (!isConstantValue(BO->getOperand(1)))
      addREF(Pointee(BO->getOperand(1), -1));
  } else if (const CastInst *CI = dyn_cast<const CastInst>(i)) {
    addDEF(Pointee(i, -1));

    if (!hasExtraReference(CI->getOperand(0)))
      addREF(Pointee(CI->getOperand(0), -1));
  } else if (const AllocaInst *AI = dyn_cast<const AllocaInst>(i)) {
      addDEF(Pointee(AI, -1));
    if (!isConstantValue(AI->getArraySize()))
      addREF(Pointee(AI->getArraySize(), -1));
  } else if (const CmpInst *CI = dyn_cast<const CmpInst>(i)) {
    addDEF(Pointee(i, -1));

    if (!isConstantValue(CI->getOperand(0)))
      addREF(Pointee(CI->getOperand(0), -1));
    if (!isConstantValue(CI->getOperand(1)))
      addREF(Pointee(CI->getOperand(1), -1));
  } else if (const BranchInst *BI = dyn_cast<const BranchInst>(i)) {
    if (BI->isConditional() && !isConstantValue(BI->getCondition()))
      addREF(Pointee(BI->getCondition(), -1));
  } else if (const PHINode *phi = dyn_cast<const PHINode>(i)) {
    addDEF(Pointee(i, -1));

    for (unsigned k = 0; k < phi->getNumIncomingValues(); ++k)
      if (!isConstantValue(phi->getIncomingValue(k)))
        addREF(Pointee(phi->getIncomingValue(k), -1));
  } else if (const SwitchInst *SI = dyn_cast<SwitchInst>(i)) {
    if (!isConstantValue(SI->getCondition()))
      addREF(Pointee(SI->getCondition(), -1));
  } else if (const SelectInst *SI = dyn_cast<const SelectInst>(i)) {
      // TODO: THE FOLLOWING CODE HAS NOT BEEN TESTED YET

    addDEF(Pointee(i, -1));

    if (!isConstantValue(SI->getCondition()))
      addREF(Pointee(SI->getCondition(), -1));
    if (!isConstantValue(SI->getTrueValue()))
      addREF(Pointee(SI->getTrueValue(), -1));
    if (!isConstantValue(SI->getFalseValue()))
      addREF(Pointee(SI->getFalseValue(), -1));
  } else if (isa<const UnreachableInst>(i)) {
  } else if (const ExtractValueInst *EV = dyn_cast<const ExtractValueInst>(i)) {
      addDEF(Pointee(i, -1));
      addREF(Pointee(EV->getAggregateOperand(), -1));
  } else if (const InsertValueInst *IV = dyn_cast<const InsertValueInst>(i)) {
//      TODO THE FOLLOWING CODE HAS NOT BEEN TESTED YET

      const Value *r = IV->getInsertedValueOperand();
      addDEF(Pointee(IV->getAggregateOperand(), -1));
      if (!isConstantValue(r))
	addREF(Pointee(r, -1));
  } else {
    errs() << "ERROR: Unsupported instruction reached\n";
    i->print(errs());
  }
}
InsInfo::InsInfo(const Instruction *i, const ptr::PointsToSets &PS,
    const mods::Modifies &MOD) : ins(i), sliced(true) {
  typedef ptr::PointsToSets::PointsToSet PTSet;

  if (const LoadInst *LI = dyn_cast<const LoadInst>(i)) {
    addDEF(i);
    const Value *op = elimConstExpr(LI->getPointerOperand());
    if (isa<ConstantPointerNull>(op)) {
      errs() << "ERROR in analysed code -- reading from address 0 at " <<
        i->getParent()->getParent()->getName() << ":\n";
      i->print(errs());
    } else if (isa<ConstantInt>(op)) {
    } else {
      addREF(op);
      if (!hasExtraReference(op)) {
        const PTSet &S = getPointsToSet(op,PS);
        for (PTSet::const_iterator I = S.begin(), E = S.end(); I != E; ++I)
          addREF(*I);
      }
    }
  } else if (const StoreInst *SI = dyn_cast<const StoreInst>(i)) {
    const Value *l = elimConstExpr(SI->getPointerOperand());
    if (isa<ConstantPointerNull>(l)) {
      errs() << "ERROR in analysed code -- writing to address 0 at " <<
        i->getParent()->getParent()->getName() << ":\n";
      i->print(errs());
    } else if (isa<ConstantInt>(l)) {
    } else {
      if (hasExtraReference(l)) {
        addDEF(l);
      } else {
        const PTSet &S = getPointsToSet(l, PS);

        for (PTSet::const_iterator I = S.begin(), E = S.end(); I != E; ++I)
          addDEF(*I);
      }

      if (!l->getType()->isIntegerTy()) {
#ifdef DEBUG_INSTINFO
        errs() << " store inst add LHS " << l->getName() << " to reference ";
        l->getType()->dump();
        errs() << "\n";
#endif
//TODO: make the reference set strict for now
        addREF(l);
      }
      const Value *r = elimConstExpr(SI->getValueOperand());
      if (!hasExtraReference(r) && !isConstantValue(r)) {
         addREF(r);
#ifdef DEBUG_INSTINFO
        errs() << " store inst add RHS " << r->getName() << " to reference\n";
#endif
      }
    }
  } else if (const GetElementPtrInst *gep =
      dyn_cast<const GetElementPtrInst>(i)) {
    addDEF(i);

    addREF(gep->getPointerOperand());

    for (unsigned i = 1, e = gep->getNumOperands(); i != e; ++i) {
      Value *op = gep->getOperand(i);
      if (!isa<ConstantInt>(op))
        addREF(op);
    }
  } else if (CallInst const* const C = dyn_cast<const CallInst>(i)) {
    if (isa<IntrinsicInst>(C)) // skip intrinsic instruction
      return;
    const Value *cv = C->getCalledValue();

    if (isInlineAssembly(C)) {
      errs() << "ERROR: Inline assembler detected in " <<
        i->getParent()->getParent()->getName() << ", ignoring\n";
    } else if (isMemoryAllocation(cv)) {
      addDEF(i);
    } else if (isMemoryDeallocation(cv)) {
    } else if (isMemoryCopy(cv) || isMemoryMove(cv)) {
      const Value *l = elimConstExpr(C->getOperand(0));
      if (isPointerValue(l)) {
        const PTSet &L = getPointsToSet(l, PS);
        for (PTSet::const_iterator p = L.begin(); p != L.end(); ++p)
          addDEF(*p);
      }
      const Value *r = elimConstExpr(C->getOperand(1));
      const Value *len = elimConstExpr(C->getOperand(2));
      addREF(l);
      addREF(r);
      /* memcpy/memset wouldn't work with len being 'undef' */
      addREF(len);
      if (isPointerValue(r)) {
        const PTSet &R = getPointsToSet(r, PS);
        for (PTSet::const_iterator p = R.begin(); p != R.end(); ++p)
          addREF(*p);
      }
    } else if (!memoryManStuff(C)) {
      typedef std::vector<const llvm::Function *> CalledVec;
      CalledVec CV;
      getCalledFunctions(C, PS, std::back_inserter(CV));
      const Value *callie = C->getCalledValue();
#ifdef DEBUG_INSTINFO
      errs() << "CallInst ";
      C->dump();
#endif

      if (!isa<Function>(callie)) {
#ifdef DEBUG_INSTINFO
        errs() << "\tRef1: ";
        callie->dump();
#endif
        addREF(callie);
      }

      for (CalledVec::const_iterator f = CV.begin(); f != CV.end(); ++f) {
        mods::Modifies::mapped_type const& M = getModSet(*f, MOD);
        for (mods::Modifies::mapped_type::const_iterator v = M.begin();
            v != M.end(); ++v) {
#ifdef DEBUG_INSTINFO
          errs() << "\tDef1: ";
          (*v)->dump();
#endif
          addDEF(*v);
        }
      }

      unsigned argn = C->getNumArgOperands();
      for (unsigned arg = 0; arg < argn; arg++) {
        Value * argument = C->getArgOperand(arg);
#ifdef DEBUG_INSTINFO
        errs() << "\tRef2: ";
        argument->dump();
#endif
        if (isConstantValue(argument)) // skip constant arugment
          continue;
        addREF(argument);
      }

      if (!callToVoidFunction(C)) {
#ifdef DEBUG_INSTINFO
        errs() << "\tDef2: ";
        C->dump();
#endif
        addDEF(C);
      }
    }
  } else if (isa<const ReturnInst>(i)) {
  } else if (const BinaryOperator *BO = dyn_cast<const BinaryOperator>(i)) {
    addDEF(i);

    if (!isConstantValue(BO->getOperand(0)))
      addREF(BO->getOperand(0));
    if (!isConstantValue(BO->getOperand(1)))
      addREF(BO->getOperand(1));
  } else if (const CastInst *CI = dyn_cast<const CastInst>(i)) {
    addDEF(i);

    if (!hasExtraReference(CI->getOperand(0)))
      addREF(CI->getOperand(0));
  } else if (const AllocaInst *AI = dyn_cast<const AllocaInst>(i)) {
    addDEF(AI);
  } else if (const CmpInst *CI = dyn_cast<const CmpInst>(i)) {
    addDEF(i);

    if (!isConstantValue(CI->getOperand(0)))
      addREF(CI->getOperand(0));
    if (!isConstantValue(CI->getOperand(1)))
      addREF(CI->getOperand(1));
  } else if (const BranchInst *BI = dyn_cast<const BranchInst>(i)) {
    if (BI->isConditional() && !isConstantValue(BI->getCondition()))
      addREF(BI->getCondition());
  } else if (const PHINode *phi = dyn_cast<const PHINode>(i)) {
    addDEF(i);

    for (unsigned k = 0; k < phi->getNumIncomingValues(); ++k)
      if (!isConstantValue(phi->getIncomingValue(k)))
        addREF(phi->getIncomingValue(k));
  } else if (const SwitchInst *SI = dyn_cast<SwitchInst>(i)) {
    if (!isConstantValue(SI->getCondition()))
      addREF(SI->getCondition());
  } else if (const SelectInst *SI = dyn_cast<const SelectInst>(i)) {
    // TODO: THE FOLLOWING CODE HAS NOT BEEN TESTED YET

    addDEF(i);

    if (!isConstantValue(SI->getCondition()))
      addREF(SI->getCondition());
    if (!isConstantValue(SI->getTrueValue()))
      addREF(SI->getTrueValue());
    if (!isConstantValue(SI->getFalseValue()))
      addREF(SI->getFalseValue());
  } else if (isa<const UnreachableInst>(i)) {
  } else if (const ExtractValueInst *EV = dyn_cast<const ExtractValueInst>(i)) {
    addDEF(i);
    addREF(EV->getAggregateOperand());
  } else if (const InsertValueInst *IV = dyn_cast<const InsertValueInst>(i)) {
    //      TODO THE FOLLOWING CODE HAS NOT BEEN TESTED YET

    const Value *r = IV->getInsertedValueOperand();
    addDEF(IV->getAggregateOperand());
    if (!isConstantValue(r))
      addREF(r);
  } else {
    errs() << "ERROR: Unsupported instruction reached\n";
    i->print(errs());
  }
}