Ejemplo n.º 1
0
void goto_inlinet::expand_function_call(
  goto_programt &dest,
  goto_programt::targett &target,
  const exprt &lhs,
  const exprt &function,
  const exprt::operandst &arguments,
  const exprt &constrain,
  bool full)
{
  // look it up
  if(function.id()!="symbol")
  {
    err_location(function);
    throw "function_call expects symbol as function operand, "
          "but got `"+function.id_string()+"'";
  }
  
  const irep_idt &identifier=function.identifier();
  
  // see if we are already expanding it
  if(recursion_set.find(identifier)!=recursion_set.end())
  {
    if(!full)
    {
      target++;
      return; // simply ignore, we don't do full inlining, it's ok
    }

    // it's really recursive. Uh. Buh. Give up.
    err_location(function);
    warning("recursion is ignored");
    target->make_skip();
    
    target++;
    return;
  }

  goto_functionst::function_mapt::iterator m_it=
    goto_functions.function_map.find(identifier);

  if(m_it==goto_functions.function_map.end())
  {
    err_location(function);
    str << "failed to find function `" << identifier
        << "'";
    throw 0;
  }
  
  goto_functiont &f=m_it->second;

  // see if we need to inline this  
  if(!full)
  {
    if(!f.body_available ||
       (!f.is_inlined() && f.body.instructions.size() > smallfunc_limit))
    {
      target++;
      return;
    }
  }

  if(f.body_available)
  {
    inlined_funcs.insert(identifier.as_string());
    for (std::set<std::string>::const_iterator it2 = f.inlined_funcs.begin();
         it2 != f.inlined_funcs.end(); it2++) {
      inlined_funcs.insert(*it2);
    }

    recursion_sett::iterator recursion_it=
      recursion_set.insert(identifier).first;  
  
    goto_programt tmp2;
    tmp2.copy_from(f.body);
    
    assert(tmp2.instructions.back().is_end_function());
    tmp2.instructions.back().type=LOCATION;
    
    replace_return(tmp2, lhs, constrain);
    
    goto_programt tmp;
    parameter_assignments(tmp2.instructions.front().location, f.type, arguments, tmp);
    tmp.destructive_append(tmp2);
    
    // set local variables
    Forall_goto_program_instructions(it, tmp)
      it->local_variables.insert(target->local_variables.begin(),
                                 target->local_variables.end());

    if(f.type.hide())
    {
      const locationt &new_location=function.find_location();
    
      Forall_goto_program_instructions(it, tmp)
      {
        if(new_location.is_not_nil())
        {
          // can't just copy, e.g., due to comments field
          it->location.id(""); // not NIL
          it->location.set_file(new_location.get_file());
          it->location.set_line(new_location.get_line());
          it->location.set_column(new_location.get_column());
          it->location.set_function(new_location.get_function());
        }
      }
    }

    // do this recursively
    goto_inline_rec(tmp, full);

    // set up location instruction for function call  
    target->type=LOCATION;
    target->code = expr2tc();
    
    goto_programt::targett next_target(target);
    next_target++;

    dest.instructions.splice(next_target, tmp.instructions);
    target=next_target;

    recursion_set.erase(recursion_it);
  }
Ejemplo n.º 2
0
void goto_inlinet::expand_function_call(
  goto_programt &dest,
  goto_programt::targett &target,
  const exprt &lhs,
  const symbol_exprt &function,
  const exprt::operandst &arguments,
  const exprt &constrain,
  bool full)
{
  // look it up
  const irep_idt identifier=function.get_identifier();
  
  // we ignore certain calls
  if(identifier=="__CPROVER_cleanup" ||
     identifier=="__CPROVER_set_must" ||
     identifier=="__CPROVER_set_may" ||
     identifier=="__CPROVER_clear_must" ||
     identifier=="__CPROVER_clear_may" ||
     identifier=="__CPROVER_cover")
  {
    target++;
    return; // ignore
  }
  
  // see if we are already expanding it
  if(recursion_set.find(identifier)!=recursion_set.end())
  {
    if(!full)
    {
      target++;
      return; // simply ignore, we don't do full inlining, it's ok
    }

    // it's really recursive, and we need full inlining.
    // Uh. Buh. Give up.
    warning().source_location=function.find_source_location();
    warning() << "recursion is ignored" << eom;
    target->make_skip();
    
    target++;
    return;
  }

  goto_functionst::function_mapt::iterator m_it=
    goto_functions.function_map.find(identifier);

  if(m_it==goto_functions.function_map.end())
  {
    if(!full)
    {
      target++;
      return; // simply ignore, we don't do full inlining, it's ok
    }

    error().source_location=function.find_source_location();
    error() << "failed to find function `" << identifier << "'" << eom;
    throw 0;
  }
  
  const goto_functionst::goto_functiont &f=m_it->second;

  // see if we need to inline this  
  if(!full)
  {
    if(!f.body_available() ||
       (!f.is_inlined() && f.body.instructions.size() > smallfunc_limit))
    {
      target++;
      return;
    }
  }

  if(f.body_available())
  {
    recursion_set.insert(identifier);

    // first make sure that this one is already inlined
    goto_inline_rec(m_it, full);

    goto_programt tmp2;
    tmp2.copy_from(f.body);
    
    assert(tmp2.instructions.back().is_end_function());
    tmp2.instructions.back().type=LOCATION;
    
    replace_return(tmp2, lhs, constrain);

    goto_programt tmp;
    parameter_assignments(target->source_location, identifier, f.type, arguments, tmp);
    tmp.destructive_append(tmp2);
    parameter_destruction(target->source_location, identifier, f.type, tmp);

    if(f.is_hidden())
    {
      source_locationt new_source_location=
        function.find_source_location();
    
      if(new_source_location.is_not_nil())
      {
        new_source_location.set_hide();
      
        Forall_goto_program_instructions(it, tmp)
        {
          if(it->function==identifier)
          {
            // don't hide assignment to lhs
            if(it->is_assign() && to_code_assign(it->code).lhs()==lhs)
            {
            }
            else
            {
              replace_location(it->source_location, new_source_location);
              replace_location(it->guard, new_source_location);
              replace_location(it->code, new_source_location);
            }

            it->function=target->function;
          }
        }
      }