vector<Value*> AssertionSiteInstrumenter::CollectArgs(
    Instruction *Before, const Automaton& A,
    Module& Mod, IRBuilder<>& Builder) {

  // Find named values to be passed to instrumentation.
  std::map<string,Value*> ValuesInScope;
  for (auto G = Mod.global_begin(); G != Mod.global_end(); G++)
    ValuesInScope[G->getName()] = G;

  auto *Fn = Before->getParent()->getParent();
  for (auto& Arg : Fn->getArgumentList())
    ValuesInScope[Arg.getName()] = &Arg;

  auto& EntryBlock(*Fn->begin());
  for (auto& I : EntryBlock) {
    auto *Inst = dyn_cast<AllocaInst>(&I);
    if (!Inst)
      break;

    ValuesInScope[Inst->getName()] = Builder.CreateLoad(Inst);
  }

  int ArgSize = 0;
  for (auto& Arg : A.getAssertion().argument())
    if (!Arg.free())
      ArgSize = std::max(ArgSize + 1, Arg.index());

  vector<Value*> Args(ArgSize, NULL);

  for (auto& Arg : A.getAssertion().argument()) {
    if (Arg.free())
      continue;

    string Name(BaseName(Arg));

    if (ValuesInScope.find(Name) == ValuesInScope.end()) {
      string s;
      raw_string_ostream Out(s);

      for (auto v : ValuesInScope) {
        Out << "  \"" << v.first << "\": ";
        v.second->getType()->print(Out);
        Out << "\n";
      }

      panic("assertion references non-existent variable '" + BaseName(Arg)
         + "'; was it defined under '#ifdef TESLA'?\n\n"
           "Variables in scope are:\n" + Out.str());
    }

    Args[Arg.index()] =
      GetArgumentValue(ValuesInScope[Name], Arg, Builder, true);
  }

  return Args;
}
void EventTranslator::CallUpdateState(const Automaton& A, uint32_t Symbol) {
  std::vector<Value*> Args;
  Args.push_back(InstrCtx.TeslaContext(A.getAssertion().context()));
  Args.push_back(InstrCtx.ExternalDescription(A));
  Args.push_back(ConstantInt::get(InstrCtx.Int32Ty, Symbol));
  Args.push_back(Key);

  Builder.CreateCall(InstrCtx.UpdateStateFn(), Args);
}