Beispiel #1
0
        void NeonVectorBackend::visit(const Nodecl::VectorAdd& n)
        {
            walk(n.get_lhs());
            walk(n.get_rhs());

            TL::Type t = n.get_type();
            ERROR_CONDITION(!t.is_vector(), "Invalid type", 0);
            TL::Type element = t.vector_element();
            ERROR_CONDITION(!element.is_float(), "Not implemented: %s", print_declarator(element.get_internal_type()));

            TL::Symbol builtin_fun = TL::Scope::get_global_scope().get_symbol_from_name("vaddq_f32");
            ERROR_CONDITION(!builtin_fun.is_valid(), "Symbol not found", 0);

            n.replace(
                    Nodecl::FunctionCall::make(
                        builtin_fun.make_nodecl(/* set_ref_type */ true),
                        Nodecl::List::make(
                            n.get_lhs(),
                            n.get_rhs()),
                        /* alternate-name */ Nodecl::NodeclBase::null(),
                        /* function-form */ Nodecl::NodeclBase::null(),
                        n.get_type(),
                        n.get_locus()
                        )
                    );
        }
Beispiel #2
0
    Nodecl::Symbol Symbol::make_nodecl(bool set_ref_type, const locus_t* locus) const
    {
        Nodecl::Symbol sym = Nodecl::Symbol::make(*this, locus);
        if (set_ref_type)
        {
            TL::Type t = this->get_type();
            if (!t.is_any_reference())
                t = t.get_lvalue_reference_to();

            sym.set_type(t);
        }
        else
        {
            sym.set_type(this->get_type());
        }

        // Set constant (currently only for variables)
        if (this->is_variable()
                && this->get_type().is_const()
                && !this->is_parameter() // avoid 'void f(const int n = 3)'
                && !this->get_value().is_null()
                && this->get_value().is_constant())
        {
            sym.set_constant(this->get_value().get_constant());
        }

        return sym;
    }
Beispiel #3
0
    void KNCModuleVisitor::visit(const Nodecl::VectorBitwiseXor& node) 
    { 
        TL::Type type = node.get_type().basic_type();

        // Intrinsic name
        file << "_mm512_xor";
        
        // Postfix
        if (type.is_float()) 
        { 
            file << "_ps"; 
        } 
        else if (type.is_integral_type())
        { 
            file << "_si128"; 
        }
        else
        {
            running_error("KNC Codegen: Node %s at %s has an unsupported type.", 
                    ast_print_node_type(node.get_kind()),
                    node.get_locus_str().c_str());
        }      

        file << "("; 
        walk(node.get_lhs());
        file << ", ";
        walk(node.get_rhs());
        file << ")"; 
    }   
        TL::Type get_array_of_vector(TL::Type t)
        {
            ERROR_CONDITION(!t.is_vector(), "Invalid type", 0);

            return t.vector_element().get_array_to(
                    const_value_to_nodecl(
                        const_value_get_signed_int(t.vector_num_elements())
                        ),
                    TL::Scope::get_global_scope());
        }
Beispiel #5
0
    Nodecl::Symbol Symbol::make_nodecl(bool set_ref_type, const locus_t* locus) const
    {
        Nodecl::Symbol sym = Nodecl::Symbol::make(*this, locus);
        if (set_ref_type)
        {
            TL::Type t = this->get_type();
            if (!t.is_any_reference())
                t = t.get_lvalue_reference_to();

            sym.set_type(t);
        }
        return sym;
    }
        TL::Type get_array_of_mask(TL::Type t)
        {
            ERROR_CONDITION(!t.is_mask(), "Invalid type", 0);

            int n = (t.get_mask_num_elements() / 8)
                + !!(t.get_mask_num_elements() % 8);

            return TL::Type::get_unsigned_char_type().get_array_to(
                    const_value_to_nodecl(
                        const_value_get_signed_int(n)
                        ),
                    TL::Scope::get_global_scope());
        }
Beispiel #7
0
    void LoweringVisitor::create_reduction_function(OpenMP::Reduction* red,
            Nodecl::NodeclBase construct,
            TL::Type reduction_type,
            TL::Symbol& basic_reduction_function,
            TL::Symbol& vector_reduction_function)
    {
        if (IS_C_LANGUAGE || IS_CXX_LANGUAGE)
        {
            basic_reduction_function = create_basic_reduction_function_c(red, construct);

            // This is not yet well supported in Nanos++
            if (!reduction_type.is_array())
            {
                vector_reduction_function = create_vector_reduction_function_c(red, construct);
            }
        }
        else if (IS_FORTRAN_LANGUAGE)
        {
            basic_reduction_function = create_basic_reduction_function_fortran(red, construct);
        }
        else
        {
            internal_error("Code unreachable", 0);
        }
    }
Beispiel #8
0
    void KNCModuleVisitor::visit(const Nodecl::VectorMinus& node) 
    { 
        TL::Type type = node.get_type().basic_type();

        // Intrinsic name
        file << "_mm512_sub";
        
        // Postfix
        if (type.is_float()) 
        { 
            file << "_ps"; 
        } 
        else if (type.is_double()) 
        { 
            file << "_pd"; 
        } 
        else if (type.is_signed_int() ||
            type.is_unsigned_int()) 
        { 
            file << "_epi32"; 
        } 
        else if (type.is_signed_short_int() ||
            type.is_unsigned_short_int()) 
        { 
            file << "_epi16"; 
        } 
        else if (type.is_char() || 
            type.is_signed_char() ||
            type.is_unsigned_char()) 
        { 
            file << "_epi8"; 
        } 
        else
        {
            running_error("KNC Codegen: Node %s at %s has an unsupported type.", 
                    ast_print_node_type(node.get_kind()),
                    node.get_locus_str().c_str());
        }      

        file << "("; 
        walk(node.get_lhs());
        file << ", ";
        walk(node.get_rhs());
        file << ")"; 
    }                                                 
Beispiel #9
0
        bool VectorizerVectorReduction::is_supported_reduction(bool is_builtin,
                const std::string& reduction_name,
                const TL::Type& reduction_type)
        {
            if(is_builtin)
            {
                if(_environment._device.compare("smp") == 0)
                {
                    if(reduction_name.compare("+") == 0)
                    {
                        if(reduction_type.is_signed_int())
                        {
                            return true;
                        }
                    }
                }
                else if(_environment._device.compare("knc") == 0)
                {
                    if((reduction_name.compare("+") == 0) ||
                            (reduction_name.compare("-") == 0))
                    {
                        if(reduction_type.is_signed_int())
                        {
                            return true;
                        }
                        else if(reduction_type.is_float())
                        {
                            return true;
                        }
                        else if (reduction_type.is_double())
                        {
                            return true;
                        }
                    }
                }
            }

            return false;
        }
    static TL::Symbol create_initializer_function_c(
            OpenMP::Reduction* red,
            TL::Type reduction_type,
            Nodecl::NodeclBase construct)
    {
        std::string fun_name;
        {
            std::stringstream ss;
            ss << "nanos_ini_" << red << "_" << reduction_type.get_internal_type() << "_" << simple_hash_str(construct.get_filename().c_str());
            fun_name = ss.str();
        }

        Nodecl::NodeclBase function_body;
        Source src;
        src << "void " << fun_name << "("
            <<      as_type(reduction_type.no_ref().get_lvalue_reference_to()) << " omp_priv,"
            <<      as_type(reduction_type.no_ref().get_lvalue_reference_to()) << " omp_orig)"
            << "{"
            <<    statement_placeholder(function_body)
            << "}"
            ;

        Nodecl::NodeclBase function_code = src.parse_global(construct.retrieve_context().get_global_scope());

        TL::Scope inside_function = ReferenceScope(function_body).get_scope();
        TL::Symbol param_omp_priv = inside_function.get_symbol_from_name("omp_priv");
        ERROR_CONDITION(!param_omp_priv.is_valid(), "Symbol omp_priv not found", 0);

        TL::Symbol param_omp_orig = inside_function.get_symbol_from_name("omp_orig");
        ERROR_CONDITION(!param_omp_orig.is_valid(), "Symbol omp_orig not found", 0);

        TL::Symbol function_sym = inside_function.get_symbol_from_name(fun_name);
        ERROR_CONDITION(!function_sym.is_valid(), "Symbol %s not found", fun_name.c_str());

        Nodecl::NodeclBase initializer = red->get_initializer().shallow_copy();
        if (initializer.is<Nodecl::StructuredValue>())
        {
            Nodecl::StructuredValue structured_value = initializer.as<Nodecl::StructuredValue>();
            if (structured_value.get_form().is<Nodecl::StructuredValueBracedImplicit>())
            {
                structured_value.set_form(Nodecl::StructuredValueCompoundLiteral::make());
            }
        }

        Nodecl::Utils::SimpleSymbolMap translation_map;

        translation_map.add_map(red->get_omp_priv(), param_omp_priv);
        translation_map.add_map(red->get_omp_orig(), param_omp_orig);

        Nodecl::NodeclBase new_initializer = Nodecl::Utils::deep_copy(initializer, inside_function, translation_map);

        if (red->get_is_initialization())
        {
            // The original initializer was something like 'omp_priv = expr1', but the
            // new_initializer only represents the lhs expression (in our example, expr1).
            // For this reason we create manually an assignment expression.
            Nodecl::NodeclBase param_omp_priv_ref = Nodecl::Symbol::make(param_omp_priv);
            param_omp_priv_ref.set_type(param_omp_priv.get_type());

            function_body.replace(
                    Nodecl::List::make(
                        Nodecl::ExpressionStatement::make(
                            Nodecl::Assignment::make(
                                param_omp_priv_ref,
                                new_initializer,
                                param_omp_priv_ref.get_type().no_ref())
                            )));
        }
        else
        {
            function_body.replace(
                    Nodecl::List::make(Nodecl::ExpressionStatement::make(new_initializer)));
        }

        // As the initializer function is needed during the instantiation of
        // the task, this function should be inserted before the construct
        Nodecl::Utils::prepend_to_enclosing_top_level_location(construct,
                function_code);

        return function_sym;
    }
Beispiel #11
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);
 }
Beispiel #12
0
 std::string as_type(TL::Type t)
 {
     return type_to_source(t.get_internal_type());
 }
Beispiel #13
0
bool casting_needs_reinterpr_or_pack(TL::Type& casted_type, TL::Type& cast_type) 
{
    if (casted_type.is_float())
    {
        if (cast_type.is_float())
            return false;
        else
            return true;
    }
    else if (casted_type.is_double())
    {
        if (cast_type.is_double())
            return false;
        else
            return true;
    }
    else if (casted_type.is_signed_int()
            || casted_type.is_unsigned_int())
    {
        if (cast_type.is_signed_int()
                || cast_type.is_unsigned_int())
            return false;
        else
            return true;
    }
    else if (casted_type.is_signed_short_int()
            || casted_type.is_unsigned_short_int())
    {
        if (cast_type.is_signed_short_int()
                || cast_type.is_unsigned_short_int())
            return false;
        else
            return true;
    }
    else if (casted_type.is_signed_char()
            || casted_type.is_unsigned_char()
            || casted_type.is_char())
    {
        if (cast_type.is_signed_char()
                || cast_type.is_unsigned_char()
                || cast_type.is_char())
            return false;
        else
            return true;
    }
    else
    {
        fatal_error("error: casting_needs_reinterpr_or_pack does not support this casting in HLT SIMD.\n");
    }
}
Beispiel #14
0
TL::Source LoopBlocking::do_blocking()
{
    Source result, block_loops;

    result
        << block_loops
        ;

    ObjectList<ForStatement> nest_loops = _for_nest_info.get_nest_list();

    _nesting = std::min(_nest_factors.size(), nest_loops.size());

    TL::Source *current_innermost_part = &block_loops;
    // For every loop declare its block loop variable and the inter-block loop
    ObjectList<TL::Expression>::iterator current_factor = _nest_factors.begin();
    ObjectList<TL::ForStatement>::iterator current_for = nest_loops.begin();
    for (int current_nest = 0;
            current_nest < _nesting;
            current_nest++, current_for++, current_factor++)
    {
        TL::IdExpression induction_var = current_for->get_induction_variable();
        TL::Symbol sym = induction_var.get_symbol();
        TL::Type type = sym.get_type();

        std::string var = "_blk_" + sym.get_name();

        TL::Source *new_innermost_part = new TL::Source();
        (*current_innermost_part)
            << "for(" << type.get_declaration(sym.get_scope(), var) << " = " << current_for->get_lower_bound() << ";"
                      << var << current_for->get_bound_operator() << current_for->get_upper_bound() << ";"
                      << var << "+= ( " << current_for->get_step() << ") * " << current_factor->prettyprint() << ")" 
            << (*new_innermost_part)
            ;

        current_innermost_part = new_innermost_part;
    }

    // Now for every loop, declare the intra-loop
    current_factor = _nest_factors.begin();
    current_for = nest_loops.begin();
    for (int current_nest = 0;
            current_nest < _nesting;
            current_nest++, current_for++, current_factor++)
    {
        TL::IdExpression induction_var = current_for->get_induction_variable();
        TL::Symbol sym = induction_var.get_symbol();
        TL::Type type = sym.get_type();

        std::string var = induction_var.prettyprint();
        std::string init_var = var;
        // If the loop declares the iterator in the for statement
        // declare it again
        AST_t loop_init = current_for->get_iterating_init();
        if (Declaration::predicate(loop_init))
        {
            // Fix init_var to be a declaration
            init_var = type.get_declaration(sym.get_scope(), var);
        }

        std::string blk_var = "_blk_" + sym.get_name();

        TL::Source min_code;

        TL::Source *new_innermost_part = new TL::Source();
        (*current_innermost_part)
            << "for(" << init_var << " = " << blk_var << ";"
                      << var << current_for->get_bound_operator() << min_code  << ";"
                      << var << "+= ( " << current_for->get_step() << "))" 
            << (*new_innermost_part)
            ;

        TL::Source a, b;
        min_code
            << "((" << a << ") < (" << b << ") ? (" << a << ") : (" << b << "))"
            ;

        a << blk_var << " + (" << current_for->get_step() << ") * (" << current_factor->prettyprint() << " - 1 )";
        b << current_for->get_upper_bound();

        current_innermost_part = new_innermost_part;
    }

    // And now the innermost loop
    (*current_innermost_part)
        << nest_loops[_nesting - 1].get_loop_body()
        ;

    return result;
}
Beispiel #15
0
    void LoweringVisitor::reduction_initialization_code(
            OutlineInfo& outline_info,
            Nodecl::NodeclBase ref_tree,
            Nodecl::NodeclBase construct)
    {
        ERROR_CONDITION(ref_tree.is_null(), "Invalid tree", 0);

        if (!Nanos::Version::interface_is_at_least("master", 5023))
        {
            running_error("%s: error: a newer version of Nanos++ (>=5023) is required for reductions support\n",
                    construct.get_locus_str().c_str());
        }

        TL::ObjectList<OutlineDataItem*> reduction_items = outline_info.get_data_items().filter(
                predicate(lift_pointer(functor(&OutlineDataItem::is_reduction))));
        ERROR_CONDITION (reduction_items.empty(), "No reductions to process", 0);

        Source result;

        Source reduction_declaration,
               thread_initializing_reduction_info,
               thread_fetching_reduction_info;

        result
            << reduction_declaration
            << "{"
            << as_type(get_bool_type()) << " red_single_guard;"
            << "nanos_err_t err;"
            << "err = nanos_enter_sync_init(&red_single_guard);"
            << "if (err != NANOS_OK)"
            <<     "nanos_handle_error(err);"
            << "if (red_single_guard)"
            << "{"
            <<    "int nanos_num_threads = nanos_omp_get_num_threads();"
            <<    thread_initializing_reduction_info
            <<    "err = nanos_release_sync_init();"
            <<    "if (err != NANOS_OK)"
            <<        "nanos_handle_error(err);"
            << "}"
            << "else"
            << "{"
            <<    "err = nanos_wait_sync_init();"
            <<    "if (err != NANOS_OK)"
            <<        "nanos_handle_error(err);"
            <<    thread_fetching_reduction_info
            << "}"
            << "}"
            ;

        for (TL::ObjectList<OutlineDataItem*>::iterator it = reduction_items.begin();
                it != reduction_items.end();
                it++)
        {
            std::string nanos_red_name = "nanos_red_" + (*it)->get_symbol().get_name();

            std::pair<OpenMP::Reduction*, TL::Type> reduction_info = (*it)->get_reduction_info();
            OpenMP::Reduction* reduction = reduction_info.first;
            TL::Type reduction_type = reduction_info.second;

            if (reduction_type.is_any_reference())
                reduction_type = reduction_type.references_to();

            TL::Type reduction_element_type = reduction_type;
            if (IS_FORTRAN_LANGUAGE)
            {
                while (reduction_element_type.is_fortran_array())
                    reduction_element_type = reduction_element_type.array_element();
            }
            else
            {
                while (reduction_element_type.is_array())
                    reduction_element_type = reduction_element_type.array_element();
            }

            Source element_size;
            if (IS_FORTRAN_LANGUAGE)
            {
                if (reduction_type.is_fortran_array())
                {
                    // We need to parse this bit in Fortran
                    Source number_of_bytes;
                    number_of_bytes << "SIZE(" << (*it)->get_symbol().get_name() << ") * " << reduction_element_type.get_size();

                    element_size << as_expression(number_of_bytes.parse_expression(construct));
                }
                else
                {
                    element_size << "sizeof(" << as_type(reduction_type) << ")";
                }
            }
            else
            {
                element_size << "sizeof(" << as_type(reduction_type) << ")";
            }

            reduction_declaration
                << "nanos_reduction_t* " << nanos_red_name << ";"
                ;

            Source allocate_private_buffer, cleanup_code;

            Source num_scalars;

            TL::Symbol basic_reduction_function, vector_reduction_function;
            create_reduction_function(reduction, construct, reduction_type, basic_reduction_function, vector_reduction_function);
            (*it)->reduction_set_basic_function(basic_reduction_function);

            thread_initializing_reduction_info
                << "err = nanos_malloc((void**)&" << nanos_red_name << ", sizeof(nanos_reduction_t), " 
                << "\"" << construct.get_filename() << "\", " << construct.get_line() << ");"
                << "if (err != NANOS_OK)"
                <<     "nanos_handle_error(err);"
                << nanos_red_name << "->original = (void*)" 
                <<            (reduction_type.is_array() ? "" : "&") << (*it)->get_symbol().get_name() << ";"
                << allocate_private_buffer
                << nanos_red_name << "->vop = "
                <<      (vector_reduction_function.is_valid() ? as_symbol(vector_reduction_function) : "0") << ";"
                << nanos_red_name << "->bop = (void(*)(void*,void*,int))" << as_symbol(basic_reduction_function) << ";"
                << nanos_red_name << "->element_size = " << element_size << ";"
                << nanos_red_name << "->num_scalars = " << num_scalars << ";"
                << cleanup_code
                << "err = nanos_register_reduction(" << nanos_red_name << ");"
                << "if (err != NANOS_OK)"
                <<     "nanos_handle_error(err);"
                ;

            if (IS_C_LANGUAGE
                    || IS_CXX_LANGUAGE)
            {
                if (reduction_type.is_array())
                {
                    num_scalars << "sizeof(" << as_type(reduction_type) << ") / sizeof(" << as_type(reduction_element_type) <<")";
                }
                else
                {
                    num_scalars << "1";
                }

                allocate_private_buffer
                    << "err = nanos_malloc(&" << nanos_red_name << "->privates, sizeof(" << as_type(reduction_type) << ") * nanos_num_threads, "
                    << "\"" << construct.get_filename() << "\", " << construct.get_line() << ");"
                    << "if (err != NANOS_OK)"
                    <<     "nanos_handle_error(err);"
                    << nanos_red_name << "->descriptor = " << nanos_red_name << "->privates;"
                    << "rdv_" << (*it)->get_field_name() << " = (" <<  as_type( (*it)->get_private_type().get_pointer_to() ) << ")" << nanos_red_name << "->privates;"
                    ;


                thread_fetching_reduction_info
                    << "err = nanos_reduction_get(&" << nanos_red_name << ", " 
                    << (reduction_type.is_array() ? "" : "&") << (*it)->get_symbol().get_name() << ");"

                    << "if (err != NANOS_OK)"
                    <<     "nanos_handle_error(err);"
                    << "rdv_" << (*it)->get_field_name() << " = (" <<  as_type( (*it)->get_private_type().get_pointer_to() ) << ")" << nanos_red_name << "->privates;"
                    ;
                cleanup_code
                    << nanos_red_name << "->cleanup = nanos_free0;"
                    ;
            }
            else if (IS_FORTRAN_LANGUAGE)
            {

                Type private_reduction_vector_type;

                Source extra_dims;
                {
                    TL::Type t = (*it)->get_symbol().get_type().no_ref();
                    int rank = 0;
                    if (t.is_fortran_array())
                    {
                        rank = t.fortran_rank();
                    }

                    if (rank != 0)
                    {
                        // We need to parse this bit in Fortran
                        Source size_call;
                        size_call << "SIZE(" << (*it)->get_symbol().get_name() << ")";

                        num_scalars << as_expression(size_call.parse_expression(construct));
                    }
                    else
                    {
                        num_scalars << "1";
                    }
                    private_reduction_vector_type = fortran_get_n_ranked_type_with_descriptor(
                            get_void_type(), rank + 1, construct.retrieve_context().get_decl_context());

                    int i;
                    for (i = 0; i < rank; i++)
                    {
                        Source lbound_src;
                        lbound_src << "LBOUND(" << (*it)->get_symbol().get_name() << ", DIM = " << (rank - i) << ")";
                        Source ubound_src;
                        ubound_src << "UBOUND(" << (*it)->get_symbol().get_name() << ", DIM = " << (rank - i) << ")";

                        extra_dims 
                            << "["
                            << as_expression(lbound_src.parse_expression(construct))
                            << ":"
                            << as_expression(ubound_src.parse_expression(construct))
                            << "]";

                        t = t.array_element();
                    }
                }

                allocate_private_buffer
                    << "@FORTRAN_ALLOCATE@((*rdv_" << (*it)->get_field_name() << ")[0:(nanos_num_threads-1)]" << extra_dims <<");"
                    << nanos_red_name << "->privates = &(*rdv_" << (*it)->get_field_name() << ");"
                    << "err = nanos_malloc(&" << nanos_red_name << "->descriptor, sizeof(" << as_type(private_reduction_vector_type) << "), "
                    << "\"" << construct.get_filename() << "\", " << construct.get_line() << ");"
                    << "if (err != NANOS_OK)"
                    <<     "nanos_handle_error(err);"
                    << "err = nanos_memcpy(" << nanos_red_name << "->descriptor, "
                    "&rdv_" << (*it)->get_field_name() << ", sizeof(" << as_type(private_reduction_vector_type) << "));"
                    << "if (err != NANOS_OK)"
                    <<     "nanos_handle_error(err);"
                    ;

                thread_fetching_reduction_info
                    << "err = nanos_reduction_get(&" << nanos_red_name << ", &" << (*it)->get_symbol().get_name() << ");"
                    << "if (err != NANOS_OK)"
                    <<     "nanos_handle_error(err);"
                    << "err = nanos_memcpy("
                    << "&rdv_" << (*it)->get_field_name() << ","
                    << nanos_red_name << "->descriptor, "
                    << "sizeof(" << as_type(private_reduction_vector_type) << "));"
                    << "if (err != NANOS_OK)"
                    <<     "nanos_handle_error(err);"
                    ;

                TL::Symbol reduction_cleanup = create_reduction_cleanup_function(reduction, construct);
                cleanup_code
                    << nanos_red_name << "->cleanup = " << as_symbol(reduction_cleanup) << ";"
                    ;
            }
            else
            {
                internal_error("Code unreachable", 0);
            }
        }

        FORTRAN_LANGUAGE()
        {
            Source::source_language = SourceLanguage::C;
        }
        ref_tree.replace(result.parse_statement(ref_tree));
        FORTRAN_LANGUAGE()
        {
            Source::source_language = SourceLanguage::Current;
        }
    }
Beispiel #16
0
    TL::Symbol new_function_symbol(
            TL::Symbol current_function,
            const std::string& name,
            TL::Type return_type,
            TL::ObjectList<std::string> parameter_names,
            TL::ObjectList<TL::Type> parameter_types)
    {
        if (IS_FORTRAN_LANGUAGE && current_function.is_nested_function())
        {
            // Get the enclosing function
            current_function = current_function.get_scope().get_related_symbol();
        }

        decl_context_t decl_context = current_function.get_scope().get_decl_context();

        ERROR_CONDITION(parameter_names.size() != parameter_types.size(), "Mismatch between names and types", 0);

        decl_context_t function_context;
        if (IS_FORTRAN_LANGUAGE)
        {
            function_context = new_program_unit_context(decl_context);
        }
        else
        {
            function_context = new_function_context(decl_context);
            function_context = new_block_context(function_context);
        }

        // Build the function type
        int num_parameters = 0;
        scope_entry_t** parameter_list = NULL;

        parameter_info_t* p_types = new parameter_info_t[parameter_types.size()];
        parameter_info_t* it_ptypes = &(p_types[0]);
        TL::ObjectList<TL::Type>::iterator type_it = parameter_types.begin();
        for (TL::ObjectList<std::string>::iterator it = parameter_names.begin();
                it != parameter_names.end();
                it++, it_ptypes++, type_it++)
        {
            scope_entry_t* param = new_symbol(function_context, function_context.current_scope, it->c_str());
            param->entity_specs.is_user_declared = 1;
            param->kind = SK_VARIABLE;
            param->locus = make_locus("", 0, 0);

            param->defined = 1;

            param->type_information = get_unqualified_type(type_it->get_internal_type());

            P_LIST_ADD(parameter_list, num_parameters, param);

            it_ptypes->is_ellipsis = 0;
            it_ptypes->nonadjusted_type_info = NULL;
            it_ptypes->type_info = get_indirect_type(param);
        }

        type_t *function_type = get_new_function_type(
                return_type.get_internal_type(),
                p_types,
                parameter_types.size());

        delete[] p_types;

        // Now, we can create the new function symbol
        scope_entry_t* new_function_sym = NULL;
        if (!current_function.get_type().is_template_specialized_type())
        {
            new_function_sym = new_symbol(decl_context, decl_context.current_scope, name.c_str());
            new_function_sym->entity_specs.is_user_declared = 1;
            new_function_sym->kind = SK_FUNCTION;
            new_function_sym->locus = make_locus("", 0, 0);
            new_function_sym->type_information = function_type;
        }
        else
        {
            scope_entry_t* new_template_sym = new_symbol(
                    decl_context, decl_context.current_scope, name.c_str());
            new_template_sym->kind = SK_TEMPLATE;
            new_template_sym->locus = make_locus("", 0, 0);

            new_template_sym->type_information = get_new_template_type(
                    decl_context.template_parameters,
                    function_type,
                    uniquestr(name.c_str()),
                    decl_context, make_locus("", 0, 0));

            template_type_set_related_symbol(new_template_sym->type_information, new_template_sym);

            // The new function is the primary template specialization
            new_function_sym = named_type_get_symbol(
                    template_type_get_primary_type(
                        new_template_sym->type_information));
        }

        function_context.function_scope->related_entry = new_function_sym;
        function_context.block_scope->related_entry = new_function_sym;

        new_function_sym->related_decl_context = function_context;

        new_function_sym->entity_specs.related_symbols = parameter_list;
        new_function_sym->entity_specs.num_related_symbols = num_parameters;
        for (int i = 0; i < new_function_sym->entity_specs.num_related_symbols; ++i)
        {
            symbol_set_as_parameter_of_function(
                    new_function_sym->entity_specs.related_symbols[i], new_function_sym, /* parameter position */ i);
        }

        // Make it static
        new_function_sym->entity_specs.is_static = 1;

        // Make it member if the enclosing function is member
        if (current_function.is_member())
        {
            new_function_sym->entity_specs.is_member = 1;
            new_function_sym->entity_specs.class_type = current_function.get_class_type().get_internal_type();

            new_function_sym->entity_specs.access = AS_PUBLIC;

            ::class_type_add_member(new_function_sym->entity_specs.class_type, new_function_sym);
        }

        if (current_function.is_inline())
            new_function_sym->entity_specs.is_inline = 1;

        // new_function_sym->entity_specs.is_defined_inside_class_specifier =
        //     current_function.get_internal_symbol()->entity_specs.is_defined_inside_class_specifier;

        if (IS_FORTRAN_LANGUAGE && current_function.is_in_module())
        {
            scope_entry_t* module_sym = current_function.in_module().get_internal_symbol();
            new_function_sym->entity_specs.in_module = module_sym;
            P_LIST_ADD(
                    module_sym->entity_specs.related_symbols,
                    module_sym->entity_specs.num_related_symbols,
                    new_function_sym);
            new_function_sym->entity_specs.is_module_procedure = 1;
        }

        return new_function_sym;
    }
Beispiel #17
0
TL::Source LoopDistribution::do_distribution()
{
    TL::Statement loop_body = _for_stmt.get_loop_body();

    if (!loop_body.is_compound_statement())
    {
        return _for_stmt.prettyprint();
    }

    TL::Source result;

    TL::Source distributed_loops, expanded_scalars;
    result
        << "{"
        << expanded_scalars
        << distributed_loops
        << "}"
        ;

    TL::ReplaceIdExpression escalar_expansion;
    if (!_expand.empty())
    {
        if (!_for_stmt.is_regular_loop())
        {
            return _for_stmt.prettyprint();
        }
        expanded_scalars
            << "int __loop_trip = (" << _for_stmt.get_upper_bound() << ") - (" << _for_stmt.get_lower_bound() << " + 1);"
            // Absolute value (calculated this way allows for conditional move instructions)
            << "__loop_trip = (__loop_trip < 0) ? (-__loop_trip) : __loop_trip;"
            ;
        // We need this because of array nature
        TL::AST_t array_expr;
        {
            TL::AST_t array_expr_ref_tree;
            Source temporal_parse;
            temporal_parse
                << "{"
                << expanded_scalars
                << statement_placeholder(array_expr_ref_tree)
                << "}"
                ;
            temporal_parse.parse_statement(_for_stmt.get_ast(),
                    _for_stmt.get_scope_link());

            array_expr = Source("__loop_trip").parse_expression(array_expr_ref_tree,
                    _for_stmt.get_scope_link());
        }

        for (TL::ObjectList<TL::Symbol>::iterator it = _expand.begin();
                it != _expand.end();
                it++)
        {
            TL::Symbol &sym(*it);

            std::string expanded_scalar_name = "_" + sym.get_name();

            TL::Type type = sym.get_type();
            TL::Type array_type = type.get_array_to(array_expr,
                    _for_stmt.get_scope_link().get_scope(array_expr));

            expanded_scalars
                << array_type.get_declaration(it->get_scope(), expanded_scalar_name) << ";";

            escalar_expansion.add_replacement(sym, 
                    expanded_scalar_name + "[" + _for_stmt.get_induction_variable().prettyprint() + "]" );
        }
    }


    TL::ObjectList<TL::Statement> statement_list = loop_body.get_inner_statements();

    for (TL::ObjectList<TL::Statement>::iterator it = statement_list.begin();
            it != statement_list.end();
            it++)
    {
        Statement &stmt(*it);
        distributed_loops
            << "for ( " << _for_stmt.get_iterating_init().prettyprint() // This one already includes ';'
            << _for_stmt.get_iterating_condition() << ";"
            << _for_stmt.get_iterating_expression() << ")"
            << "{"
            << escalar_expansion.replace(stmt)
            << "}"
            ;
    }

    return result;
}
Beispiel #18
0
    void LoweringVisitor::perform_partial_reduction(OutlineInfo& outline_info, Nodecl::NodeclBase ref_tree)
    {
        ERROR_CONDITION(ref_tree.is_null(), "Invalid tree", 0);

        Source reduction_code;

        TL::ObjectList<OutlineDataItem*> reduction_items = outline_info.get_data_items().filter(
                predicate(lift_pointer(functor(&OutlineDataItem::is_reduction))));
        if (!reduction_items.empty())
        {
            for (TL::ObjectList<OutlineDataItem*>::iterator it = reduction_items.begin();
                    it != reduction_items.end();
                    it++)
            {
                if (IS_C_LANGUAGE || IS_CXX_LANGUAGE)
                {
                    if ((*it)->get_private_type().is_array())
                    {
                        reduction_code
                            << "__builtin_memcpy(rdv_" << (*it)->get_field_name() << "[nanos_omp_get_thread_num()],"
                            << "rdp_" << (*it)->get_symbol().get_name() << ","
                            << " sizeof(" << as_type((*it)->get_private_type()) << "));"
                            ;
                    }
                    else
                    {
                        reduction_code
                            << "rdv_" << (*it)->get_field_name() << "[nanos_omp_get_thread_num()] "
                            << "= rdp_" << (*it)->get_symbol().get_name() << ";"
                            ;
                    }
                }
                else if (IS_FORTRAN_LANGUAGE)
                {
                    Source extra_dims;
                    {
                        TL::Type t = (*it)->get_symbol().get_type().no_ref();
                        int rank = 0;
                        if (t.is_fortran_array())
                        {
                            rank = t.fortran_rank();
                        }

                        int i;
                        for (i = 0; i < rank; i++)
                        {
                            extra_dims << ":,";
                        }
                    }

                    reduction_code
                        << "rdv_" << (*it)->get_field_name() << "( " << extra_dims << "nanos_omp_get_thread_num() ) = rdp_" << (*it)->get_symbol().get_name() << "\n"
                        ;
                }
                else
                {
                    internal_error("Code unreachable", 0);
                }
            }
        }

        ref_tree.replace(reduction_code.parse_statement(ref_tree));
    }
    static TL::Symbol create_initializer_function_fortran(
            OpenMP::Reduction* red,
            TL::Type reduction_type,
            Nodecl::NodeclBase construct)
    {
        std::string fun_name;
        {
            std::stringstream ss;
            ss << "nanos_ini_" << red << "_" << reduction_type.get_internal_type() << "_" << simple_hash_str(construct.get_filename().c_str());
            fun_name = ss.str();
        }

        Nodecl::NodeclBase initializer = red->get_initializer().shallow_copy();


        TL::Type omp_out_type = reduction_type,
                 omp_ori_type = reduction_type;

        // These sources are only used in array reductions
        TL::Source omp_out_extra_attributes,
            extra_stuff_array_red;

        if (reduction_type.is_array())
        {
            Source dims_descr;
            TL::Type t = reduction_type;
            int rank = 0;
            if (t.is_fortran_array())
            {
                rank = t.fortran_rank();
            }

            dims_descr << "(";
            omp_out_extra_attributes << ", POINTER, DIMENSION(";

            int i;
            for (i = 0; i < rank; i++)
            {
                if (i != 0)
                {
                    dims_descr << ",";
                    omp_out_extra_attributes << ",";
                }

                dims_descr << "LBOUND(omp_orig, DIM = " << (rank - i) << ")"
                    << ":"
                    << "UBOUND(omp_orig, DIM = " << (rank - i) << ")"
                    ;

                omp_out_extra_attributes << ":";
                t = t.array_element();
            }

            dims_descr << ")";
            omp_out_extra_attributes << ")";

            omp_out_type = t;

            extra_stuff_array_red << "ALLOCATE(omp_out" << dims_descr <<")\n";
        }

        Source src;
        src << "SUBROUTINE " << fun_name << "(omp_out, omp_orig)\n"
            <<    "IMPLICIT NONE\n"
            <<    as_type(omp_out_type) << omp_out_extra_attributes << " ::  omp_out\n"
            <<    as_type(omp_ori_type) <<  " :: omp_orig\n"
            <<    extra_stuff_array_red
            <<    "omp_out = " << as_expression(initializer) << "\n"
            << "END SUBROUTINE " << fun_name << "\n"
            ;

        TL::Scope global_scope = construct.retrieve_context().get_global_scope();
        Nodecl::NodeclBase function_code = src.parse_global(global_scope);
        TL::Symbol function_sym = global_scope.get_symbol_from_name(fun_name);

        ERROR_CONDITION(!function_sym.is_valid(), "Symbol %s not found", fun_name.c_str());

        // As the initializer function is needed during the instantiation of
        // the task, this function should be inserted before the construct
        Nodecl::Utils::prepend_to_enclosing_top_level_location(construct,
                function_code);

        return function_sym;
    }
TL::Source LoopUnroll::do_unroll()
{
	if (!_for_stmt.regular_loop())
	{
		return silly_unroll();
	}
	
    // Get parts of the loop
    IdExpression induction_var = _for_stmt.get_induction_variable();
    Expression lower_bound = _for_stmt.get_lower_bound();
    Expression upper_bound = _for_stmt.get_upper_bound();
    Expression step = _for_stmt.get_step();
    TL::Source operator_bound = _for_stmt.get_bound_operator();

    Statement loop_body = _for_stmt.get_loop_body();

    TL::Source result, epilogue, 
        main, induction_var_decl,
        before_main, after_main;

    std::stringstream ss;
    ss << _factor;

    result
        << "{"
        << induction_var_decl
        << before_main
        << main
        << after_main
        << epilogue
        << "}"
        ;

	Source replicated_body;
	Source epilogue_body;
	if (_factor > 1)
	{
		AST_t init = _for_stmt.get_iterating_init();
		if (Declaration::predicate(init))
		{
			TL::Symbol sym = induction_var.get_symbol();
			TL::Type type = sym.get_type();
			// Declare it since it will have local scope
			induction_var_decl
				<< type.get_declaration(sym.get_scope(), sym.get_name()) << ";"
				;
		}

		main
			<< "for (" << induction_var << " = " << lower_bound << ";"
			<< induction_var << operator_bound << "((" << upper_bound << ") - (" << _factor << " - 1)* (" << step << "));"
			<< induction_var << "+= (" << step << ") * " << _factor << ")"
			<< "{"
			<< replicated_body
			<< "}"
			;

		// FIXME - It could help to initialize here another variable and make both loops independent
		epilogue
			<< "for ( ; "  // No initialization, keep using the old induction var
			<< induction_var << operator_bound << upper_bound << ";"
			<< induction_var << "+= (" << step << "))"
			<< epilogue_body
			;

		if (!_remove_tasks)
		{
			epilogue_body << loop_body;
		}
		else
		{
			std::cerr << "Do not create task " << __FILE__ << ":" << __LINE__ << std::endl;
            running_error("Path not supported yet", 0);
			// epilogue_body << loop_body.get_ast().prettyprint_with_callback(functor(ignore_tasks));
		}
	}
	else
	{
		// Leave it as is
		main << "for(" << _for_stmt.get_iterating_init().prettyprint()
			<< _for_stmt.get_iterating_condition() << ";"
			<< _for_stmt.get_iterating_expression() << ")"
			<< "{"
			<< replicated_body
			<< "}"
			;
	}

    // Replicate the body
    bool consider_omp = false;

    if (TaskAggregation::contains_relevant_openmp(loop_body))
    {
        consider_omp = true;
    }

    if (_ignore_omp || !consider_omp)
    {
        simple_replication(_factor, replicated_body, epilogue_body,
                induction_var, loop_body);
    }
    else
    {
        omp_replication(_factor, replicated_body, epilogue_body,
                induction_var, loop_body, before_main, after_main);
    }

    return result;
}
    Type Type::fix_references_()
    {
        if ((IS_C_LANGUAGE && this->is_any_reference())
                || (IS_CXX_LANGUAGE && this->is_rebindable_reference()))
        {
            TL::Type ref = this->references_to();
            if (ref.is_array())
            {
                // T (&a)[10] -> T * const
                // T (&a)[10][20] -> T (* const)[20]
                ref = ref.array_element();
            }

            // T &a -> T * const a
            TL::Type ptr = ref.get_pointer_to();
            if (!this->is_rebindable_reference())
            {
                ptr = ptr.get_const_type();
            }
            return ptr;
        }
        else if (IS_FORTRAN_LANGUAGE && this->is_any_reference())
        {
            return this->references_to();
        }
        else if (this->is_array())
        {
            if (this->array_is_region())
            {
                Nodecl::NodeclBase lb, reg_lb, ub, reg_ub;
                this->array_get_bounds(lb, ub);
                this->array_get_region_bounds(reg_lb, reg_ub);
                TL::Scope sc = array_type_get_region_size_expr_context(this->get_internal_type());

                return this->array_element().fix_references_().get_array_to_with_region(lb, ub, reg_lb, reg_ub, sc);
            }
            else
            {
                Nodecl::NodeclBase size = this->array_get_size();
                TL::Scope sc = array_type_get_array_size_expr_context(this->get_internal_type());

                return this->array_element().fix_references_().get_array_to(size, sc);
            }
        }
        else if (this->is_pointer())
        {
            TL::Type fixed = this->points_to().fix_references_().get_pointer_to();

            cv_qualifier_t cv_qualif = CV_NONE;
            ::advance_over_typedefs_with_cv_qualif(this->get_internal_type(), &cv_qualif);

            fixed = ::get_cv_qualified_type(fixed.get_internal_type(), cv_qualif);

            return fixed;
        }
        else if (this->is_function())
        {
            // Do not fix unprototyped functions
            if (this->lacks_prototype())
                return (*this);

            cv_qualifier_t cv_qualif = CV_NONE;
            ::advance_over_typedefs_with_cv_qualif(this->get_internal_type(), &cv_qualif);

            ref_qualifier_t ref_qualifier = function_type_get_ref_qualifier(this->get_internal_type());
            TL::Type fixed_result = this->returns().fix_references_();
            bool has_ellipsis = 0;

            TL::ObjectList<TL::Type> fixed_parameters = this->parameters(has_ellipsis);
            for (TL::ObjectList<TL::Type>::iterator it = fixed_parameters.begin();
                    it != fixed_parameters.end();
                    it++)
            {
                *it = it->fix_references_();
            }

            TL::ObjectList<TL::Type> nonadjusted_fixed_parameters = this->nonadjusted_parameters();
            for (TL::ObjectList<TL::Type>::iterator it = nonadjusted_fixed_parameters.begin();
                    it != nonadjusted_fixed_parameters.end();
                    it++)
            {
                *it = it->fix_references_();
            }

            TL::Type fixed_function = fixed_result.get_function_returning(
                    fixed_parameters,
                    nonadjusted_fixed_parameters,
                    has_ellipsis,
                    ref_qualifier);

            fixed_function = TL::Type(get_cv_qualified_type(fixed_function.get_internal_type(), cv_qualif));

            return fixed_function;
        }
        // Note: we are not fixing classes
        else
        {
            // Anything else must be left untouched
            return (*this);
        }
    }