Example #1
0
    static nodecl_t make_list_helper(const TL::ObjectList<NodeclBase>::const_iterator& first, 
            const TL::ObjectList<NodeclBase>::const_iterator& last)
    {
        if (first == last)
        {
            if (first->is<Nodecl::List>())
            {
                return first->get_internal_nodecl();
            }
            else
            {
                return nodecl_make_list_1(first->get_internal_nodecl());
            }
        }
        else
        {
            nodecl_t previous_list =  make_list_helper(first, last - 1);

            if (last->is<Nodecl::List>())
            {
                return nodecl_concat_lists(previous_list, 
                        last->get_internal_nodecl());
            }
            else
            {
                return nodecl_append_to_list(previous_list, 
                        last->get_internal_nodecl());
            }
        }
    }
Example #2
0
 TL::ObjectList<NodeclBase> List::to_object_list() const
 {
     TL::ObjectList<NodeclBase> result;
     for (List::const_iterator it = this->begin(); it != this->end(); ++it)
     {
         result.append(*it);
     }
     return result;
 }
Example #3
0
void TL::Optimizations::strength_reduce(
        TL::ObjectList<Nodecl::NodeclBase>& list, 
        bool fast_math)
{
    for(TL::ObjectList<Nodecl::NodeclBase>::iterator it = list.begin();
            it != list.end();
            it++)
    {
        strength_reduce(*it, fast_math);
    }
}
Example #4
0
void TL::Optimizations::canonicalize_and_fold(
        const TL::ObjectList<Nodecl::NodeclBase>& list, 
        bool fast_math)
{
    ReduceExpressionVisitor exp_reducer;

    for(TL::ObjectList<Nodecl::NodeclBase>::const_iterator it = list.begin();
            it != list.end();
            it++)
    {
        canonicalize_and_fold(*it, fast_math);
    }
}
Example #5
0
bool DeviceFPGA::task_has_scalars(TL::ObjectList<OutlineDataItem*> & dataitems)
{
    for (ObjectList<OutlineDataItem*>::iterator it = dataitems.begin();
            it != dataitems.end();
            it++)
    {
        /*
         * We happily assume that everything that does not need a copy is a scalar
         * Which is true as long everything that is not a scalar is going to be copied
         * We could also use DataReference to check this
         * FIXME structs should be treated
         */
        if((*it)->get_copies().empty())
        {
            return true;
        }
    }
    return false;
}
    ObjectList<MemberDeclarationInfo> Type::get_member_declarations() const
    {
        TL::ObjectList<MemberDeclarationInfo> result;

        int num_decls = 0;

        member_declaration_info_t* mdi = ::class_type_get_member_declarations(_type_info, &num_decls);

        int i;
        for (i = 0; i < num_decls; i++)
        {
            result.push_back(
                    MemberDeclarationInfo(mdi[i].entry, mdi[i].decl_context, mdi[i].is_definition)
                    );
        }

        DELETE(mdi);

        return result;
    }
Example #7
0
void DeviceFPGA::copy_stuff_to_device_file(
        const TL::ObjectList<Nodecl::NodeclBase>& stuff_to_be_copied)
{
    for (TL::ObjectList<Nodecl::NodeclBase>::const_iterator it = stuff_to_be_copied.begin();
            it != stuff_to_be_copied.end();
            ++it)
    {
        if (it->is<Nodecl::FunctionCode>()
                || it->is<Nodecl::TemplateFunctionCode>())
        {
            TL::Symbol function = it->get_symbol();
            TL::Symbol new_function = SymbolUtils::new_function_symbol(function, function.get_name() + "_hls");

            Nodecl::Utils::SimpleSymbolMap symbol_map;
            symbol_map.add_map(function, new_function);
            _fpga_file_code.append(Nodecl::Utils::deep_copy(*it, *it, symbol_map));
        }
        else
        {
            _fpga_file_code.append(Nodecl::Utils::deep_copy(*it, *it));
        }
    }
}
void DeviceOpenCL::generate_ndrange_code(
        const TL::Symbol& called_task,
        const TL::Symbol& unpacked_function,
        const TargetInformation& target_info,
        const std::string filename,
        const std::string kernel_name,
        const TL::ObjectList<OutlineDataItem*>& data_items,
        Nodecl::Utils::SimpleSymbolMap* called_fun_to_outline_data_map,
        Nodecl::Utils::SimpleSymbolMap* outline_data_to_unpacked_fun_map,
        // Out
        TL::Source& code_ndrange)
{
    if (!Nanos::Version::interface_is_at_least("opencl", 1003))
    {
        return old_generate_ndrange_code(
                called_task,
                unpacked_function,
                target_info,
                filename,
                kernel_name,
                data_items,
                called_fun_to_outline_data_map,
                outline_data_to_unpacked_fun_map,
                code_ndrange);
    }

    // The arguments of the clauses 'ndrange' and 'shmem' must be updated because
    // they are not expressed in terms of the unpacked function parameters
    TL::ObjectList<Nodecl::NodeclBase> new_ndrange, new_shmem;
    update_ndrange_and_shmem_expressions(
            unpacked_function.get_related_scope(),
            target_info,
            outline_data_to_unpacked_fun_map,
            new_ndrange,
            new_shmem);

    // Prepare mapping for the call to the kernel
    TL::Source code_ndrange_aux;
    Nodecl::Utils::SimpleSymbolMap called_fun_to_unpacked_fun_map;

    const std::map<TL::Symbol, TL::Symbol>* called_fun_to_outline_data_map_simple =
        called_fun_to_outline_data_map->get_simple_symbol_map();
    for (std::map<TL::Symbol, TL::Symbol>::const_iterator it = called_fun_to_outline_data_map_simple->begin();
            it != called_fun_to_outline_data_map_simple->end();
            it++)
    {
        TL::Symbol key = it->first;
        TL::Symbol value = outline_data_to_unpacked_fun_map->map(it->second.get_internal_symbol());
        called_fun_to_unpacked_fun_map.add_map(key, value);
    }

    // The syntax of ndrange is
    //
    //     ndrange(N, global-list [, local-list])
    //
    // Each X-list has as much as N elements

    Nodecl::NodeclBase num_dims_expr = new_ndrange[0];

    // N must be a constant
    if (!num_dims_expr.is_constant())
    {
        fatal_printf_at(num_dims_expr.get_locus(),
                "first argument in 'ndrange' clause must be constant\n");
    }

    // At this point we can remove "N" from the new_ndrange list (pop_front)
    new_ndrange.erase(new_ndrange.begin());

    // N must be between 1 and 3
    int num_dims = const_value_cast_to_signed_int(num_dims_expr.get_constant());
    if (num_dims < 1 || num_dims > 3)
    {
        fatal_printf_at(num_dims_expr.get_locus(),
                "number of dimensions for 'ndrange' clause is not 1, 2 or 3\n");
    }

    // Checking the number of remaining expressions in the new_ndrange list
    if (num_dims != (int)new_ndrange.size()
            && (num_dims * 2) != (int)new_ndrange.size())
    {
        fatal_printf_at(num_dims_expr.get_locus(),
                "a 'ndrange(%d, argument-list)' clause requires %d or %d arguments in argument-list\n",
                num_dims,
                num_dims ,
                num_dims * 2);
    }

    std::string compiler_options;
    if (CURRENT_CONFIGURATION->opencl_build_options != NULL)
    {
        compiler_options = std::string(CURRENT_CONFIGURATION->opencl_build_options);
    }

    // Create OpenCL kernel
    code_ndrange_aux << "nanos_err_t nanos_err;"
                     << "void* ompss_kernel_ocl = nanos_create_current_kernel(\""
                     <<         kernel_name << "\",\""
                     <<         filename << "\","
                     <<         "\"" << compiler_options << "\");";

    // Prepare setArgs
    TL::ObjectList<Nodecl::NodeclBase> global_list;
    TL::ObjectList<Nodecl::NodeclBase> local_list;

    unsigned int index_local = 0;
    TL::ObjectList<TL::Symbol> parameters_called = called_task.get_function_parameters();
    for (unsigned int i = 0; i < parameters_called.size(); ++i)
    {
        TL::Symbol unpacked_argument = called_fun_to_unpacked_fun_map.map(parameters_called[i]);

        // The attribute __global is deduced: the current argument will be __global if it has any copies
        bool is_global = false;
        if (unpacked_argument.get_type().no_ref().is_pointer()
                || unpacked_argument.get_type().no_ref().is_array())
        {
            for (TL::ObjectList<OutlineDataItem*>::const_iterator it = data_items.begin();
                    it != data_items.end() && !is_global;
                    ++it)
            {
                TL::Symbol outline_data_item_sym = (*it)->get_symbol();

                // If the outline data item has not a valid symbol, skip it
                if (!outline_data_item_sym.is_valid())
                    continue;

                // If the symbol of the current outline data item is not the
                // same as the unpacked_argument, skip it
                if(outline_data_to_unpacked_fun_map->map(outline_data_item_sym.get_internal_symbol()) != unpacked_argument)
                    continue;

                is_global = !((*it)->get_copies().empty());
            }
        }

        bool is_local = !is_global && unpacked_argument.get_type().no_ref().is_pointer();

        if (is_global)
        {
            code_ndrange_aux
                << "nanos_err = nanos_opencl_set_bufferarg("
                <<      "ompss_kernel_ocl, "
                <<      i << ", "
                <<      as_symbol(unpacked_argument) <<");";
        }
        else if (is_local)
        {
            TL::Source sizeof_arg;
            if (index_local >= new_shmem.size())
            {
                warn_printf_at(called_task.get_locus(),
                        "the size of the local symbol '%s' has not been specified in the 'shmem' clause, assuming zero\n",
                        unpacked_argument.get_name().c_str());

                sizeof_arg << "0";
            }
            else
            {
                sizeof_arg << as_expression(new_shmem[index_local]);
            }

            code_ndrange_aux << "nanos_err = nanos_opencl_set_arg("
                <<      "ompss_kernel_ocl, "
                <<      i << ", "
                <<      sizeof_arg << ", "
                <<      "0);";
            ++index_local;
        }
        else
        {
            code_ndrange_aux << "nanos_err = nanos_opencl_set_arg("
                <<      "ompss_kernel_ocl, "
                <<      i << ", "
                <<      "sizeof(" << as_type(unpacked_argument.get_type().no_ref()) << "), "
                <<      "&" << as_symbol(unpacked_argument) <<");";
        }
    }


    //Build arrays with information from ndrange clause or pointing to the ndrange pointers
    if (num_dims * 2 == (int)new_ndrange.size())
    {
        // ndrange(global-list, local-list)
        int i = 0;
        for (; i < num_dims; i++)
        {
            global_list.append(new_ndrange[i]);
        }
        for (; i < num_dims*2; i++)
        {
            local_list.append(new_ndrange[i]);
        }
    }
    // locals are not specified here
    else if (num_dims == (int)new_ndrange.size())
    {
        // ndrange(global-list)
        int i = 0;
        for (int k = 0; k < num_dims; k++, i++)
        {
            global_list.append(new_ndrange[i]);
        }
    }
    else
    {
        internal_error("Code unreachable", 0);
    }

    bool there_is_local_size = !local_list.empty();

    // Prepare ndrange calc pointers and arrays
    if (there_is_local_size)
    {
        code_ndrange_aux
            << "size_t local_size_arr[" << num_dims << "];"
            ;
    }
    code_ndrange_aux
        << "size_t global_size_arr[" << num_dims << "];"
        ;

    for (int i = 0; i < num_dims; i++)
    {
        if (there_is_local_size)
        {
            code_ndrange_aux
                << "local_size_arr[" << i << "] = " << as_expression(local_list[i]) << ";"
                ;
        }
        code_ndrange_aux
            << "global_size_arr[" << i << "] = " << as_expression(global_list[i]) << ";"
            ;
    }

    if (there_is_local_size)
    {
        // Launch kernel/ it will be freed inside, with ndrange calculated inside the checkDim loop
        code_ndrange_aux << "nanos_err = nanos_exec_kernel(ompss_kernel_ocl, " << num_dims << ", local_size_arr, global_size_arr);"
            ;
    }
    else
    {
        // Let the runtime choose the best local size
        code_ndrange_aux << "nanos_err = nanos_profile_exec_kernel(ompss_kernel_ocl, " << num_dims << ", global_size_arr);"
            ;
    }

    if (IS_FORTRAN_LANGUAGE)
    {
        Source::source_language = SourceLanguage::C;

        Nodecl::NodeclBase code_ndrange_tree = code_ndrange_aux.parse_statement(unpacked_function.get_related_scope());

        Source::source_language = SourceLanguage::Current;

        code_ndrange << as_statement(code_ndrange_tree);
    }
    else
    {
        code_ndrange << code_ndrange_aux;
    }
}
// Old version - Deprecated. Kept here for compatibility with old runtimes (Nanos++ 0.7)
void DeviceOpenCL::old_generate_ndrange_code(
        const TL::Symbol& called_task,
        const TL::Symbol& unpacked_function,
        const TargetInformation& target_info,
        const std::string filename,
        const std::string kernel_name,
        const TL::ObjectList<OutlineDataItem*>& data_items,
        Nodecl::Utils::SimpleSymbolMap* called_fun_to_outline_data_map,
        Nodecl::Utils::SimpleSymbolMap* outline_data_to_unpacked_fun_map,
        // Out
        TL::Source& code_ndrange)
{
    // The arguments of the clauses 'ndrange' and 'shmem' must be updated because
    // they are not expressed in terms of the unpacked function parameters
    TL::ObjectList<Nodecl::NodeclBase> new_ndrange, new_shmem;
    update_ndrange_and_shmem_expressions(
            unpacked_function.get_related_scope(),
            target_info,
            outline_data_to_unpacked_fun_map,
            new_ndrange,
            new_shmem);

    int num_args_ndrange = new_ndrange.size();

    TL::Source code_ndrange_aux;
    Nodecl::Utils::SimpleSymbolMap called_fun_to_unpacked_fun_map;

    const std::map<TL::Symbol, TL::Symbol>* called_fun_to_outline_data_map_simple =
        called_fun_to_outline_data_map->get_simple_symbol_map();
    for (std::map<TL::Symbol, TL::Symbol>::const_iterator it = called_fun_to_outline_data_map_simple->begin();
            it != called_fun_to_outline_data_map_simple->end();
            it++)
    {
        TL::Symbol key = it->first;
        TL::Symbol value = outline_data_to_unpacked_fun_map->map(it->second.get_internal_symbol());
        called_fun_to_unpacked_fun_map.add_map(key, value);
    }

    bool dim_const = new_ndrange[0].is_constant();

    char is_null_ended = 0;
    bool check_dim = !(new_ndrange[num_args_ndrange - 1].is_constant()
            && const_value_is_string(new_ndrange[num_args_ndrange - 1].get_constant())
            && (strcmp(const_value_string_unpack_to_string(new_ndrange[num_args_ndrange-1].get_constant(), &is_null_ended),
                    "noCheckDim") == 0));

    int num_dim = 0;
    if (dim_const)
    {
        num_dim = const_value_cast_to_4(new_ndrange[0].get_constant());

        ERROR_CONDITION(num_dim < 1 || num_dim > 3,
                "invalid number of dimensions for 'ndrange' clause. Valid values: 1, 2 and 3." , 0);

        ERROR_CONDITION((((num_dim * 3) + 1 + !check_dim) != num_args_ndrange)
                && (((num_dim * 2) + 1 + !check_dim) != num_args_ndrange),
                "invalid number of arguments for 'ndrange' clause", 0);
    }

    std::string compiler_opts;
    if (CURRENT_CONFIGURATION->opencl_build_options != NULL)
    {
        compiler_opts = std::string(CURRENT_CONFIGURATION->opencl_build_options);
    }

    //Create OCL Kernel
    code_ndrange_aux << "nanos_err_t nanos_err;"
                     << "void* ompss_kernel_ocl = nanos_create_current_kernel(\""
                     <<         kernel_name << "\",\""
                     <<         filename << "\",\""
                     <<         compiler_opts << "\");";

    //Prepare setArgs
    unsigned int index_local = 0;
    TL::ObjectList<TL::Symbol> parameters_called = called_task.get_function_parameters();
    for (unsigned int i = 0; i < parameters_called.size(); ++i)
    {
        TL::Symbol unpacked_argument = called_fun_to_unpacked_fun_map.map(parameters_called[i]);

        // The attribute __global is deduced: the current argument will be __global if it has any copies
        bool is_global = false;
        if (unpacked_argument.get_type().no_ref().is_pointer()
                || unpacked_argument.get_type().no_ref().is_array())
        {
            for (TL::ObjectList<OutlineDataItem*>::const_iterator it = data_items.begin();
                    it != data_items.end() && !is_global;
                    ++it)
            {
                TL::Symbol outline_data_item_sym = (*it)->get_symbol();

                // If the outline data item has not a valid symbol, skip it
                if (!outline_data_item_sym.is_valid())
                    continue;

                // If the symbol of the current outline data item is not the
                // same as the unpacked_argument, skip it
                if(outline_data_to_unpacked_fun_map->map(outline_data_item_sym.get_internal_symbol()) != unpacked_argument)
                    continue;

                is_global = !((*it)->get_copies().empty());
            }
        }

        bool is_local = !is_global && unpacked_argument.get_type().no_ref().is_pointer();

        if (is_global)
        {
            code_ndrange_aux
                << "nanos_err = nanos_opencl_set_bufferarg("
                <<      "ompss_kernel_ocl, "
                <<      i << ", "
                <<      as_symbol(unpacked_argument) <<");";
        }
        else if (is_local)
        {
            TL::Source sizeof_arg;
            if (index_local >= new_shmem.size())
            {
                warn_printf_at(called_task.get_locus(),
                        "the size of the local symbol '%s' has not been specified in the 'shmem' clause, assuming zero\n",
                        unpacked_argument.get_name().c_str());

                sizeof_arg << "0";
            }
            else
            {
                sizeof_arg << as_expression(new_shmem[index_local]);
            }

            code_ndrange_aux << "nanos_err = nanos_opencl_set_arg("
                <<      "ompss_kernel_ocl, "
                <<      i << ", "
                <<      sizeof_arg << ", "
                <<      "0);";
            ++index_local;
        }
        else
        {
            code_ndrange_aux << "nanos_err = nanos_opencl_set_arg("
                <<      "ompss_kernel_ocl, "
                <<      i << ", "
                <<      "sizeof(" << as_type(unpacked_argument.get_type().no_ref()) << "), "
                <<      "&" << as_symbol(unpacked_argument) <<");";
        }
    }


    //Build arrays with information from ndrange clause or pointing to the ndrange pointers
    if (!dim_const)
    {
        if (IS_FORTRAN_LANGUAGE)
        {
            internal_error("The number of dimensions is non-constant. This feature is not implemented yet in Fortran.", 0);
        }

        //Prepare ndrange calc pointers and arrays
        code_ndrange_aux
            << "int num_dim = " << as_expression(new_ndrange[0]) <<";"
            << "size_t offset_tmp[num_dim];"
            << "size_t offset_arr[num_dim];"
            << "size_t local_size_arr[num_dim];"
            << "size_t global_size_arr[num_dim];"
            << "size_t* local_size_ptr;"
            << "size_t* offset_ptr;"
            << "size_t* global_size_ptr;"
            << "size_t* final_local_size_ptr;"
            << as_type(TL::Type::get_bool_type()) << " local_size_zero = 0;"
            << "int i = 0;"
            ;
        if (num_args_ndrange == 3)
        {
            code_ndrange_aux
                << "for (i = 0; i < num_dim; ++i)"
                << "{"
                <<     "offset_tmp[i] = 0;"
                << "}"
                << "offset_ptr = offset_tmp;"
                << "global_size_ptr = " << as_expression(new_ndrange[1]) << ";"
                << "local_size_ptr = " << as_expression(new_ndrange[2]) << ";"
                ;
        }
        else if (num_args_ndrange == 4)
        {
            code_ndrange_aux
                << "offset_ptr = " << as_expression(new_ndrange[1]) << ";"
                << "global_size_ptr = " << as_expression(new_ndrange[2]) << ";"
                << "local_size_ptr = " << as_expression(new_ndrange[3]) << ";"
                ;
        }
        else
        {
            WARNING_MESSAGE("Invalid number of parameters for ndrange, when number of dimensions is not const, it must be 3 or 4",0);
        }

        //Check if local_size has zeros
        code_ndrange_aux
            << "for (i = 0; i < num_dim; ++i)"
            << "{"
            <<     "if (local_size_ptr[i] == 0)"
            <<     "{"
            <<         "local_size_zero = 1;"
            <<     "}"
            << " }"
            << "if (local_size_zero)"
            << "{"
            <<     "for (i = 0; i < num_dim; ++i)"
            <<     "{"
            <<         "local_size_ptr[i] = 1;"
            <<     "}"
            << "}"
            ;

        //Now do the rounding
        if (check_dim)
        {
            code_ndrange_aux
                << "for (i = 0; i < num_dim; ++i)"
                << "{"
                <<     "offset_arr[i] = offset_ptr[i];"

                <<     "local_size_arr[i] = (global_size_ptr[i] < local_size_ptr[i]) ? "
                <<         "global_size_ptr[i] : local_size_ptr[i];"

                <<     "global_size_arr[i] = (global_size_ptr[i] < local_size_ptr[i]) ? "
                <<         "global_size_ptr[i] : global_size_ptr[i] + ("
                <<             "(global_size_ptr[i] % local_size_ptr[i] == 0) ? "
                <<                  "0 : (local_size_ptr[i] - global_size_ptr[i] % local_size_ptr[i]));"
                << "}"
                ;
        }

        if (check_dim)
        {
            code_ndrange_aux
                << "if (local_size_zero)"
                << "{"
                <<     "final_local_size_ptr = 0;"
                << "}"
                << "else"
                << "{"
                <<     "final_local_size_ptr = local_size_arr;"
                << "}"
                //Launch kernel/ it will be freed inside, with ndrange calculated inside the checkDim loop
                << "nanos_exec_kernel(ompss_kernel_ocl, num_dim, offset_arr, final_local_size_ptr, global_size_arr);";
            ;
        }
        else
        {
            code_ndrange_aux
                << "if (local_size_zero)"
                << "{"
                <<     "final_local_size_ptr = 0;"
                << "}"
                << "else"
                << "{"
                <<     "final_local_size_ptr = local_size_ptr;"
                << "}"
                << "nanos_exec_kernel(ompss_kernel_ocl, num_dim, offset_ptr, final_local_size_ptr, global_size_ptr);"
                ;
        }
    }
    else
    {
        int num_dim_offset = num_dim;

        //Prepare ndrange calc pointers and arrays
        code_ndrange_aux
            << "int num_dim = " << as_expression(new_ndrange[0]) <<";"
            << "size_t offset_arr[num_dim];"
            << "size_t local_size_arr[num_dim];"
            << "size_t global_size_arr[num_dim];"
            << as_type(TL::Type::get_bool_type()) << " local_size_zero;"
            << "local_size_zero = 0;"
            ;

        for (int i = 1; i <= num_dim; ++i)
        {
            if (((num_dim * 3) + 1 + !check_dim) != num_args_ndrange)
            {
                num_dim_offset = 0;
                code_ndrange_aux << "offset_arr[" << i-1 << "] = 0;";
            }
            else
            {
                code_ndrange_aux
                    << "offset_arr[" << i-1 << "] = " << as_expression(new_ndrange[i]) << ";";
            }

            code_ndrange_aux
                << "local_size_arr[" << i-1 << "] = " << as_expression(new_ndrange[num_dim + num_dim_offset + i]) << ";"
                << "if (local_size_arr[" << i - 1 << "] == 0)"
                << "{"
                <<      "local_size_zero = 1;"
                << "}"
                << "global_size_arr[" << i-1 << "] = " << as_expression(new_ndrange[num_dim_offset + i]) << ";"
                ;
        }

        //Now do the rounding
        if (check_dim)
        {
            code_ndrange_aux
                << "if (!local_size_zero)"
                << "{"
                <<      "int i;"
                <<      "for (i = 0; i < num_dim; i = i + 1)"
                <<      "{"
                <<           "if (global_size_arr[i] < local_size_arr[i])"
                <<           "{"
                <<               "local_size_arr[i] = global_size_arr[i];"
                <<           "}"
                <<           "else"
                <<           "{"
                <<               "if (global_size_arr[i] % local_size_arr[i] != 0)"
                <<               "{"
                <<                   "global_size_arr[i] = global_size_arr[i]"
                <<                       " + (local_size_arr[i] - global_size_arr[i] % local_size_arr[i]);"
                <<               "}"
                <<           "}"
                <<      "}"
                << "}"
                ;
        }

        code_ndrange_aux
            << "if (local_size_zero)"
            << "{"
            //Launch kernel/ it will be freed inside, with ndrange calculated inside the checkDim loop
            <<      "nanos_err = nanos_exec_kernel(ompss_kernel_ocl, num_dim, offset_arr, 0, global_size_arr);"
            << "}"
            << "else"
            << "{"
            //Launch kernel/ it will be freed inside, with ndrange calculated inside the checkDim loop
            <<      "nanos_err = nanos_exec_kernel(ompss_kernel_ocl, num_dim, offset_arr, local_size_arr, global_size_arr);"
            << "}"
            ;
    }

    if (IS_FORTRAN_LANGUAGE)
    {
        Source::source_language = SourceLanguage::C;

        Nodecl::NodeclBase code_ndrange_tree = code_ndrange_aux.parse_statement(unpacked_function.get_related_scope());

        Source::source_language = SourceLanguage::Current;

        code_ndrange << as_statement(code_ndrange_tree);
    }
    else
    {
        code_ndrange << code_ndrange_aux;
    }
}
Example #10
0
        static void add_copy_items(PragmaCustomLine construct, 
                DataEnvironment& data_sharing_environment,
                const ObjectList<Nodecl::NodeclBase>& list,
                TL::OmpSs::CopyDirection copy_direction,
                TL::OmpSs::TargetInfo& target_info,
                bool in_ompss_mode)
        {
            TL::ObjectList<TL::OmpSs::CopyItem> items;

            for (ObjectList<Nodecl::NodeclBase>::const_iterator it = list.begin();
                    it != list.end();
                    it++)
            {
                DataReference expr(*it);

                std::string warning;
                if (!expr.is_valid())
                {
                    expr.commit_diagnostic();
                    warn_printf_at(construct.get_locus(), "'%s' is not a valid copy data-reference, skipping\n",
                            expr.prettyprint().c_str());
                    continue;
                }

                // In OmpSs copies we may fix the data-sharing to something more natural
                if (in_ompss_mode)
                {
                    Symbol sym = expr.get_base_symbol();
                    // In OmpSs, the storage of a copy is always SHARED. Note that with this
                    // definition we aren't defining the data-sharings of the variables involved
                    // in that expression.
                    //
                    // About the data-sharings of the variables involved in the copy expression:
                    // - Fortran: the base symbol of the copy expression is always SHARED
                    // - C/C++:
                    //  * The base symbol of a trivial copy (i.e the expression is a symbol) must always be SHARED:
                    //          int x, a[10];
                    //          copy_inout(x) -> shared(x)
                    //          copy_inout(a) -> shared(a)
                    //  * The base symbol of an array expression or a reference to an array must be SHARED too:
                    //          copy_int a[10];
                    //          copy_inout(a[4])   -> shared(a)
                    //          copy_inout(a[1:2]) -> shared(a)
                    //  * The base symbol of a class member access must be shared too:
                    //          struct C { int z; } c;
                    //          copy_inout(c.z)       -> shared(c)
                    //  * Otherwise, the data-sharing of the base symbol is FIRSTPRIVATE:
                    //          int* p;
                    //          copy_inout(*p)     -> firstprivate(p)
                    //          copy_inout(p[10])  -> firstprivate(p)
                    //          copy_inout(p[1:2]) -> firstprivate(p)
                    //          copy_inout([10][20] p) -> firstprivate(p)
                    if (IS_FORTRAN_LANGUAGE)
                    {
                        data_sharing_environment.set_data_sharing(sym, DS_SHARED, DSK_IMPLICIT,
                                "the variable is mentioned in a copy and it did not have an explicit data-sharing");
                    }
                    else if (expr.is<Nodecl::Symbol>())
                    {
                        data_sharing_environment.set_data_sharing(sym, DS_SHARED, DSK_IMPLICIT,
                                "the variable is mentioned in a copy and it did not have an explicit data-sharing");
                    }
                    else if (sym.get_type().is_array()
                            || (sym.get_type().is_any_reference()
                                && sym.get_type().references_to().is_array()))
                    {
                        data_sharing_environment.set_data_sharing(sym, DS_SHARED, DSK_IMPLICIT,
                                "the variable is an array mentioned in a non-trivial copy "
                                "and it did not have an explicit data-sharing");
                    }
                    else if (sym.get_type().is_class())
                    {
                        data_sharing_environment.set_data_sharing(sym, DS_SHARED, DSK_IMPLICIT,
                                "the variable is an object mentioned in a non-trivial dependence "
                                "and it did not have an explicit data-sharing");
                    }
                    else
                    {
                        data_sharing_environment.set_data_sharing(sym, DS_FIRSTPRIVATE, DSK_IMPLICIT,
                                "the variable is a non-array mentioned in a non-trivial copy "
                                "and it did not have an explicit data-sharing");
                    }
                }

                TL::OmpSs::CopyItem copy_item(expr, copy_direction);
                items.append(copy_item);
            }

            switch (copy_direction)
            {
                case TL::OmpSs::COPY_DIR_IN:
                    {
                        target_info.append_to_copy_in(items);
                        break;
                    }
                case TL::OmpSs::COPY_DIR_OUT:
                    {
                        target_info.append_to_copy_out(items);
                        break;
                    }
                case TL::OmpSs::COPY_DIR_INOUT:
                    {
                        target_info.append_to_copy_inout(items);
                        break;
                    }
                default:
                    {
                        internal_error("Unreachable code", 0);
                    }
            }
        }
Example #11
0
        void VectorizerVisitorFunction::visit(const Nodecl::FunctionCode& function_code)
        {
            // Set up enviroment
            _environment._external_scope =
                function_code.retrieve_context();
            _environment._local_scope_list.push_back(
                    function_code.get_statements().retrieve_context());

            // Get analysis info
            Vectorizer::initialize_analysis(function_code);

            // Push FunctionCode as scope for analysis
            _environment._analysis_scopes.push_back(function_code);

            //Vectorize function type and parameters
            TL::Symbol vect_func_sym = function_code.get_symbol();
            TL::Type func_type = vect_func_sym.get_type();
            TL::ObjectList<TL::Symbol> parameters = vect_func_sym.get_function_parameters();
            TL::ObjectList<TL::Type> parameters_type = func_type.parameters();

            TL::ObjectList<TL::Type> parameters_vector_type;
            
            TL::ObjectList<TL::Type>::iterator it_type;
            TL::ObjectList<TL::Symbol>::iterator it_param_sym;
            
            for(it_param_sym = parameters.begin(), it_type = parameters_type.begin();
                    it_type != parameters_type.end();
                    it_param_sym++, it_type++)
            {
                TL::Type sym_type = get_qualified_vector_to((*it_type), _environment._vector_length);

                // Set type to parameter TL::Symbol
                (*it_param_sym).set_type(sym_type);

                parameters_vector_type.append(sym_type);
            }


            if(_masked_version)
            {
                TL::Scope scope = vect_func_sym.get_related_scope();

                // Create mask parameter
                TL::Symbol mask_sym = scope.new_symbol("__mask_param");
                mask_sym.get_internal_symbol()->kind = SK_VARIABLE;
                mask_sym.get_internal_symbol()->entity_specs.is_user_declared = 1;
                mask_sym.set_type(TL::Type::get_mask_type(_environment._mask_size));
               
                symbol_set_as_parameter_of_function(mask_sym.get_internal_symbol(), 
                        vect_func_sym.get_internal_symbol(),
                        parameters.size());

                // Add mask symbol and type to parameters
                parameters.append(mask_sym);
                parameters_vector_type.append(mask_sym.get_type());
                vect_func_sym.set_related_symbols(parameters);

                // Take care of default_argument_info_t*
                //TODO: Move this into a function
                {
                int num_parameters =
                    vect_func_sym.get_internal_symbol()->entity_specs.num_parameters;
                default_argument_info_t** default_argument_info =
                    vect_func_sym.get_internal_symbol()->entity_specs.default_argument_info;

                num_parameters++;
                default_argument_info = (default_argument_info_t**)xrealloc(default_argument_info,
                        num_parameters * sizeof(*default_argument_info));
                default_argument_info[num_parameters-1] = NULL;

                vect_func_sym.get_internal_symbol()->entity_specs.default_argument_info = default_argument_info;
                vect_func_sym.get_internal_symbol()->entity_specs.num_parameters = num_parameters;
                }

                Nodecl::Symbol mask_nodecl_sym = 
                    mask_sym.make_nodecl(true, function_code.get_locus());

                _environment._mask_list.push_back(mask_nodecl_sym);
            }
            else // Add MaskLiteral to mask_list
            {
                Nodecl::MaskLiteral all_one_mask =
                    Nodecl::MaskLiteral::make(
                            TL::Type::get_mask_type(_environment._mask_size),
                            const_value_get_minus_one(_environment._mask_size, 1),
                            make_locus("", 0, 0));

                _environment._mask_list.push_back(all_one_mask);
            }

            vect_func_sym.set_type(get_qualified_vector_to(func_type.returns(), 
                        _environment._vector_length).get_function_returning(parameters_vector_type));

            // Vectorize function statements
            VectorizerVisitorStatement visitor_stmt(_environment);
            visitor_stmt.walk(function_code.get_statements());

            // Add final return if multi-return function
            if (_environment._function_return.is_valid())
            {
                // Return value
                Nodecl::Symbol return_value= _environment._function_return.make_nodecl(
                        false, function_code.get_locus());

//                VectorizerVisitorExpression visitor_sym(_environment);
//                visitor_sym.walk(return_value);

                // Return value at the end of the Compound Statement
                Nodecl::ReturnStatement return_stmt =
                    Nodecl::ReturnStatement::make(return_value, function_code.get_locus());

                function_code.get_statements().as<Nodecl::Context>().get_in_context().as<Nodecl::List>()
                    .front().as<Nodecl::CompoundStatement>().get_statements()
                    .as<Nodecl::List>().append(return_stmt);
            }
            

            _environment._analysis_scopes.pop_back();
            _environment._mask_list.pop_back();

            // Analysis in functions won't be reused anywhere so it must be freed
            Vectorizer::finalize_analysis();
        }
Example #12
0
void DeviceFPGA::add_hls_pragmas(
        Nodecl::NodeclBase &task,
        TL::ObjectList<OutlineDataItem*> &data_items
        )
{
    /*
     * Insert hls pragmas in order to denerate input/output connections
     * Every parameter needs a directive:
     * scalar: create plain wire connections:
     *      #pragma HLS INTERFACE ap_none port=VAR
     *      #pragma AP resource core=AXI_SLAVE variable=VAR metadata="-bus_bundle AXIlite"
     *
     * Array; create fifo port to be handled by axi stream
     *      #pragma HLS stream variable=VAR <-- NOT NEEDED
     *      #pragma HLS resource core=AXI4Stream variable=VAR
     *      #pragma HLS interface ap_fifo port=VAR
     *
     * For every task there is a control bus defined to kick the accelerator off:
     *
     * #pragma AP resource core=AXI_SLAVE variable=return metadata="-bus_bundle AXIlite" \
     *      port_map={{ap_start START} {ap_done DONE} {ap_idle IDLE} {ap_return RETURN}}
     *
     * All of this stuff must be inside the function body i.e.
     *
     * void foo(...)
     * {
     *     pragma stuff
     *     function body
     * }
     *
     */

    //see what kind of ast it really is

    std::cerr << ast_node_type_name(task.get_kind()) 
        << " in_list: " << task.is_in_list()
        << " locus: " << task.get_locus()
        << std::endl;

    //Dig into the tree and find where the function statements are
    ObjectList<Nodecl::NodeclBase> tchildren = task.children();
    Nodecl::NodeclBase& context = tchildren.front();
    ObjectList<Nodecl::NodeclBase> cchildren = context.children();
    Nodecl::List list(cchildren.front().get_internal_nodecl());
    Nodecl::List stlist(list.begin()->children().front().get_internal_nodecl());

    Nodecl::UnknownPragma ctrl_bus = Nodecl::UnknownPragma::make(
        "AP resource core=AXI_SLAVE variable=return metadata=\"-bus_bundle AXIlite\" port_map={{ap_start START} {ap_done DONE} {ap_idle IDLE} {ap_return RETURN}}");
    stlist.prepend(ctrl_bus);


    //since we are using prepend, everything is going to appar in reverse order
    //but this may not be a real issue
//    TL::ObjectList<OutlineDataItem*> data_items = outline_info.get_data_items();
    for (TL::ObjectList<OutlineDataItem*>::iterator it = data_items.begin();
            it != data_items.end();
            it++)
    {
        std::string field_name = (*it)->get_field_name();
        Nodecl::UnknownPragma pragma_node;

        if ((*it)->get_copies().empty())
        {
            //set scalar argumenit pragmas
            pragma_node = Nodecl::UnknownPragma::make("HLS INTERFACE ap_none port=" + field_name);
            stlist.prepend(pragma_node);

            pragma_node = Nodecl::UnknownPragma::make("AP resource core=AXI_SLAVE variable="
                    + field_name
                    + " metadata=\"-bus_bundle AXIlite\"");
            stlist.prepend(pragma_node);
        }
        else
        {
            //set array/stream pragmas
            pragma_node = Nodecl::UnknownPragma::make(
                    "HLS resource core=AXI4Stream variable=" + field_name);
            stlist.prepend(pragma_node);
            pragma_node = Nodecl::UnknownPragma::make(
                    "HLS interface ap_fifo port=" + field_name);
            stlist.prepend(pragma_node);
            
        }
    }
}
Example #13
0
/*
 * We may need to set scalar arguments here, but not transfers
 */
Source DeviceFPGA::fpga_param_code(
        TL::ObjectList<OutlineDataItem*> &data_items,
        Nodecl::Utils::SymbolMap *symbol_map,//we may not need it
        Scope sc
        )
{

    //Nodecl::Utils::SimpleSymbolMap *ssmap = (Nodecl::Utils::SimpleSymbolMap*)symbol_map;
    //TL::ObjectList<OutlineDataItem*> data_items = outline_info.get_data_items();
    Source args_src;

    /*
     * Get the fpga handle to write the data that we need.
     *
     * TODO: Make sure mmap + set arg does not break when we don't have scalar arguments
     */
    args_src
        << "int fd = open(\"/dev/mem\", NANOS_O_RDWR);"    //2=O_RDWR
//        << "unsigned int acc_addr = NANOS_AXI_BASE_ADDRESS;"
//        << "printf(\"address: %x\\n\", acc_addr);"
        << "unsigned int *acc_handle = "
        << "    (unsigned int *) mmap(0, NANOS_MMAP_SIZE,"     //0=NULL
        << "    NANOS_PROT_READ|NANOS_PROT_WRITE, NANOS_MAP_SHARED,"           //"        PROT_READ | PROT_WRITE, MAP_SHARED"
        << "    fd, NANOS_AXI_BASE_ADDRESS);"
    ;

    //set scalar arguments
    /* FIXME
     * We assume that the base address to set scalar parameters
     * (which appears to be true)
     * In fact all of this is defined in the 
     *   impl/pcores/foo_top_v1_00_a/include/xfoo_AXIlite.h
     * where foo is the name of the function and top_v1_00_a is the version name
     * This path may change so we are assuming base addres does not
     */

    /*
     * Parameter have an offset of 8 bytes with the preceding one (except for 64bit ones)
     * If any parameter is smaller than 32bit (4byte), padding is added in between
     * If a paramater is 64bit(aka long long int) another 32bit of padding are added 
     */

    int argIndex = 0x14/4;  //base address/(sizeof(int)=4)
    for (TL::ObjectList<OutlineDataItem*>::iterator it = data_items.begin();
            it != data_items.end();
            it++)
    {
//        print_dataItem_info(*it, sc);
        Symbol outline_symbol = symbol_map->map((*it)->get_symbol());
        const TL::ObjectList<OutlineDataItem::CopyItem> &copies = (*it)->get_copies();

        //if copies are empty, we need to set the scalar value
        if (copies.empty())
        {
            const Type & type = (*it)->get_field_type();

            args_src
                << "acc_handle[" << argIndex << "] = "
                << outline_symbol.get_name() << ";"
            ;

            //+1 for field +1 for padding
            //we are adding an index to int[] => addresses are 4x
            argIndex+=2;
            if (type.get_size() >= 8)
            {
                argIndex ++;
            }
        }

    }

    /*
     * There should be a control bus mapped at 0x40440000
     * This is true if function has non-scalar parameters
     * To start the device we must set the first bt to 1
     */
    args_src << "acc_handle[0] = 1;"
        << "munmap(acc_handle, NANOS_MMAP_SIZE);"
        << "close(fd);"
        ;


    return args_src;
}
Example #14
0
 List List::make(const TL::ObjectList<NodeclBase>& list)
 {
     if (list.empty())
         return nodecl_null();
     return make_list_helper(list.begin(), list.end() - 1);
 }
Example #15
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;
    }