/*
 Copyright 2012 MINES ParisTech
 Copyright 2012 Silkan

 This file is part of PIPS.

 PIPS is free software: you can redistribute it and/or modify it
 under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 any later version.

 PIPS is distributed in the hope that it will be useful, but WITHOUT ANY
 WARRANTY; without even the implied warranty of MERCHANTABILITY or
 FITNESS FOR A PARTICULAR PURPOSE.

 See the GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with PIPS.  If not, see <http://www.gnu.org/licenses/>.

 */

/**
 * @file taskify.c
 * Task generation
 * @author Mehdi Amini <mehdi.amini@silkan.com>
 */

#ifdef HAVE_CONFIG_H
    #include "pips_config.h"
#endif
#include "genC.h"
#include "linear.h"
#include "ri.h"
#include "effects.h"
#include "ri-util.h"
#include "prettyprint.h"
#include "effects-util.h"
#include "gpu.h"
#include "accel-util.h"
#include "text.h"
#include "pipsdbm.h"
#include "pipsmake.h"
#include "resources.h"
#include "properties.h"
#include "misc.h"
#include "control.h"
#include "callgraph.h"
#include "effects-generic.h"
#include "effects-convex.h"
#include "preprocessor.h"
#include "expressions.h"
#include "text-util.h"
#include "parser_private.h"

static string get_next_task_name() {
  string prefix = (string)get_string_property("TASKIFY_TASK_PREFIX");
  string task_name = build_outline_name(prefix, entity_user_name(get_current_module_entity()));
  return task_name;
}

static bool loop_found_p(_UNUSED_ loop l, bool *found) {
  *found = true;
  return false;
}

bool taskify_statement(statement s) {
  bool contains_a_loop = false;
  if(!statement_loop_p(s)) {
    gen_context_recurse(s, &contains_a_loop, loop_domain, loop_found_p, gen_null2);
  }

  if( !contains_a_loop
      && !declaration_statement_p(s)
      && !return_statement_p(s)
      && !empty_statement_or_continue_p(s)
      && !statement_contains_user_call_p(s)) {
    ifdebug(2) {
      pips_debug(2,"Ouline statement into a new task : ");
      print_statement(s);
    }
    outliner(get_next_task_name(),CONS(statement,s,NIL));
    return false;
  }
  return true;
}

bool taskify(char * module_name) {

  statement module_stat = (statement)db_get_memory_resource(DBR_CODE,
                                                            module_name,
                                                            true);
  set_current_module_statement(module_stat);

  set_current_module_entity(local_name_to_top_level_entity(module_name));

  debug_on("TASKIFY_DEBUG_LEVEL");


  /* regions */
  string region = db_get_memory_resource(DBR_REGIONS, module_name, true);
  set_proper_rw_effects((statement_effects) region);
  set_cumulated_rw_effects((statement_effects) db_get_memory_resource(DBR_CUMULATED_EFFECTS,
                                                                      module_name,
                                                                      true));


  // Save the value of a property we are going to change locally:
  bool old_outline_independent_compilation_unit =
    get_bool_property("OUTLINE_INDEPENDENT_COMPILATION_UNIT");
  set_bool_property("OUTLINE_INDEPENDENT_COMPILATION_UNIT",false);

  /* Initialize set for each statement */
  gen_recurse(module_stat, statement_domain, taskify_statement, gen_null);

  // Restore the original property value:
  set_bool_property("OUTLINE_INDEPENDENT_COMPILATION_UNIT",
        old_outline_independent_compilation_unit);


  module_reorder(get_current_module_statement());
  DB_PUT_MEMORY_RESOURCE(DBR_CODE,
      module_name,
      module_stat);

  // We may have outline some code, so recompute the callees:
  DB_PUT_MEMORY_RESOURCE(DBR_CALLEES, module_name,
       compute_callees(get_current_module_statement()));


  debug_off();

  reset_proper_rw_effects();
  reset_current_module_statement();
  reset_current_module_entity();
  reset_cumulated_rw_effects();

  return true;
}

