bool llvm::slicing::findInitialCriterion(Function &F,
                                         FunctionStaticSlicer &ss,
                                         bool starting) {
  bool added = false;
#ifdef DEBUG_INITCRIT
  errs() << __func__ << " ============ BEGIN\n";
#endif
  const Function *Fklee_assume = F.getParent()->getFunction("klee_assume");
  const Function *F__assert_fail = F.getParent()->getFunction("__assert_fail");
  if (!F__assert_fail) /* no cookies in this module */
    return false;

  for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) {
    const Instruction *i = &*I;
    if (const StoreInst *SI = dyn_cast<StoreInst>(i)) {
      const Value *LHS = SI->getPointerOperand();
     if (LHS->hasName() && LHS->getName().startswith("__ai_state_")) {
#ifdef DEBUG_INITCRIT
        errs() << "    adding\n";
#endif
        ss.addInitialCriterion(SI, ptr::PointsToSets::Pointee(LHS, -1));
     }
    } else if (const CallInst *CI = dyn_cast<CallInst>(i)) {
      Function *callie = CI->getCalledFunction();
      if (callie == F__assert_fail) {
	added = handleAssert(F, ss, CI);
      } else if (callie == Fklee_assume) { // this is kind of hack
	const Value *l = elimConstExpr(CI->getArgOperand(0));
	ss.addInitialCriterion(CI, ptr::PointsToSets::Pointee(l, -1));
      }
    } else if (const ReturnInst *RI = dyn_cast<ReturnInst>(i)) {
      if (starting) {
        const Module *M = F.getParent();
        for (Module::const_global_iterator II = M->global_begin(),
             EE = M->global_end(); II != EE; ++II) {
          const GlobalVariable &GV = *II;
          if (!GV.hasName() || !GV.getName().startswith("__ai_state_"))
            continue;
#ifdef DEBUG_INITCRIT
          errs() << "adding " << GV.getName() << " into " << F.getName() <<
              " to \n";
          RI->dump();
#endif
          ss.addInitialCriterion(RI, ptr::PointsToSets::Pointee(&GV, -1),
	      false);
        }
      }
    }
  }
#ifdef DEBUG_INITCRIT
  errs() << __func__ << " ============ END\n";
#endif
  return added;
}
bool llvm::slicing::findInitialCriterion(Function &F,
    FunctionStaticSlicer &ss,
    bool starting) {
  bool added = false;
#ifdef DEBUG_INITCRIT
  errs() << __func__ << " ============ BEGIN\n";
#endif

  for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) {
    const Instruction *i = &*I;
    i->dump();
    if (const StoreInst *SI = dyn_cast<StoreInst>(i)) {
      const Value *LHS = SI->getPointerOperand();
      if (LHS->hasName() && LHS->getName().startswith("product")) {
#ifdef DEBUG_INITCRIT
        errs() << "    adding\n";
#endif
        ss.addInitialCriterion(SI, LHS);
      }
    /* } else if (const CallInst *CI = dyn_cast<CallInst>(i)) {
      Function *callie = CI->getCalledFunction();
      if (callie == F__assert_fail) {
        added = handleAssert(F, ss, CI);
      }
      */
    } else if (const ReturnInst *RI = dyn_cast<ReturnInst>(i)) {
      if (starting) {
        const Module *M = F.getParent();
        for (Module::const_global_iterator II = M->global_begin(),
            EE = M->global_end(); II != EE; ++II) {
          const GlobalVariable &GV = *II;
          if (!GV.hasName() || !GV.getName().startswith("__ai_state_"))
            continue;
#ifdef DEBUG_INITCRIT
          errs() << "adding " << GV.getName() << " into " << F.getName() <<
            " to \n";
          RI->dump();
#endif
          ss.addInitialCriterion(RI, &GV, false);
        }
      }
    }
  }
#ifdef DEBUG_INITCRIT
  errs() << __func__ << " ============ END\n";
#endif
  return added;
}
bool llvm::slicing::handleCall(Function &F, FunctionStaticSlicer &ss,
		const CallInst *CI) {

  const char *ass_file = getenv("SLICE_ASSERT_FILE");
  const char *ass_line = getenv("SLICE_ASSERT_LINE");
  const ConstantExpr *fileArg = dyn_cast<ConstantExpr>(CI->getArgOperand(1));
  //const ConstantInt *lineArg = dyn_cast<ConstantInt>(CI->getArgOperand(2));
  const ConstantInt *lineArg = dyn_cast<ConstantInt>(CI->getArgOperand(1));

  if (ass_file && ass_line) {
    if (fileArg && fileArg->getOpcode() == Instruction::GetElementPtr &&
	lineArg) {
      const GlobalVariable *strVar =
	dyn_cast<GlobalVariable>(fileArg->getOperand(0));
      assert(strVar && strVar->hasInitializer());
      const ConstantDataArray *str =
	dyn_cast<ConstantDataArray>(strVar->getInitializer());
      assert(str && str->isCString());
      /* trim the NUL terminator */
      StringRef fileArgStr = str->getAsString().drop_back(1);
      const int ass_line_int = atoi(ass_line);

      errs() << "ASSERT at " << fileArgStr << ":" << lineArg->getValue() << "\n";

      if (fileArgStr.equals(ass_file) && lineArg->equalsInt(ass_line_int)) {
	errs() << "\tMATCH\n";
	goto count;
      }
    }
    ss.addSkipAssert(CI);
    return false;
  }

count:
#ifdef DEBUG_INITCRIT
        errs() << "    adding\n";
#endif
  ss.addInitialCriterion(CI,
      Pointee(F.getParent()->getGlobalVariable("__ai_init_functions", true), -1));
  // Add all the arguments of the call instruction
  for( int i = 0; i< CI->getNumArgOperands(); i++){
    ss.addInitialCriterion(CI, Pointee(CI->getArgOperand(i), -1));
  }
  return true;
}
static bool handleAssert(Function &F, FunctionStaticSlicer &ss,
    const CallInst *CI) {

  const char *ass_file = getenv("SLICE_ASSERT_FILE");
  const char *ass_line = getenv("SLICE_ASSERT_LINE");
  const ConstantExpr *fileArg = dyn_cast<ConstantExpr>(CI->getArgOperand(1));
  const ConstantInt *lineArg = dyn_cast<ConstantInt>(CI->getArgOperand(2));

  if (ass_file && ass_line) {
    if (fileArg && fileArg->getOpcode() == Instruction::GetElementPtr &&
        lineArg) {
      const GlobalVariable *strVar =
        dyn_cast<GlobalVariable>(fileArg->getOperand(0));
      assert(strVar && strVar->hasInitializer());
      const ConstantArray *str =
        dyn_cast<ConstantArray>(strVar->getInitializer());
      assert(str && str->isCString());
      /* trim the NUL terminator */
      StringRef tmpStr(str->getAsString());
      StringRef fileArgStr = tmpStr.substr(0,tmpStr.size() - 1);
      const int ass_line_int = atoi(ass_line);

      errs() << "ASSERT at " << fileArgStr << ":" << lineArg->getValue() << "\n";

      if (fileArgStr.equals(ass_file) && lineArg->equalsInt(ass_line_int)) {
        errs() << "\tMATCH\n";
        goto count;
      }
    }
    ss.addSkipAssert(CI);
    return false;
  }

count:
#ifdef DEBUG_INITCRIT
  errs() << "    adding\n";
#endif
  ss.addInitialCriterion(CI,
      F.getParent()->getGlobalVariable("__ai_init_functions", true));
  return true;
}