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