Пример #1
0
    // We redefine the visitor of Nodecl::FunctionCode because  we need to
    // visit first the internal functions and later the statements
    void LoweringVisitor::visit(const Nodecl::FunctionCode& function_code)
    {
        Nodecl::List stmts = function_code.get_statements().as<Nodecl::List>();

        // First, traverse nested functions
        for (Nodecl::List::iterator it = stmts.begin();
                it != stmts.end();
                it++)
        {
            if (it->is<Nodecl::FunctionCode>())
            {
                walk(*it);
            }
        }
        // Second, remaining statements
        for (Nodecl::List::iterator it = stmts.begin();
                it != stmts.end();
                it++)
        {
            if (!it->is<Nodecl::FunctionCode>())
            {
                walk(*it);
            }
        }
    }
Пример #2
0
    bool NodeclStaticInfo::is_constant_access( const Nodecl::NodeclBase& n ) const
    {
        bool result = true;
        
        if( n.is<Nodecl::ArraySubscript>( ) )
        {
            Nodecl::ArraySubscript array = n.as<Nodecl::ArraySubscript>( );

            //Check subscripted
            if ( !is_constant( array.get_subscripted( ) ))
            {
                return false;
            }

            // Check subscrips
            Nodecl::List subscript = array.get_subscripts( ).as<Nodecl::List>( );
            Nodecl::List::iterator it = subscript.begin( );
            for( ; it != subscript.end( ); ++it )
            {   // All dimensions must be constant
                if( !is_constant( *it ) )
                {
                    result = false;
                    break;
                }
            }
        }
        
        return result;
    }
    void Lower::lower_taskwait_with_dependences(const Nodecl::OpenMP::Taskwait& node)
    {
        Nodecl::List environment = node.get_environment().as<Nodecl::List>();

        // Prepare if(0) task reusing environment and set TaskIsTaskwait flag
        Nodecl::NodeclBase zero_expr;
        if(IS_C_LANGUAGE || IS_CXX_LANGUAGE)
        {
            zero_expr = const_value_to_nodecl(const_value_get_unsigned_int(0));
        }
        else  // IS_FORTRAN_LANGUAGE
        {
            zero_expr = Nodecl::BooleanLiteral::make(
                    TL::Type::get_bool_type(),
                    const_value_get_zero(/* bytes */ 4, /* sign */0));
        }
        environment.append(Nodecl::OpenMP::If::make(zero_expr));
        environment.append(Nodecl::OpenMP::TaskIsTaskwait::make());

        Nodecl::OpenMP::Task taskwait_task = Nodecl::OpenMP::Task::make(
                environment,
                Nodecl::List::make(Nodecl::EmptyStatement::make()),
                node.get_locus());

        node.replace(taskwait_task);
        lower_task(node.as<Nodecl::OpenMP::Task>());
    }
Пример #4
0
    static void handle_ompss_opencl_deallocate_intrinsic(
            Nodecl::FunctionCall function_call,
            Nodecl::NodeclBase expr_stmt)
    {
        Nodecl::List arguments = function_call.get_arguments().as<Nodecl::List>();
        ERROR_CONDITION(arguments.size() != 1, "More than one argument in ompss_opencl_deallocate call", 0);

        Nodecl::NodeclBase actual_argument = arguments[0];
        ERROR_CONDITION(!actual_argument.is<Nodecl::FortranActualArgument>(), "Unexpected tree", 0);

        Nodecl::NodeclBase arg = actual_argument.as<Nodecl::FortranActualArgument>().get_argument();
        TL::Symbol array_sym = ::fortran_data_ref_get_symbol(arg.get_internal_nodecl());

        ERROR_CONDITION(
                !(array_sym.get_type().is_fortran_array()
                    && array_sym.is_allocatable())
                &&
                !(array_sym.get_type().is_pointer()
                    && array_sym.get_type().points_to().is_fortran_array()),
                "The argument of 'ompss_opencl_deallocate' intrinsic must be "
                "an allocatable array or a pointer to an array\n", 0);

        // Replace the current intrinsic call by a call to the Nanos++ API
        TL::Symbol ptr_of_arr_sym = get_function_ptr_of(array_sym, expr_stmt.retrieve_context());

        TL::Source new_function_call;
        new_function_call
            << "CALL NANOS_OPENCL_DEALLOCATE_FORTRAN("
            <<      ptr_of_arr_sym.get_name() << "("<< as_expression(arg) << "))\n"
            ;

        expr_stmt.replace(new_function_call.parse_statement(expr_stmt));
    }
        void VectorizerVisitorExpression::visit(const Nodecl::ArraySubscript& n)
        {
            // Computing new vector type
            TL::Type vector_type = n.get_type();
            if (vector_type.is_lvalue_reference())
            {
                vector_type = vector_type.references_to();
            }
            vector_type = get_qualified_vector_to(vector_type, _vector_length);

            TL::Type basic_type = n.get_type();
            if (basic_type.is_lvalue_reference())
            {
                basic_type = basic_type.references_to();
            }

            // Vector Load
            if (Vectorizer::_analysis_info->is_adjacent_access(
                        Vectorizer::_analysis_scopes->back(),
                        n))
            {
                const Nodecl::VectorLoad vector_load =
                    Nodecl::VectorLoad::make(
                            Nodecl::Reference::make(
                                Nodecl::ParenthesizedExpression::make(
                                    n.shallow_copy(),
                                    basic_type,
                                    n.get_locus()),
                                basic_type.get_pointer_to(),
                                n.get_locus()),
                            vector_type,
                            n.get_locus());

                n.replace(vector_load);
            }
            else // Vector Gather
            {
                const Nodecl::NodeclBase base = n.get_subscripted();
                const Nodecl::List subscripts = n.get_subscripts().as<Nodecl::List>();

                ERROR_CONDITION(subscripts.size() > 1,
                    "Vectorizer: Gather on multidimensional array is not supported yet!", 0);

                std::cerr << "Gather: " << n.prettyprint() << "\n";

                Nodecl::NodeclBase strides = *subscripts.begin();
                walk(strides);

                const Nodecl::VectorGather vector_gather =
                    Nodecl::VectorGather::make(
                            base.shallow_copy(),
                            strides,
                            vector_type,
                            n.get_locus());

                n.replace(vector_gather);
            }
        }
Пример #6
0
        void VectorizerVectorReduction::vectorize_reduction(const TL::Symbol& scalar_symbol,
                TL::Symbol& vector_symbol,
                const Nodecl::NodeclBase& reduction_initializer,
                const std::string& reduction_name,
                const TL::Type& reduction_type,
                Nodecl::List& pre_nodecls,
                Nodecl::List& post_nodecls)
        {
            // Step1: ADD REDUCTION SYMBOLS
            vector_symbol.set_value(Nodecl::VectorPromotion::make(
                        reduction_initializer.shallow_copy(),
                        vector_symbol.get_type()));

            // Add new ObjectInit with the initialization
            Nodecl::ObjectInit reduction_object_init =
                Nodecl::ObjectInit::make(vector_symbol);

            pre_nodecls.append(reduction_object_init);


            // Step2: ADD VECTOR REDUCTION INSTRUCTIONS
            if(reduction_name.compare("+") == 0)
            {
                Nodecl::ExpressionStatement post_reduction_stmt =
                    Nodecl::ExpressionStatement::make(
                            Nodecl::VectorReductionAdd::make(
                                scalar_symbol.make_nodecl(true),
                                vector_symbol.make_nodecl(true),
                                scalar_symbol.get_type()));

                post_nodecls.append(post_reduction_stmt);
            }
            else if (reduction_name.compare("-") == 0)
            {
                Nodecl::ExpressionStatement post_reduction_stmt =
                    Nodecl::ExpressionStatement::make(
                            Nodecl::VectorReductionMinus::make(
                                scalar_symbol.make_nodecl(true),
                                vector_symbol.make_nodecl(true),
                                scalar_symbol.get_type()));

                post_nodecls.append(post_reduction_stmt);
            }
        }
Пример #7
0
 void ExtensibleGraph::propagate_arguments_in_function_graph( Nodecl::NodeclBase arguments )
 {
     ERROR_CONDITION( _nodecl.is_null( ), "Found a null nodecl for a graph that is supposed to contain a FunctionCode", 0 );
     ERROR_CONDITION( !_nodecl.is<Nodecl::FunctionCode>( ), "Expected FunctionCode but '%s' found", 
                      ast_print_node_type( _nodecl.get_kind( ) ) );
     Symbol func_sym( _nodecl.get_symbol( ) );
     ERROR_CONDITION( !func_sym.is_valid( ), "Invalid symbol for a nodecl that is supposed to contain a FunctionCode", 0 );
     
     Nodecl::List args = arguments.as<Nodecl::List>( );
     ObjectList<Symbol> params = func_sym.get_function_parameters( );
     int n_common_params = std::max( args.size( ), params.size( ) );
     
     sym_to_nodecl_map rename_map;
     for( int i = 0; i < n_common_params; ++i )
     {
         rename_map[params[i]] = args[i];
     }
     RenameVisitor rv( rename_map );
     Node* graph_entry = _graph->get_graph_entry_node( );
     propagate_argument_rec( graph_entry, &rv );
     ExtensibleGraph::clear_visits( graph_entry );
 }
Пример #8
0
void AutoScopeVisitor::visit( const Nodecl::OpenMP::Task& n )
{
    // Retrieve the results of the Auto-Scoping process to the user
    _analysis_info->print_auto_scoping_results( n );

    // Modify the Nodecl with the new variables' scope
    Analysis::Utils::AutoScopedVariables autosc_vars = _analysis_info->get_auto_scoped_variables( n );
    Analysis::Utils::ext_sym_set private_ext_syms, firstprivate_ext_syms, race_ext_syms,
             shared_ext_syms, undef_ext_syms;
    Nodecl::NodeclBase user_private_vars, user_firstprivate_vars, user_shared_vars;

    // Get actual environment
    Nodecl::List environ = n.get_environment().as<Nodecl::List>();
    for( Nodecl::List::iterator it = environ.begin( ); it != environ.end( ); )
    {
        if( it->is<Nodecl::OpenMP::Auto>( ) )
        {
            it = environ.erase( it );
        }
        else
        {
            if( it->is<Nodecl::OpenMP::Private>( ) )
            {
                user_private_vars = it->as<Nodecl::OpenMP::Private>( );
            }
            if( it->is<Nodecl::OpenMP::Firstprivate>( ) )
            {
                user_firstprivate_vars = it->as<Nodecl::OpenMP::Firstprivate>( );
            }
            if( it->is<Nodecl::OpenMP::Shared>( ) )
            {
                user_shared_vars = it->as<Nodecl::OpenMP::Shared>( );
            }
            ++it;
        }
    }

    // Remove user-scoped variables from auto-scoped variables and reset environment
    private_ext_syms = autosc_vars.get_private_vars( );
    if( !private_ext_syms.empty( ) )
    {
        ObjectList<Nodecl::NodeclBase> autosc_private_vars;
        for( Analysis::Utils::ext_sym_set::iterator it = private_ext_syms.begin( ); it != private_ext_syms.end( ); ++it )
        {
            autosc_private_vars.insert( it->get_nodecl( ) );
        }
        ObjectList<Nodecl::NodeclBase> purged_autosc_private_vars;
        for( ObjectList<Nodecl::NodeclBase>::iterator it = autosc_private_vars.begin( );
                it != autosc_private_vars.end( ); ++it )
        {
            if( !Nodecl::Utils::nodecl_is_in_nodecl_list( *it, user_firstprivate_vars.as<Nodecl::List>( ) )
                    && !Nodecl::Utils::nodecl_is_in_nodecl_list( *it, user_private_vars.as<Nodecl::List>( ) )
                    && !Nodecl::Utils::nodecl_is_in_nodecl_list( *it, user_shared_vars.as<Nodecl::List>( ) ) )
            {
                purged_autosc_private_vars.insert( it->shallow_copy() );
            }
        }
        if( !purged_autosc_private_vars.empty( ) )
        {
            Nodecl::OpenMP::Private private_node =
                Nodecl::OpenMP::Private::make( Nodecl::List::make( purged_autosc_private_vars ),
                                               n.get_locus( ) );
            environ.append( private_node );
        }
    }

    firstprivate_ext_syms = autosc_vars.get_firstprivate_vars( );
    if( !firstprivate_ext_syms.empty( ) )
    {
        ObjectList<Nodecl::NodeclBase> autosc_firstprivate_vars;
        for( Analysis::Utils::ext_sym_set::iterator it = firstprivate_ext_syms.begin( ); it != firstprivate_ext_syms.end( ); ++it )
        {
            autosc_firstprivate_vars.insert( it->get_nodecl( ) );
        }
        ObjectList<Nodecl::NodeclBase> purged_autosc_firstprivate_vars;
        for( ObjectList<Nodecl::NodeclBase>::iterator it = autosc_firstprivate_vars.begin( );
                it != autosc_firstprivate_vars.end( ); ++it )
        {
            if( !Nodecl::Utils::nodecl_is_in_nodecl_list( *it, user_firstprivate_vars.as<Nodecl::List>( ) )
                    && !Nodecl::Utils::nodecl_is_in_nodecl_list( *it, user_private_vars.as<Nodecl::List>( ) )
                    && !Nodecl::Utils::nodecl_is_in_nodecl_list( *it, user_shared_vars.as<Nodecl::List>( ) ) )
            {
                purged_autosc_firstprivate_vars.insert( it->shallow_copy() );
            }
        }
        if( !purged_autosc_firstprivate_vars.empty( ) )
        {
            Nodecl::OpenMP::Firstprivate firstprivate_node =
                Nodecl::OpenMP::Firstprivate::make( Nodecl::List::make( purged_autosc_firstprivate_vars ),
                                                    n.get_locus( ) );
            environ.append( firstprivate_node );
        }
    }

    shared_ext_syms = autosc_vars.get_shared_vars( );
    if( !shared_ext_syms.empty( ) )
    {
        ObjectList<Nodecl::NodeclBase> autosc_shared_vars;
        for( Analysis::Utils::ext_sym_set::iterator it = shared_ext_syms.begin( ); it != shared_ext_syms.end( ); ++it )
        {
            autosc_shared_vars.insert( it->get_nodecl( ) );
        }
        ObjectList<Nodecl::NodeclBase> purged_autosc_shared_vars;
        for( ObjectList<Nodecl::NodeclBase>::iterator it = autosc_shared_vars.begin( );
                it != autosc_shared_vars.end( ); ++it )
        {
            if( !Nodecl::Utils::nodecl_is_in_nodecl_list( *it, user_firstprivate_vars.as<Nodecl::List>( ) )
                    && !Nodecl::Utils::nodecl_is_in_nodecl_list( *it, user_private_vars.as<Nodecl::List>( ) )
                    && !Nodecl::Utils::nodecl_is_in_nodecl_list( *it, user_shared_vars.as<Nodecl::List>( ) ) )
            {
                purged_autosc_shared_vars.insert( it->shallow_copy() );
            }
        }
        if( !purged_autosc_shared_vars.empty( ) )
        {
            Nodecl::OpenMP::Shared shared_node =
                Nodecl::OpenMP::Shared::make( Nodecl::List::make( purged_autosc_shared_vars ),
                                              n.get_locus( ) );
            environ.append( shared_node );
        }
    }
}
void DeviceOpenCL::create_outline(CreateOutlineInfo &info,
        Nodecl::NodeclBase &outline_placeholder,
        Nodecl::NodeclBase &output_statements,
        Nodecl::Utils::SimpleSymbolMap* &symbol_map)
{
    // Unpack DTO
    Lowering *lowering = info._lowering;
    const std::string& outline_name = ocl_outline_name(info._outline_name);
    const Nodecl::NodeclBase& task_statements = info._task_statements;
    const Nodecl::NodeclBase& original_statements = info._original_statements;
    const TL::Symbol& called_task = info._called_task;
    bool is_function_task = info._called_task.is_valid();
    TL::ObjectList<OutlineDataItem*> data_items = info._data_items;

    lowering->seen_opencl_task = true;

    symbol_map = new Nodecl::Utils::SimpleSymbolMap();

    output_statements = task_statements;

    ERROR_CONDITION(called_task.is_valid() && !called_task.is_function(),
            "The '%s' symbol is not a function", called_task.get_name().c_str());

    TL::Symbol current_function = original_statements.retrieve_context().get_related_symbol();
    if (current_function.is_nested_function())
    {
        if (IS_C_LANGUAGE || IS_CXX_LANGUAGE)
            fatal_printf_at(original_statements.get_locus(), "nested functions are not supported\n");


        if (IS_FORTRAN_LANGUAGE)
            fatal_printf_at(original_statements.get_locus(), "internal subprograms are not supported\n");
    }


    Source extra_declarations;
    Source final_statements, initial_statements;

    // *** Unpacked (and forward in Fortran) function ***
    TL::Symbol unpacked_function, forward_function;
    if (IS_FORTRAN_LANGUAGE)
    {
        forward_function = new_function_symbol_forward(
                current_function,
                outline_name + "_forward",
                info);
        unpacked_function = new_function_symbol_unpacked(
                current_function,
                outline_name + "_unpack",
                info,
                // out
                symbol_map,
                initial_statements,
                final_statements);
    }
    else
    {
        unpacked_function = new_function_symbol_unpacked(
                current_function,
                outline_name + "_unpacked",
                info,
                // out
                symbol_map,
                initial_statements,
                final_statements);
    }


    Nodecl::NodeclBase unpacked_function_code, unpacked_function_body;
    SymbolUtils::build_empty_body_for_function(unpacked_function,
            unpacked_function_code,
            unpacked_function_body);

    if (IS_FORTRAN_LANGUAGE)
    {
        // Now get all the needed internal functions and replicate them in the outline
        Nodecl::Utils::Fortran::InternalFunctions internal_functions;
        internal_functions.walk(info._original_statements);

        Nodecl::List l;
        for (TL::ObjectList<Nodecl::NodeclBase>::iterator
                it2 = internal_functions.function_codes.begin();
                it2 != internal_functions.function_codes.end();
                it2++)
        {
            l.append(
                    Nodecl::Utils::deep_copy(*it2, unpacked_function.get_related_scope(), *symbol_map)
                    );
        }

        // unpacked_function_code.as<Nodecl::FunctionCode>().set_internal_functions(l);
    }

    Nodecl::Utils::append_to_top_level_nodecl(unpacked_function_code);

    //Get the argument of the 'file' clause, if not present, use the files passed in the command line (if any)
    std::string file_clause_arg = info._target_info.get_file();
    std::string kernel_files = file_clause_arg;
    if (!file_clause_arg.empty())
    {
        bool found = false;
        for (int i = 0; i < ::compilation_process.num_translation_units; ++i)
        {
            compilation_file_process_t* file_process = ::compilation_process.translation_units[i];
            translation_unit_t* current_translation_unit = file_process->translation_unit;
            const char* extension = get_extension_filename(current_translation_unit->input_filename);
            struct extensions_table_t* current_extension = fileextensions_lookup(extension, strlen(extension));

            if (current_extension->source_language == SOURCE_SUBLANGUAGE_OPENCL)
            {
                const char* basename = give_basename(current_translation_unit->input_filename);
                if (file_clause_arg == std::string(basename))
                {
                    ERROR_CONDITION(found, "%s: error: more than one OpenCL file in the command line matches clause file(%s)\n",
                            original_statements.get_locus_str().c_str(), basename);

                    found = true;
                    kernel_files = std::string(current_translation_unit->input_filename);
                }
            }
        }

        if (!found && !_disable_opencl_file_check)
        {
            error_printf_at(original_statements.get_locus(),
                    "no OpenCL file in the command line matches clause file(%s)\n",
                    file_clause_arg.c_str());
        }
    }
    else
    {
        int ocl_files = 0;
        for (int i = 0; i < ::compilation_process.num_translation_units; ++i)
        {
            compilation_file_process_t* file_process = ::compilation_process.translation_units[i];
            translation_unit_t* current_translation_unit = file_process->translation_unit;
            const char* extension = get_extension_filename(current_translation_unit->input_filename);
            struct extensions_table_t* current_extension = fileextensions_lookup(extension, strlen(extension));

            if (current_extension->source_language == SOURCE_SUBLANGUAGE_OPENCL)
            {
                if (ocl_files > 0)
                    kernel_files += ",";

                kernel_files += std::string(current_translation_unit->input_filename);
                ocl_files++;
            }
        }

        if (ocl_files == 0)
        {
            fatal_printf_at(original_statements.get_locus(),
                    "no OpenCL file specified for kernel '%s'\n",
                    called_task.get_name().c_str());
        }
    }

    // Get the name of the kernel
    std::string kernel_name = info._target_info.get_name();
    if (kernel_name.empty())
    {
        // If the clause name is not present, use the name of the called task
        kernel_name = called_task.get_name();
    }

    Source ndrange_code;
    if (called_task.is_valid()
            && info._target_info.get_ndrange().size() > 0)
    {
        Nodecl::Utils::SimpleSymbolMap param_to_args_map =
            info._target_info.get_param_arg_map();

        generate_ndrange_code(called_task,
                unpacked_function,
                info._target_info,
                kernel_files,
                kernel_name,
                info._data_items,
                &param_to_args_map,
                symbol_map,
                ndrange_code);
    }


    Source unpacked_source;
    if (!IS_FORTRAN_LANGUAGE)
    {
        unpacked_source
            << "{";
    }

    unpacked_source
        << extra_declarations
        << initial_statements
        << ndrange_code
        //<< statement_placeholder(outline_placeholder)
        << final_statements
        ;

    if (!IS_FORTRAN_LANGUAGE)
    {
        unpacked_source
            << "}";
    }
    
    // Fortran may require more symbols
    if (IS_FORTRAN_LANGUAGE)
    {
        // Insert extra symbols
        TL::Scope unpacked_function_scope = unpacked_function_body.retrieve_context();

        Nodecl::Utils::Fortran::ExtraDeclsVisitor fun_visitor(symbol_map,
                unpacked_function_scope,
                current_function);
        if (is_function_task)
        {
            fun_visitor.insert_extra_symbol(info._called_task);
        }
        fun_visitor.insert_extra_symbols(task_statements);

        Nodecl::Utils::Fortran::append_used_modules(
                original_statements.retrieve_context(),
                unpacked_function_scope);

        if (is_function_task)
        {
            Nodecl::Utils::Fortran::append_used_modules(
                    info._called_task.get_related_scope(),
                    unpacked_function_scope);
        }

        // Add also used types
        add_used_types(data_items, unpacked_function.get_related_scope());

        // Now get all the needed internal functions and replicate them in the outline
        Nodecl::Utils::Fortran::InternalFunctions internal_functions;
        internal_functions.walk(info._original_statements);

        duplicate_internal_subprograms(internal_functions.function_codes,
                unpacked_function.get_related_scope(),
                symbol_map,
                output_statements);

        extra_declarations
            << "IMPLICIT NONE\n";
    }
    else if (IS_CXX_LANGUAGE)
    {
        if (!unpacked_function.is_member())
        {
            Nodecl::NodeclBase nodecl_decl = Nodecl::CxxDecl::make(
                    /* optative context */ nodecl_null(),
                    unpacked_function,
                    original_statements.get_locus());
            Nodecl::Utils::prepend_to_enclosing_top_level_location(original_statements, nodecl_decl);
        }
    }

    Nodecl::NodeclBase new_unpacked_body = unpacked_source.parse_statement(unpacked_function_body);
    unpacked_function_body.replace(new_unpacked_body);


    // **** Outline function *****
    ObjectList<std::string> structure_name;
    structure_name.append("args");
    ObjectList<TL::Type> structure_type;
    structure_type.append(
            TL::Type(get_user_defined_type(info._arguments_struct.get_internal_symbol())).get_lvalue_reference_to()
            );

    TL::Symbol outline_function = SymbolUtils::new_function_symbol(
            current_function,
            outline_name,
            TL::Type::get_void_type(),
            structure_name,
            structure_type);

    Nodecl::NodeclBase outline_function_code, outline_function_body;
    SymbolUtils::build_empty_body_for_function(outline_function,
            outline_function_code,
            outline_function_body);
    Nodecl::Utils::append_to_top_level_nodecl(outline_function_code);

    // Prepare arguments for the call to the unpack (or forward in Fortran)
    TL::Scope outline_function_scope(outline_function_body.retrieve_context());
    TL::Symbol structure_symbol = outline_function_scope.get_symbol_from_name("args");
    ERROR_CONDITION(!structure_symbol.is_valid(), "Argument of outline function not found", 0);

    Source unpacked_arguments, cleanup_code;

    for (TL::ObjectList<OutlineDataItem*>::iterator it = data_items.begin();
            it != data_items.end();
            it++)
    {
        if (!is_function_task
                && (*it)->get_is_cxx_this())
            continue;

        switch ((*it)->get_sharing())
        {
            case OutlineDataItem::SHARING_PRIVATE:
                {
                    // Do nothing
                    break;
                }
            case OutlineDataItem::SHARING_SHARED:
            case OutlineDataItem::SHARING_CAPTURE:
            case OutlineDataItem::SHARING_CAPTURE_ADDRESS:
                {
                    TL::Type param_type = (*it)->get_in_outline_type();

                    Source argument;
                    if (IS_C_LANGUAGE || IS_CXX_LANGUAGE)
                    {
                        // Normal shared items are passed by reference from a pointer,
                        // derreference here
                        if ((*it)->get_sharing() == OutlineDataItem::SHARING_SHARED
                                && !(IS_CXX_LANGUAGE && (*it)->get_symbol().get_name() == "this"))
                        {
                            if (!param_type.no_ref().depends_on_nonconstant_values())
                            {
                                argument << "*(args." << (*it)->get_field_name() << ")";
                            }
                            else
                            {
                                TL::Type ptr_type = (*it)->get_in_outline_type().references_to().get_pointer_to();
                                TL::Type cast_type = rewrite_type_of_vla_in_outline(ptr_type, data_items, structure_symbol);

                                argument << "*((" << as_type(cast_type) << ")args." << (*it)->get_field_name() << ")";
                            }
                        }
                        // Any other parameter is bound to the storage of the struct
                        else
                        {
                            if (!param_type.no_ref().depends_on_nonconstant_values())
                            {
                                argument << "args." << (*it)->get_field_name();
                            }
                            else
                            {
                                TL::Type cast_type = rewrite_type_of_vla_in_outline(param_type, data_items, structure_symbol);
                                argument << "(" << as_type(cast_type) << ")args." << (*it)->get_field_name();
                            }
                        }

                        if (IS_CXX_LANGUAGE
                                && (*it)->get_allocation_policy() == OutlineDataItem::ALLOCATION_POLICY_TASK_MUST_DESTROY)
                        {
                            internal_error("Not yet implemented: call the destructor", 0);
                        }
                    }
                    else if (IS_FORTRAN_LANGUAGE)
                    {
                        argument << "args % " << (*it)->get_field_name();

                        if ((*it)->get_allocation_policy()
                                & OutlineDataItem::ALLOCATION_POLICY_TASK_MUST_DEALLOCATE_ALLOCATABLE)
                        {
                            cleanup_code
                                << "IF (ALLOCATED(args % " << (*it)->get_field_name() << ")) THEN\n"
                                <<      "DEALLOCATE(args % " << (*it)->get_field_name() << ")\n"
                                << "ENDIF\n"
                                ;
                        }
                    }
                    else
                    {
                        internal_error("running error", 0);
                    }

                    unpacked_arguments.append_with_separator(argument, ", ");
                    break;
                }
            case OutlineDataItem::SHARING_REDUCTION:
                {
                    // // Pass the original reduced variable as if it were a shared
                    Source argument;
                    if (IS_C_LANGUAGE || IS_CXX_LANGUAGE)
                    {
                        argument << "*(args." << (*it)->get_field_name() << ")";
                    }
                    else if (IS_FORTRAN_LANGUAGE)
                    {
                        argument << "args % " << (*it)->get_field_name();
                    }
                    unpacked_arguments.append_with_separator(argument, ", ");
                    break;
                }
            default:
                {
                    internal_error("Unexpected data sharing kind", 0);
                }
        }
    }

    Source outline_src,
           instrument_before,
           instrument_after;

    if (IS_C_LANGUAGE || IS_CXX_LANGUAGE)
    {
        Source unpacked_function_call;
        if (IS_CXX_LANGUAGE
                && !is_function_task
                && current_function.is_member()
                && !current_function.is_static())
        {
            unpacked_function_call << "args.this_->";
        }

        unpacked_function_call << unpacked_function.get_qualified_name_for_expression(
                /* in_dependent_context */
                (current_function.get_type().is_template_specialized_type()
                 && current_function.get_type().is_dependent())
                ) << "(" << unpacked_arguments << ");";

        outline_src
            << "{"
            <<      instrument_before
            <<      unpacked_function_call
            <<      instrument_after
            <<      cleanup_code
            << "}"
            ;

        if (IS_CXX_LANGUAGE)
        {
            if (!outline_function.is_member())
            {
                Nodecl::NodeclBase nodecl_decl = Nodecl::CxxDecl::make(
                        /* optative context */ nodecl_null(),
                        outline_function,
                        original_statements.get_locus());
                Nodecl::Utils::prepend_to_enclosing_top_level_location(original_statements, nodecl_decl);
            }
        }
    }
    else if (IS_FORTRAN_LANGUAGE)
    {
        Source outline_function_addr;

        outline_src
            << instrument_before << "\n"
            << "CALL " << outline_name << "_forward(" << outline_function_addr << unpacked_arguments << ")\n"
            << instrument_after << "\n"
            << cleanup_code
            ;

        outline_function_addr << "LOC(" << unpacked_function.get_name() << ")";
        if (!unpacked_arguments.empty())
        {
            outline_function_addr << ", ";
        }

        // Copy USEd information to the outline and forward functions
        TL::Symbol *functions[] = { &outline_function, &forward_function, NULL };

        for (int i = 0; functions[i] != NULL; i++)
        {
            TL::Symbol &function(*functions[i]);

            Nodecl::Utils::Fortran::append_used_modules(original_statements.retrieve_context(),
                    function.get_related_scope());

            add_used_types(data_items, function.get_related_scope());
        }

        // Generate ancillary code in C
        add_forward_function_code_to_extra_c_code(outline_name, data_items, outline_function_body);
    }
    else
    {
        internal_error("Code unreachable", 0);
    }

    if (instrumentation_enabled())
    {
        get_instrumentation_code(
                info._called_task,
                outline_function,
                outline_function_body,
                info._task_label,
                original_statements.get_locus(),
                instrument_before,
                instrument_after);
    }

    Nodecl::NodeclBase new_outline_body = outline_src.parse_statement(outline_function_body);
    outline_function_body.replace(new_outline_body);

    // Nodecl::Utils::prepend_to_enclosing_top_level_location(original_statements, outline_function_code);
    //
     //Dummy function call placeholder
     Source unpacked_ndr_code;
     unpacked_ndr_code << statement_placeholder(outline_placeholder);
     Nodecl::NodeclBase new_unpacked_ndr_code = unpacked_ndr_code.parse_statement(unpacked_function_body);
     outline_placeholder=new_unpacked_ndr_code;
}
Пример #10
0
 void PointerSize::compute_pointer_vars_size_rec(Node* current)
 {
     if(current->is_visited())
         return;
     
     current->set_visited(true);
     if(current->is_graph_node())
     {
         compute_pointer_vars_size_rec(current->get_graph_entry_node());
     }
     else
     {
         if(current->has_statements())
         {
             NBase s;
             NBase value;
             TL::Type t;
             NodeclList stmts = current->get_statements();
             for(NodeclList::iterator it = stmts.begin(); it != stmts.end(); ++it)
             {
                 // If assignment (or object init) check whether its for is a dynamic allocation of resources for a pointer type
                 if(it->is<Nodecl::ObjectInit>() || it->is<Nodecl::Assignment>())
                 {
                     // Get the variable assigned and the value used for the assignment
                     if(it->is<Nodecl::ObjectInit>())
                     {
                         Symbol tmp(it->get_symbol());
                         s = Nodecl::Symbol::make(tmp);
                         t = tmp.get_type();
                         s.set_type(t);
                         value = tmp.get_value().no_conv();
                     }
                     else if(it->is<Nodecl::Assignment>())
                     {
                         s = it->as<Nodecl::Assignment>().get_lhs().no_conv();
                         t = s.get_type().no_ref();
                         if(!s.is<Nodecl::Symbol>() && !s.is<Nodecl::ClassMemberAccess>() && !s.is<Nodecl::ArraySubscript>())
                             continue;
                         value = it->as<Nodecl::Assignment>().get_rhs().no_conv();
                     }
                     
                     // Check whether this is a pointer and the assignment is a recognized memory operation
                     if(t.is_pointer() && !value.is_null())      // This can be null if uninitialized ObjectInit
                     {
                         if(value.is<Nodecl::FunctionCall>())
                         {
                             Symbol called_sym = value.as<Nodecl::FunctionCall>().get_called().get_symbol();
                             Type return_t = called_sym.get_type().returns();
                             Nodecl::List args = value.as<Nodecl::FunctionCall>().get_arguments().as<Nodecl::List>();
                             std::string sym_name = called_sym.get_name();
                             NBase size = NBase::null();
                             if((sym_name == "malloc") && (args.size() == 1))
                             {   // void* malloc (size_t size);
                                 Type arg0_t = args[0].get_type();
                                 if(return_t.is_pointer() && return_t.points_to().is_void() && arg0_t.is_same_type(get_size_t_type()))
                                 {   // We recognize the form 'sizeof(base_type) * n_elemes' and 'n_elemes * sizeof(base_type)'
                                     if(args[0].is<Nodecl::Mul>())
                                     {
                                         NBase lhs = args[0].as<Nodecl::Mul>().get_lhs().no_conv();
                                         NBase rhs = args[0].as<Nodecl::Mul>().get_rhs().no_conv();
                                         if(lhs.is<Nodecl::Sizeof>() && (rhs.is<Nodecl::IntegerLiteral>() || rhs.is<Nodecl::Symbol>()))
                                             size = rhs;
                                         else if(rhs.is<Nodecl::Sizeof>() && (lhs.is<Nodecl::IntegerLiteral>() || lhs.is<Nodecl::Symbol>()))
                                             size = lhs;
                                     }
                                 }
                             }
                             else if((sym_name == "calloc") && (args.size() == 2))
                             {   // void* calloc (size_t num, size_t size);
                                 Type arg0_t = args[0].get_type();
                                 Type arg1_t = args[1].get_type();
                                 if(return_t.is_pointer() && return_t.points_to().is_void()
                                         && arg0_t.is_same_type(get_size_t_type())
                                         && arg1_t.is_same_type(get_size_t_type()))
                                 {
                                     size = args[0];
                                 }
                             }
                             
                             if(!size.is_null())
                                 _pcfg->set_pointer_n_elems(s, size);
                         }
                     }
                     
                     // Clear up the common variables s, value and t
                     s = NBase::null();
                     value = NBase::null();
                     t = Type();
                 }
             }
         }
     }
     
     // Keep iterating over the children
     ObjectList<Node*> children = current->get_children();
     for(ObjectList<Node*>::iterator it = children.begin(); it != children.end(); ++it)
         compute_pointer_vars_size_rec(*it);
 }
Пример #11
0
    void loop_hlt_handler_post(TL::PragmaCustomStatement construct)
    {
        TL::PragmaCustomLine pragma_line = construct.get_pragma_line();
        TL::PragmaCustomClause collapse = construct.get_pragma_line().get_clause("collapse");
        if (!collapse.is_defined())
            return;

        TL::ObjectList<Nodecl::NodeclBase> expr_list = collapse.get_arguments_as_expressions(construct);
        if (expr_list.size() != 1)
        {
            error_printf_at(construct.get_locus(), "'collapse' clause needs exactly one argument\n");
            return;
        }

        Nodecl::NodeclBase expr = expr_list[0];
        if (!expr.is_constant()
                || !is_any_int_type(expr.get_type().get_internal_type()))
        {
            error_printf_at(construct.get_locus(),
                    "'collapse' clause requires an integer constant expression\n");
            return;
        }

        int collapse_factor = const_value_cast_to_signed_int(expr.get_constant());

        if (collapse_factor <= 0)
        {
            error_printf_at(
                    construct.get_locus(),
                    "Non-positive factor (%d) is not allowed in the 'collapse' clause\n",
                    collapse_factor);
        }
        else if (collapse_factor == 1)
        {
            // Removing the collapse clause from the pragma
            pragma_line.remove_clause("collapse");
        }
        else if (collapse_factor > 1)
        {
            Nodecl::NodeclBase loop = get_statement_from_pragma(construct);

            HLT::LoopCollapse loop_collapse;
            loop_collapse.set_loop(loop);
            loop_collapse.set_pragma_context(construct.retrieve_context());
            loop_collapse.set_collapse_factor(collapse_factor);

            loop_collapse.collapse();

            Nodecl::NodeclBase transformed_code = loop_collapse.get_whole_transformation();
            TL::ObjectList<TL::Symbol> capture_symbols = loop_collapse.get_omp_capture_symbols();

            // We may need to add some symbols that are used to implement the collapse clause to the pragma
            std::string names;
            for (TL::ObjectList<TL::Symbol>::iterator it = capture_symbols.begin();
                    it != capture_symbols.end();
                    it++)
            {
                if (it != capture_symbols.begin())
                    names += ",";
                names += it->get_name();
            }
            Nodecl::List clauses = pragma_line.get_clauses().as<Nodecl::List>();
            clauses.append(Nodecl::PragmaCustomClause::make(Nodecl::List::make(Nodecl::PragmaClauseArg::make(names)), "firstprivate"));

            // Removing the collapse clause from the pragma
            pragma_line.remove_clause("collapse");

            // Create a new pragma over the new for stmt
            ERROR_CONDITION(!transformed_code.is<Nodecl::Context>(), "Unexpected node\n", 0);
            Nodecl::NodeclBase compound_statement =
                transformed_code.as<Nodecl::Context>().get_in_context().as<Nodecl::List>().front();

            ERROR_CONDITION(!compound_statement.is<Nodecl::CompoundStatement>(), "Unexpected node\n", 0);
            Nodecl::Context context_for_stmt =
                compound_statement.as<Nodecl::CompoundStatement>().get_statements()
                .as<Nodecl::List>().find_first<Nodecl::Context>();

            Nodecl::Utils::remove_from_enclosing_list(context_for_stmt);

            Nodecl::List stmt_list =
                compound_statement.as<Nodecl::CompoundStatement>().get_statements().as<Nodecl::List>();
            ERROR_CONDITION(stmt_list.is_null(), "Unreachable code\n", 0);

            Nodecl::PragmaCustomStatement new_pragma =
                Nodecl::PragmaCustomStatement::make(pragma_line,
                        Nodecl::List::make(context_for_stmt),
                        construct.get_text(),
                        construct.get_locus());

            stmt_list.append(new_pragma);

            construct.replace(transformed_code);
        }
    }
Пример #12
0
    int SuitableAlignmentVisitor::visit( const Nodecl::ArraySubscript& n ) 
    {
        if( _nesting_level == 0 )  // Target access
        {
            _nesting_level++;
            
            int i;
            int alignment = 0;
            
            Nodecl::NodeclBase subscripted = n.get_subscripted( );
            TL::Type element_type = subscripted.get_type( );
            // TODO: subscript is aligned
            
            Nodecl::List subscripts = n.get_subscripts( ).as<Nodecl::List>( );
            int num_subscripts = subscripts.size( );
            
            // Get dimension sizes
            int *dimension_sizes = (int *)malloc( ( num_subscripts-1 ) * sizeof( int ) );
            
            for( i = 0; i < (num_subscripts-1); i++ ) // Skip the first one. It does not have size
            {
                // Iterate on array subscript type
                if( element_type.is_array( ) )
                {
                    element_type = element_type.array_element( );
                }
                else if( element_type.is_pointer( ) )
                {
                    element_type = element_type.points_to( );
                }
                else
                {
                    WARNING_MESSAGE( "Array subscript does not have array type or pointer to array type", 0 );
                    return -1;
                }
                
                if( !element_type.array_has_size( ) )
                {
                    WARNING_MESSAGE( "Array type does not have size", 0 );
                    return -1;
                }
                
                // Compute dimension alignment 
                Nodecl::NodeclBase dimension_size_node = element_type.array_get_size( );

                // If VLA, get the actual size
                if(dimension_size_node.is<Nodecl::Symbol>() &&
                        dimension_size_node.get_symbol().is_saved_expression())
                {
                    dimension_size_node = dimension_size_node.get_symbol().get_value();
                }
               
                int dimension_size = -1;
                if( dimension_size_node.is_constant( ) )
                {
                    dimension_size = const_value_cast_to_signed_int( dimension_size_node.get_constant( ) );
                    
                    if( is_suitable_constant( dimension_size * _type_size ) )
                        dimension_size = 0;
                }
                // If dimension size is suitable
                else if( is_suitable_expression( dimension_size_node ) )
                {
                    dimension_size = 0;
                }
                if( VERBOSE )
                    printf( "Dim %d, size %d\n", i, dimension_size );
                
                dimension_sizes[i] = dimension_size;
            }
            
            int it_alignment;
            Nodecl::List::iterator it = subscripts.begin( );
            // Multiply dimension sizes by indexes
            for( i=0; it != subscripts.end( ); i++ )
            {
                it_alignment = walk( *it );
                
                it++;
                if( it == subscripts.end( ) ) break; // Last dimmension does not have to be multiplied
                
                // a[i][j][k] -> i -> i*J*K
                for( int j = i; j < (num_subscripts-1); j++ )
                {
                    if( ( dimension_sizes[j] == 0 ) || ( it_alignment == 0 ) )
                    {
                        it_alignment = 0;
                    }
                    else if( ( dimension_sizes[j] < 0 ) || ( it_alignment < 0 ) )
                    {
                        it_alignment = -1;
                    }
                    else
                    {
                        it_alignment *= dimension_sizes[j];
                    }
                }
                
                if( it_alignment < 0 )
                {
                    return -1;
                }
                
                alignment += it_alignment;
            }
            // Add adjacent dimension
            alignment += it_alignment;
            
            free(dimension_sizes);
            
            _nesting_level--;
            
            return alignment;
        }
        // Nested array subscript
        else
        {
            if (is_suitable_expression(n))
            {
                return 0;
            }
            
            return -1;
        }
    }
Пример #13
0
    static void handle_ompss_opencl_allocate_intrinsic(
            Nodecl::FunctionCall function_call,
            std::map<std::pair<TL::Type, std::pair<int, bool> > , Symbol> &declared_ocl_allocate_functions,
            Nodecl::NodeclBase expr_stmt)
    {
        Nodecl::List arguments = function_call.get_arguments().as<Nodecl::List>();
        ERROR_CONDITION(arguments.size() != 1, "More than one argument in 'ompss_opencl_allocate' call\n", 0);

        Nodecl::NodeclBase actual_argument = arguments[0];
        ERROR_CONDITION(!actual_argument.is<Nodecl::FortranActualArgument>(), "Unexpected tree\n", 0);

        Nodecl::NodeclBase arg = actual_argument.as<Nodecl::FortranActualArgument>().get_argument();
        ERROR_CONDITION(!arg.is<Nodecl::ArraySubscript>(), "Unreachable code\n", 0);

        Nodecl::NodeclBase subscripted = arg.as<Nodecl::ArraySubscript>().get_subscripted();
        TL::Symbol subscripted_symbol = ::fortran_data_ref_get_symbol(subscripted.get_internal_nodecl());

        ERROR_CONDITION(
                !(subscripted_symbol.get_type().is_fortran_array()
                    && subscripted_symbol.is_allocatable())
                &&
                !(subscripted_symbol.get_type().is_pointer()
                    && subscripted_symbol.get_type().points_to().is_fortran_array()),
                "The argument of 'ompss_opencl_allocate' intrinsic must be "
                "an allocatable array or a pointer to an array with all its bounds specified\n", 0);

        TL::Type array_type;
        int num_dimensions;
        bool is_allocatable;
        if (subscripted_symbol.is_allocatable())
        {
            array_type = subscripted_symbol.get_type();
            num_dimensions = subscripted_symbol.get_type().get_num_dimensions();
            is_allocatable = true;
        }
        else
        {
            array_type = subscripted_symbol.get_type().points_to();
            num_dimensions = array_type.get_num_dimensions();
            is_allocatable = false;
        }

        TL::Type element_type = array_type;
        while (element_type.is_array())
        {
            element_type = element_type.array_element();
        }

        ERROR_CONDITION(!array_type.is_array(), "This type should be an array type", 0);

        std::pair<TL::Type, std::pair<int, bool> > key =
            std::make_pair(element_type, std::make_pair(num_dimensions, is_allocatable));

        std::map<std::pair<TL::Type, std::pair<int, bool> > , Symbol>::iterator it_new_fun =
            declared_ocl_allocate_functions.find(key);

        // Reuse the auxiliar function if it already exists
        Symbol new_function_sym;
        if (it_new_fun != declared_ocl_allocate_functions.end())
        {
            new_function_sym = it_new_fun->second;
        }
        else
        {
            new_function_sym = create_new_function_opencl_allocate(
                    expr_stmt, subscripted_symbol, element_type, num_dimensions, is_allocatable);

            declared_ocl_allocate_functions[key] = new_function_sym;
        }

        // Replace the current intrinsic call by a call to the new function
        TL::Source actual_arg_array;
        Nodecl::NodeclBase subscripted_lvalue = subscripted.shallow_copy();
        subscripted_lvalue.set_type(subscripted_symbol.get_type().no_ref().get_lvalue_reference_to());

        actual_arg_array << as_expression(subscripted_lvalue);

        TL::Source actual_arg_bounds;
        Nodecl::List subscripts = arg.as<Nodecl::ArraySubscript>().get_subscripts().as<Nodecl::List>();
        for (Nodecl::List::reverse_iterator it = subscripts.rbegin();
                it != subscripts.rend();
                it++)
        {
            Nodecl::NodeclBase subscript = *it, lower, upper;

            if (it != subscripts.rbegin())
                actual_arg_bounds << ", ";

            if (subscript.is<Nodecl::Range>())
            {
                lower = subscript.as<Nodecl::Range>().get_lower();
                upper = subscript.as<Nodecl::Range>().get_upper();
            }
            else
            {
                lower = nodecl_make_integer_literal(
                        fortran_get_default_integer_type(),
                        const_value_get_signed_int(1), make_locus("", 0, 0));
                upper = subscript;
            }
            actual_arg_bounds << as_expression(lower) << "," << as_expression(upper);
        }

        TL::Source new_function_call;
        new_function_call
            << "CALL " << as_symbol(new_function_sym) << "("
            <<  actual_arg_array  << ", "
            <<  actual_arg_bounds << ")\n"
            ;

        expr_stmt.replace(new_function_call.parse_statement(expr_stmt));

    }
        void VectorizerVisitorExpression::visit(const Nodecl::Assignment& n)
        {
            Nodecl::NodeclBase lhs = n.get_lhs();
            walk(n.get_rhs());

            // Computing new vector type
            TL::Type vector_type = n.get_type();
            /*
            if (vector_type.is_lvalue_reference())
            {
                vector_type = vector_type.references_to();
            }
            */
            vector_type = get_qualified_vector_to(vector_type, _vector_length);

            if(lhs.is<Nodecl::ArraySubscript>())
            {
                // Vector Store
                if(Vectorizer::_analysis_info->is_adjacent_access(
                            Vectorizer::_analysis_scopes->back(),
                            lhs))
                {
                    TL::Type basic_type = lhs.get_type();
                    if (basic_type.is_lvalue_reference())
                    {
                        basic_type = basic_type.references_to();
                    }

                    const Nodecl::VectorStore vector_store =
                        Nodecl::VectorStore::make(
                                Nodecl::Reference::make(
                                    Nodecl::ParenthesizedExpression::make(
                                        lhs.shallow_copy(),
                                        basic_type,
                                        n.get_locus()),
                                    basic_type.get_pointer_to(),
                                    n.get_locus()),
                                n.get_rhs().shallow_copy(),
                                vector_type,
                                n.get_locus());

                    n.replace(vector_store);
                }
                else // Vector Scatter
                {
                    const Nodecl::ArraySubscript lhs_array = lhs.as<Nodecl::ArraySubscript>();

                    const Nodecl::NodeclBase base = lhs_array.get_subscripted();
                    const Nodecl::List subscripts = lhs_array.get_subscripts().as<Nodecl::List>();

                    std::cerr << "Scatter: " << lhs_array.prettyprint() << "\n";

                    ERROR_CONDITION(subscripts.size() > 1,
                            "Vectorizer: Scatter on multidimensional array is not supported yet!", 0);

                    Nodecl::NodeclBase strides = *subscripts.begin();
                    walk(strides);

                    const Nodecl::VectorScatter vector_scatter =
                        Nodecl::VectorScatter::make(
                                base.shallow_copy(),
                                strides,
                                n.get_rhs().shallow_copy(),
                                vector_type,
                                n.get_locus());

                    n.replace(vector_scatter);
                }
            }
            else // Register
            {
                walk(lhs);

                const Nodecl::VectorAssignment vector_assignment =
                    Nodecl::VectorAssignment::make(
                            lhs.shallow_copy(),
                            n.get_rhs().shallow_copy(),
                            vector_type,
                            n.get_locus());

                n.replace(vector_assignment);
            }
        }
Пример #15
0
        void NanosMain::run(TL::DTO& dto)
        {
            this->PragmaCustomCompilerPhase::run(dto);

            TL::Symbol main_function = get_main_function_symbol();
            if (!main_function.is_valid()
                    || main_function.get_function_code().is_null())
                return;

            bool new_ompss_main_api = Nanos::Version::interface_is_at_least("master", 5030);
            bool emit_main_instrumentation = _instrumentation_enabled
                    && new_ompss_main_api;

            bool emit_nanos_main_call = (_nanos_main_enabled
                    && Nanos::Version::interface_is_at_least("master", 5026))
                || emit_main_instrumentation;

            if (!emit_main_instrumentation
                    && !emit_nanos_main_call)
                return;

            Source initial_main_code_src;
            Nodecl::FunctionCode function_code = main_function.get_function_code().as<Nodecl::FunctionCode>();

            if (emit_nanos_main_call)
            {
                if (new_ompss_main_api)
                {
                    if (!IS_FORTRAN_LANGUAGE)
                    {
                        initial_main_code_src
                            << "ompss_nanox_main_begin((void*)main,"
                            << "\"" << function_code.get_filename() << "\","
                            << function_code.get_line() << ");";
                    }
                    else
                    {
                        initial_main_code_src
                            << "int nanos_main_proxy_address = 0;"
                            << "ompss_nanox_main_begin(&nanos_main_proxy_address,"
                            << "\"" << function_code.get_filename() << "\","
                            << "(int)" << function_code.get_line() << ");";
                    }
                }
                else
                {
                    // Older version, used only for Cluster and Offload so far
                    initial_main_code_src
                        << "ompss_nanox_main();"
                        ;
                }
            }

            if (emit_main_instrumentation)
            {
                initial_main_code_src
                    << "nanos_atexit((void*)ompss_nanox_main_end);";
            }

            if (IS_FORTRAN_LANGUAGE)
            {
                Source::source_language = SourceLanguage::C;
            }
            Nodecl::NodeclBase initial_main_code = initial_main_code_src.parse_statement(main_function.get_function_code());
            Source::source_language = SourceLanguage::Current;

            // Now prepend the code
            Nodecl::Context context = function_code.get_statements().as<Nodecl::Context>();
            Nodecl::List stmts = context.get_in_context().as<Nodecl::List>();

            Nodecl::List statement_list;
            if (!IS_FORTRAN_LANGUAGE)
            {
                // In C/C++ inside a context there is always a singleton list with a compound statement
                Nodecl::CompoundStatement compound_stmt = stmts[0].as<Nodecl::CompoundStatement>();
                stmts = compound_stmt.get_statements().as<Nodecl::List>();
            }

            stmts.prepend(initial_main_code);
        }