void InstrumentCalls::InstrumentCallsFunctor::postorder(Context ctx, AST_t node)
    {
        ScopeLink scope_link = ctx.scope_link;

        AST_t called_expression_tree = node.get_attribute(LANG_CALLED_EXPRESSION);
        AST_t arguments_tree = node.get_attribute(LANG_FUNCTION_ARGUMENTS);
        Expression called_expression(called_expression_tree, scope_link);

        // Only function-names are considered here
        if (!called_expression.is_id_expression())
        {
            // std::cerr << "Called expression is not an id expression" << std::endl;
            return;
        }

        IdExpression called_id_expression = called_expression.get_id_expression();

        if (!_instrument_filter.match(called_id_expression.prettyprint()))
            return;

        std::string shadow_function_name = 
            "_" + called_id_expression.mangle_id_expression() + "_instr";

        if (defined_shadows.find(shadow_function_name) == defined_shadows.end())
        {
            // The shadow has not been defined, define it here
            if (!define_shadow(called_id_expression, shadow_function_name))
            {
                // Ignore this shadow
                return;
            }
            defined_shadows.insert(shadow_function_name);
        }

        // Now replace the arguments
        Source replaced_arguments;

        replaced_arguments 
            << "\"" << node.get_file() << "\""
            << ","
            << node.get_line()
            ;

        if (arguments_tree.prettyprint() != "")
        {
            replaced_arguments << "," << arguments_tree.prettyprint(/*commas=*/true);
        }

        // Now create an expression tree
        Source shadow_function_call;
        shadow_function_call
            << shadow_function_name << "(" << replaced_arguments << ")"
            ;

        AST_t shadow_function_call_tree = 
            shadow_function_call.parse_expression(node, scope_link);

        node.replace(shadow_function_call_tree);
    }
void DeviceCUDA::replace_kernel_config(AST_t &kernel_call, ScopeLink sl)
{
	CUDA::KernelCall kcall(kernel_call, sl);

	Source new_kernel_call;
	Source new_config, new_param_list, nanos_stream_call;

	new_kernel_call << kcall.get_called_expression() << "<<<" << new_config << ">>>(" << new_param_list << ")";

	ObjectList<Expression> argument_list = kcall.get_argument_list();

	for (ObjectList<Expression>::iterator it = argument_list.begin();
			it != argument_list.end();
			it++)
	{
		new_param_list.append_with_separator(it->prettyprint(), ",");
	}

	nanos_stream_call << "nanos_get_kernel_execution_stream()";
	ObjectList<Expression> kernel_config = kcall.get_kernel_configuration();
	if (kernel_config.size() == 2)
	{
		new_config << kernel_config[0] << ","
				<< kernel_config[1] << ","
				<< "0, "
				<< nanos_stream_call;
	}
	else if (kernel_config.size() == 3)
	{
		new_config << kernel_config[0] << ","
				<< kernel_config[1] << ","
				<< kernel_config[2] << ","
				<< nanos_stream_call;
	}
	else if (kernel_config.size() == 4)
	{
		// Do nothing at the moment
	}
	else
	{
		internal_error("Code unreachable: a kernel call configuration must have between 2 and 4 parameters", 0);
	}

	AST_t expr = new_kernel_call.parse_expression(kernel_call, sl);
	kernel_call.replace(expr);
}
    void InstrumentCalls::MainWrapper::postorder(Context, AST_t node)
    {
        FunctionDefinition function_def(node, _sl);
        IdExpression function_name = function_def.get_function_name();

        Symbol function_symbol = function_name.get_symbol();
        Type function_type = function_symbol.get_type();

        ObjectList<std::string> parameters;

        Source main_declaration = function_type.get_declaration_with_parameters(function_symbol.get_scope(),
                "main", parameters);

        // "main" is always an unqualified name so this transformation is safe
        function_name.get_ast().replace_text("__instrumented_main");

        Source instrumented_main_declaration = function_type.get_declaration(function_symbol.get_scope(),
                "__instrumented_main");
        Source null_expr;

        C_LANGUAGE()
        {
            null_expr << "(void*)0";
        }
        CXX_LANGUAGE()
        {
            null_expr << "0";
        }

        Source new_main;
        new_main
            << instrumented_main_declaration << ";"
            << "pthread_mutex_t __mintaka_instr_global_lock;"
            << "int __mintaka_pthread_global_counter;"
            << main_declaration
            << "{"
            // Begin
            << "  pthread_mutex_init(&__mintaka_instr_global_lock, " <<  null_expr << ");"
            << "  __mintaka_pthread_global_counter = 0;"
            << "  mintaka_app_begin();"
            << "  mintaka_set_filebase(_p_1[0]);"
            << "  mintaka_thread_begin(1, ++__mintaka_pthread_global_counter);"
            << "  mintaka_state_run();"
            // Event definition
            << "  static const char* EVENT_CALL_USER_FUNCTION_DESCR = \"User function call\";"
            << "  const int EVENT_CALL_USER_FUNCTION = 60000018;"
            << "  mintaka_index_event(EVENT_CALL_USER_FUNCTION, EVENT_CALL_USER_FUNCTION_DESCR);"
            // Program
            << "  int __result = __instrumented_main(_p_0, _p_1);"
            // End
            << "  mintaka_thread_end();"
            << "  mintaka_app_end();"
            << "  mintaka_merge();"
            << "  mintaka_index_generate();"
            << "  return __result;"
            << "}"
            << node.prettyprint()
            ;

        AST_t new_main_tree = new_main.parse_global(function_def.get_ast(),
                function_def.get_scope_link());

        node.replace(new_main_tree);
    }