// We redefine the visitor of Nodecl::FunctionCode because we need to // visit first the internal functions and later the statements void LoweringVisitor::visit(const Nodecl::FunctionCode& function_code) { Nodecl::List stmts = function_code.get_statements().as<Nodecl::List>(); // First, traverse nested functions for (Nodecl::List::iterator it = stmts.begin(); it != stmts.end(); it++) { if (it->is<Nodecl::FunctionCode>()) { walk(*it); } } // Second, remaining statements for (Nodecl::List::iterator it = stmts.begin(); it != stmts.end(); it++) { if (!it->is<Nodecl::FunctionCode>()) { walk(*it); } } }
bool NodeclStaticInfo::is_constant_access( const Nodecl::NodeclBase& n ) const { bool result = true; if( n.is<Nodecl::ArraySubscript>( ) ) { Nodecl::ArraySubscript array = n.as<Nodecl::ArraySubscript>( ); //Check subscripted if ( !is_constant( array.get_subscripted( ) )) { return false; } // Check subscrips Nodecl::List subscript = array.get_subscripts( ).as<Nodecl::List>( ); Nodecl::List::iterator it = subscript.begin( ); for( ; it != subscript.end( ); ++it ) { // All dimensions must be constant if( !is_constant( *it ) ) { result = false; break; } } } return result; }
void Lower::lower_taskwait_with_dependences(const Nodecl::OpenMP::Taskwait& node) { Nodecl::List environment = node.get_environment().as<Nodecl::List>(); // Prepare if(0) task reusing environment and set TaskIsTaskwait flag Nodecl::NodeclBase zero_expr; if(IS_C_LANGUAGE || IS_CXX_LANGUAGE) { zero_expr = const_value_to_nodecl(const_value_get_unsigned_int(0)); } else // IS_FORTRAN_LANGUAGE { zero_expr = Nodecl::BooleanLiteral::make( TL::Type::get_bool_type(), const_value_get_zero(/* bytes */ 4, /* sign */0)); } environment.append(Nodecl::OpenMP::If::make(zero_expr)); environment.append(Nodecl::OpenMP::TaskIsTaskwait::make()); Nodecl::OpenMP::Task taskwait_task = Nodecl::OpenMP::Task::make( environment, Nodecl::List::make(Nodecl::EmptyStatement::make()), node.get_locus()); node.replace(taskwait_task); lower_task(node.as<Nodecl::OpenMP::Task>()); }
static void handle_ompss_opencl_deallocate_intrinsic( Nodecl::FunctionCall function_call, Nodecl::NodeclBase expr_stmt) { Nodecl::List arguments = function_call.get_arguments().as<Nodecl::List>(); ERROR_CONDITION(arguments.size() != 1, "More than one argument in ompss_opencl_deallocate call", 0); Nodecl::NodeclBase actual_argument = arguments[0]; ERROR_CONDITION(!actual_argument.is<Nodecl::FortranActualArgument>(), "Unexpected tree", 0); Nodecl::NodeclBase arg = actual_argument.as<Nodecl::FortranActualArgument>().get_argument(); TL::Symbol array_sym = ::fortran_data_ref_get_symbol(arg.get_internal_nodecl()); ERROR_CONDITION( !(array_sym.get_type().is_fortran_array() && array_sym.is_allocatable()) && !(array_sym.get_type().is_pointer() && array_sym.get_type().points_to().is_fortran_array()), "The argument of 'ompss_opencl_deallocate' intrinsic must be " "an allocatable array or a pointer to an array\n", 0); // Replace the current intrinsic call by a call to the Nanos++ API TL::Symbol ptr_of_arr_sym = get_function_ptr_of(array_sym, expr_stmt.retrieve_context()); TL::Source new_function_call; new_function_call << "CALL NANOS_OPENCL_DEALLOCATE_FORTRAN(" << ptr_of_arr_sym.get_name() << "("<< as_expression(arg) << "))\n" ; expr_stmt.replace(new_function_call.parse_statement(expr_stmt)); }
void VectorizerVisitorExpression::visit(const Nodecl::ArraySubscript& n) { // Computing new vector type TL::Type vector_type = n.get_type(); if (vector_type.is_lvalue_reference()) { vector_type = vector_type.references_to(); } vector_type = get_qualified_vector_to(vector_type, _vector_length); TL::Type basic_type = n.get_type(); if (basic_type.is_lvalue_reference()) { basic_type = basic_type.references_to(); } // Vector Load if (Vectorizer::_analysis_info->is_adjacent_access( Vectorizer::_analysis_scopes->back(), n)) { const Nodecl::VectorLoad vector_load = Nodecl::VectorLoad::make( Nodecl::Reference::make( Nodecl::ParenthesizedExpression::make( n.shallow_copy(), basic_type, n.get_locus()), basic_type.get_pointer_to(), n.get_locus()), vector_type, n.get_locus()); n.replace(vector_load); } else // Vector Gather { const Nodecl::NodeclBase base = n.get_subscripted(); const Nodecl::List subscripts = n.get_subscripts().as<Nodecl::List>(); ERROR_CONDITION(subscripts.size() > 1, "Vectorizer: Gather on multidimensional array is not supported yet!", 0); std::cerr << "Gather: " << n.prettyprint() << "\n"; Nodecl::NodeclBase strides = *subscripts.begin(); walk(strides); const Nodecl::VectorGather vector_gather = Nodecl::VectorGather::make( base.shallow_copy(), strides, vector_type, n.get_locus()); n.replace(vector_gather); } }
void VectorizerVectorReduction::vectorize_reduction(const TL::Symbol& scalar_symbol, TL::Symbol& vector_symbol, const Nodecl::NodeclBase& reduction_initializer, const std::string& reduction_name, const TL::Type& reduction_type, Nodecl::List& pre_nodecls, Nodecl::List& post_nodecls) { // Step1: ADD REDUCTION SYMBOLS vector_symbol.set_value(Nodecl::VectorPromotion::make( reduction_initializer.shallow_copy(), vector_symbol.get_type())); // Add new ObjectInit with the initialization Nodecl::ObjectInit reduction_object_init = Nodecl::ObjectInit::make(vector_symbol); pre_nodecls.append(reduction_object_init); // Step2: ADD VECTOR REDUCTION INSTRUCTIONS if(reduction_name.compare("+") == 0) { Nodecl::ExpressionStatement post_reduction_stmt = Nodecl::ExpressionStatement::make( Nodecl::VectorReductionAdd::make( scalar_symbol.make_nodecl(true), vector_symbol.make_nodecl(true), scalar_symbol.get_type())); post_nodecls.append(post_reduction_stmt); } else if (reduction_name.compare("-") == 0) { Nodecl::ExpressionStatement post_reduction_stmt = Nodecl::ExpressionStatement::make( Nodecl::VectorReductionMinus::make( scalar_symbol.make_nodecl(true), vector_symbol.make_nodecl(true), scalar_symbol.get_type())); post_nodecls.append(post_reduction_stmt); } }
void ExtensibleGraph::propagate_arguments_in_function_graph( Nodecl::NodeclBase arguments ) { ERROR_CONDITION( _nodecl.is_null( ), "Found a null nodecl for a graph that is supposed to contain a FunctionCode", 0 ); ERROR_CONDITION( !_nodecl.is<Nodecl::FunctionCode>( ), "Expected FunctionCode but '%s' found", ast_print_node_type( _nodecl.get_kind( ) ) ); Symbol func_sym( _nodecl.get_symbol( ) ); ERROR_CONDITION( !func_sym.is_valid( ), "Invalid symbol for a nodecl that is supposed to contain a FunctionCode", 0 ); Nodecl::List args = arguments.as<Nodecl::List>( ); ObjectList<Symbol> params = func_sym.get_function_parameters( ); int n_common_params = std::max( args.size( ), params.size( ) ); sym_to_nodecl_map rename_map; for( int i = 0; i < n_common_params; ++i ) { rename_map[params[i]] = args[i]; } RenameVisitor rv( rename_map ); Node* graph_entry = _graph->get_graph_entry_node( ); propagate_argument_rec( graph_entry, &rv ); ExtensibleGraph::clear_visits( graph_entry ); }
void AutoScopeVisitor::visit( const Nodecl::OpenMP::Task& n ) { // Retrieve the results of the Auto-Scoping process to the user _analysis_info->print_auto_scoping_results( n ); // Modify the Nodecl with the new variables' scope Analysis::Utils::AutoScopedVariables autosc_vars = _analysis_info->get_auto_scoped_variables( n ); Analysis::Utils::ext_sym_set private_ext_syms, firstprivate_ext_syms, race_ext_syms, shared_ext_syms, undef_ext_syms; Nodecl::NodeclBase user_private_vars, user_firstprivate_vars, user_shared_vars; // Get actual environment Nodecl::List environ = n.get_environment().as<Nodecl::List>(); for( Nodecl::List::iterator it = environ.begin( ); it != environ.end( ); ) { if( it->is<Nodecl::OpenMP::Auto>( ) ) { it = environ.erase( it ); } else { if( it->is<Nodecl::OpenMP::Private>( ) ) { user_private_vars = it->as<Nodecl::OpenMP::Private>( ); } if( it->is<Nodecl::OpenMP::Firstprivate>( ) ) { user_firstprivate_vars = it->as<Nodecl::OpenMP::Firstprivate>( ); } if( it->is<Nodecl::OpenMP::Shared>( ) ) { user_shared_vars = it->as<Nodecl::OpenMP::Shared>( ); } ++it; } } // Remove user-scoped variables from auto-scoped variables and reset environment private_ext_syms = autosc_vars.get_private_vars( ); if( !private_ext_syms.empty( ) ) { ObjectList<Nodecl::NodeclBase> autosc_private_vars; for( Analysis::Utils::ext_sym_set::iterator it = private_ext_syms.begin( ); it != private_ext_syms.end( ); ++it ) { autosc_private_vars.insert( it->get_nodecl( ) ); } ObjectList<Nodecl::NodeclBase> purged_autosc_private_vars; for( ObjectList<Nodecl::NodeclBase>::iterator it = autosc_private_vars.begin( ); it != autosc_private_vars.end( ); ++it ) { if( !Nodecl::Utils::nodecl_is_in_nodecl_list( *it, user_firstprivate_vars.as<Nodecl::List>( ) ) && !Nodecl::Utils::nodecl_is_in_nodecl_list( *it, user_private_vars.as<Nodecl::List>( ) ) && !Nodecl::Utils::nodecl_is_in_nodecl_list( *it, user_shared_vars.as<Nodecl::List>( ) ) ) { purged_autosc_private_vars.insert( it->shallow_copy() ); } } if( !purged_autosc_private_vars.empty( ) ) { Nodecl::OpenMP::Private private_node = Nodecl::OpenMP::Private::make( Nodecl::List::make( purged_autosc_private_vars ), n.get_locus( ) ); environ.append( private_node ); } } firstprivate_ext_syms = autosc_vars.get_firstprivate_vars( ); if( !firstprivate_ext_syms.empty( ) ) { ObjectList<Nodecl::NodeclBase> autosc_firstprivate_vars; for( Analysis::Utils::ext_sym_set::iterator it = firstprivate_ext_syms.begin( ); it != firstprivate_ext_syms.end( ); ++it ) { autosc_firstprivate_vars.insert( it->get_nodecl( ) ); } ObjectList<Nodecl::NodeclBase> purged_autosc_firstprivate_vars; for( ObjectList<Nodecl::NodeclBase>::iterator it = autosc_firstprivate_vars.begin( ); it != autosc_firstprivate_vars.end( ); ++it ) { if( !Nodecl::Utils::nodecl_is_in_nodecl_list( *it, user_firstprivate_vars.as<Nodecl::List>( ) ) && !Nodecl::Utils::nodecl_is_in_nodecl_list( *it, user_private_vars.as<Nodecl::List>( ) ) && !Nodecl::Utils::nodecl_is_in_nodecl_list( *it, user_shared_vars.as<Nodecl::List>( ) ) ) { purged_autosc_firstprivate_vars.insert( it->shallow_copy() ); } } if( !purged_autosc_firstprivate_vars.empty( ) ) { Nodecl::OpenMP::Firstprivate firstprivate_node = Nodecl::OpenMP::Firstprivate::make( Nodecl::List::make( purged_autosc_firstprivate_vars ), n.get_locus( ) ); environ.append( firstprivate_node ); } } shared_ext_syms = autosc_vars.get_shared_vars( ); if( !shared_ext_syms.empty( ) ) { ObjectList<Nodecl::NodeclBase> autosc_shared_vars; for( Analysis::Utils::ext_sym_set::iterator it = shared_ext_syms.begin( ); it != shared_ext_syms.end( ); ++it ) { autosc_shared_vars.insert( it->get_nodecl( ) ); } ObjectList<Nodecl::NodeclBase> purged_autosc_shared_vars; for( ObjectList<Nodecl::NodeclBase>::iterator it = autosc_shared_vars.begin( ); it != autosc_shared_vars.end( ); ++it ) { if( !Nodecl::Utils::nodecl_is_in_nodecl_list( *it, user_firstprivate_vars.as<Nodecl::List>( ) ) && !Nodecl::Utils::nodecl_is_in_nodecl_list( *it, user_private_vars.as<Nodecl::List>( ) ) && !Nodecl::Utils::nodecl_is_in_nodecl_list( *it, user_shared_vars.as<Nodecl::List>( ) ) ) { purged_autosc_shared_vars.insert( it->shallow_copy() ); } } if( !purged_autosc_shared_vars.empty( ) ) { Nodecl::OpenMP::Shared shared_node = Nodecl::OpenMP::Shared::make( Nodecl::List::make( purged_autosc_shared_vars ), n.get_locus( ) ); environ.append( shared_node ); } } }
void DeviceOpenCL::create_outline(CreateOutlineInfo &info, Nodecl::NodeclBase &outline_placeholder, Nodecl::NodeclBase &output_statements, Nodecl::Utils::SimpleSymbolMap* &symbol_map) { // Unpack DTO Lowering *lowering = info._lowering; const std::string& outline_name = ocl_outline_name(info._outline_name); const Nodecl::NodeclBase& task_statements = info._task_statements; const Nodecl::NodeclBase& original_statements = info._original_statements; const TL::Symbol& called_task = info._called_task; bool is_function_task = info._called_task.is_valid(); TL::ObjectList<OutlineDataItem*> data_items = info._data_items; lowering->seen_opencl_task = true; symbol_map = new Nodecl::Utils::SimpleSymbolMap(); output_statements = task_statements; ERROR_CONDITION(called_task.is_valid() && !called_task.is_function(), "The '%s' symbol is not a function", called_task.get_name().c_str()); TL::Symbol current_function = original_statements.retrieve_context().get_related_symbol(); if (current_function.is_nested_function()) { if (IS_C_LANGUAGE || IS_CXX_LANGUAGE) fatal_printf_at(original_statements.get_locus(), "nested functions are not supported\n"); if (IS_FORTRAN_LANGUAGE) fatal_printf_at(original_statements.get_locus(), "internal subprograms are not supported\n"); } Source extra_declarations; Source final_statements, initial_statements; // *** Unpacked (and forward in Fortran) function *** TL::Symbol unpacked_function, forward_function; if (IS_FORTRAN_LANGUAGE) { forward_function = new_function_symbol_forward( current_function, outline_name + "_forward", info); unpacked_function = new_function_symbol_unpacked( current_function, outline_name + "_unpack", info, // out symbol_map, initial_statements, final_statements); } else { unpacked_function = new_function_symbol_unpacked( current_function, outline_name + "_unpacked", info, // out symbol_map, initial_statements, final_statements); } Nodecl::NodeclBase unpacked_function_code, unpacked_function_body; SymbolUtils::build_empty_body_for_function(unpacked_function, unpacked_function_code, unpacked_function_body); if (IS_FORTRAN_LANGUAGE) { // Now get all the needed internal functions and replicate them in the outline Nodecl::Utils::Fortran::InternalFunctions internal_functions; internal_functions.walk(info._original_statements); Nodecl::List l; for (TL::ObjectList<Nodecl::NodeclBase>::iterator it2 = internal_functions.function_codes.begin(); it2 != internal_functions.function_codes.end(); it2++) { l.append( Nodecl::Utils::deep_copy(*it2, unpacked_function.get_related_scope(), *symbol_map) ); } // unpacked_function_code.as<Nodecl::FunctionCode>().set_internal_functions(l); } Nodecl::Utils::append_to_top_level_nodecl(unpacked_function_code); //Get the argument of the 'file' clause, if not present, use the files passed in the command line (if any) std::string file_clause_arg = info._target_info.get_file(); std::string kernel_files = file_clause_arg; if (!file_clause_arg.empty()) { bool found = false; for (int i = 0; i < ::compilation_process.num_translation_units; ++i) { compilation_file_process_t* file_process = ::compilation_process.translation_units[i]; translation_unit_t* current_translation_unit = file_process->translation_unit; const char* extension = get_extension_filename(current_translation_unit->input_filename); struct extensions_table_t* current_extension = fileextensions_lookup(extension, strlen(extension)); if (current_extension->source_language == SOURCE_SUBLANGUAGE_OPENCL) { const char* basename = give_basename(current_translation_unit->input_filename); if (file_clause_arg == std::string(basename)) { ERROR_CONDITION(found, "%s: error: more than one OpenCL file in the command line matches clause file(%s)\n", original_statements.get_locus_str().c_str(), basename); found = true; kernel_files = std::string(current_translation_unit->input_filename); } } } if (!found && !_disable_opencl_file_check) { error_printf_at(original_statements.get_locus(), "no OpenCL file in the command line matches clause file(%s)\n", file_clause_arg.c_str()); } } else { int ocl_files = 0; for (int i = 0; i < ::compilation_process.num_translation_units; ++i) { compilation_file_process_t* file_process = ::compilation_process.translation_units[i]; translation_unit_t* current_translation_unit = file_process->translation_unit; const char* extension = get_extension_filename(current_translation_unit->input_filename); struct extensions_table_t* current_extension = fileextensions_lookup(extension, strlen(extension)); if (current_extension->source_language == SOURCE_SUBLANGUAGE_OPENCL) { if (ocl_files > 0) kernel_files += ","; kernel_files += std::string(current_translation_unit->input_filename); ocl_files++; } } if (ocl_files == 0) { fatal_printf_at(original_statements.get_locus(), "no OpenCL file specified for kernel '%s'\n", called_task.get_name().c_str()); } } // Get the name of the kernel std::string kernel_name = info._target_info.get_name(); if (kernel_name.empty()) { // If the clause name is not present, use the name of the called task kernel_name = called_task.get_name(); } Source ndrange_code; if (called_task.is_valid() && info._target_info.get_ndrange().size() > 0) { Nodecl::Utils::SimpleSymbolMap param_to_args_map = info._target_info.get_param_arg_map(); generate_ndrange_code(called_task, unpacked_function, info._target_info, kernel_files, kernel_name, info._data_items, ¶m_to_args_map, symbol_map, ndrange_code); } Source unpacked_source; if (!IS_FORTRAN_LANGUAGE) { unpacked_source << "{"; } unpacked_source << extra_declarations << initial_statements << ndrange_code //<< statement_placeholder(outline_placeholder) << final_statements ; if (!IS_FORTRAN_LANGUAGE) { unpacked_source << "}"; } // Fortran may require more symbols if (IS_FORTRAN_LANGUAGE) { // Insert extra symbols TL::Scope unpacked_function_scope = unpacked_function_body.retrieve_context(); Nodecl::Utils::Fortran::ExtraDeclsVisitor fun_visitor(symbol_map, unpacked_function_scope, current_function); if (is_function_task) { fun_visitor.insert_extra_symbol(info._called_task); } fun_visitor.insert_extra_symbols(task_statements); Nodecl::Utils::Fortran::append_used_modules( original_statements.retrieve_context(), unpacked_function_scope); if (is_function_task) { Nodecl::Utils::Fortran::append_used_modules( info._called_task.get_related_scope(), unpacked_function_scope); } // Add also used types add_used_types(data_items, unpacked_function.get_related_scope()); // Now get all the needed internal functions and replicate them in the outline Nodecl::Utils::Fortran::InternalFunctions internal_functions; internal_functions.walk(info._original_statements); duplicate_internal_subprograms(internal_functions.function_codes, unpacked_function.get_related_scope(), symbol_map, output_statements); extra_declarations << "IMPLICIT NONE\n"; } else if (IS_CXX_LANGUAGE) { if (!unpacked_function.is_member()) { Nodecl::NodeclBase nodecl_decl = Nodecl::CxxDecl::make( /* optative context */ nodecl_null(), unpacked_function, original_statements.get_locus()); Nodecl::Utils::prepend_to_enclosing_top_level_location(original_statements, nodecl_decl); } } Nodecl::NodeclBase new_unpacked_body = unpacked_source.parse_statement(unpacked_function_body); unpacked_function_body.replace(new_unpacked_body); // **** Outline function ***** ObjectList<std::string> structure_name; structure_name.append("args"); ObjectList<TL::Type> structure_type; structure_type.append( TL::Type(get_user_defined_type(info._arguments_struct.get_internal_symbol())).get_lvalue_reference_to() ); TL::Symbol outline_function = SymbolUtils::new_function_symbol( current_function, outline_name, TL::Type::get_void_type(), structure_name, structure_type); Nodecl::NodeclBase outline_function_code, outline_function_body; SymbolUtils::build_empty_body_for_function(outline_function, outline_function_code, outline_function_body); Nodecl::Utils::append_to_top_level_nodecl(outline_function_code); // Prepare arguments for the call to the unpack (or forward in Fortran) TL::Scope outline_function_scope(outline_function_body.retrieve_context()); TL::Symbol structure_symbol = outline_function_scope.get_symbol_from_name("args"); ERROR_CONDITION(!structure_symbol.is_valid(), "Argument of outline function not found", 0); Source unpacked_arguments, cleanup_code; for (TL::ObjectList<OutlineDataItem*>::iterator it = data_items.begin(); it != data_items.end(); it++) { if (!is_function_task && (*it)->get_is_cxx_this()) continue; switch ((*it)->get_sharing()) { case OutlineDataItem::SHARING_PRIVATE: { // Do nothing break; } case OutlineDataItem::SHARING_SHARED: case OutlineDataItem::SHARING_CAPTURE: case OutlineDataItem::SHARING_CAPTURE_ADDRESS: { TL::Type param_type = (*it)->get_in_outline_type(); Source argument; if (IS_C_LANGUAGE || IS_CXX_LANGUAGE) { // Normal shared items are passed by reference from a pointer, // derreference here if ((*it)->get_sharing() == OutlineDataItem::SHARING_SHARED && !(IS_CXX_LANGUAGE && (*it)->get_symbol().get_name() == "this")) { if (!param_type.no_ref().depends_on_nonconstant_values()) { argument << "*(args." << (*it)->get_field_name() << ")"; } else { TL::Type ptr_type = (*it)->get_in_outline_type().references_to().get_pointer_to(); TL::Type cast_type = rewrite_type_of_vla_in_outline(ptr_type, data_items, structure_symbol); argument << "*((" << as_type(cast_type) << ")args." << (*it)->get_field_name() << ")"; } } // Any other parameter is bound to the storage of the struct else { if (!param_type.no_ref().depends_on_nonconstant_values()) { argument << "args." << (*it)->get_field_name(); } else { TL::Type cast_type = rewrite_type_of_vla_in_outline(param_type, data_items, structure_symbol); argument << "(" << as_type(cast_type) << ")args." << (*it)->get_field_name(); } } if (IS_CXX_LANGUAGE && (*it)->get_allocation_policy() == OutlineDataItem::ALLOCATION_POLICY_TASK_MUST_DESTROY) { internal_error("Not yet implemented: call the destructor", 0); } } else if (IS_FORTRAN_LANGUAGE) { argument << "args % " << (*it)->get_field_name(); if ((*it)->get_allocation_policy() & OutlineDataItem::ALLOCATION_POLICY_TASK_MUST_DEALLOCATE_ALLOCATABLE) { cleanup_code << "IF (ALLOCATED(args % " << (*it)->get_field_name() << ")) THEN\n" << "DEALLOCATE(args % " << (*it)->get_field_name() << ")\n" << "ENDIF\n" ; } } else { internal_error("running error", 0); } unpacked_arguments.append_with_separator(argument, ", "); break; } case OutlineDataItem::SHARING_REDUCTION: { // // Pass the original reduced variable as if it were a shared Source argument; if (IS_C_LANGUAGE || IS_CXX_LANGUAGE) { argument << "*(args." << (*it)->get_field_name() << ")"; } else if (IS_FORTRAN_LANGUAGE) { argument << "args % " << (*it)->get_field_name(); } unpacked_arguments.append_with_separator(argument, ", "); break; } default: { internal_error("Unexpected data sharing kind", 0); } } } Source outline_src, instrument_before, instrument_after; if (IS_C_LANGUAGE || IS_CXX_LANGUAGE) { Source unpacked_function_call; if (IS_CXX_LANGUAGE && !is_function_task && current_function.is_member() && !current_function.is_static()) { unpacked_function_call << "args.this_->"; } unpacked_function_call << unpacked_function.get_qualified_name_for_expression( /* in_dependent_context */ (current_function.get_type().is_template_specialized_type() && current_function.get_type().is_dependent()) ) << "(" << unpacked_arguments << ");"; outline_src << "{" << instrument_before << unpacked_function_call << instrument_after << cleanup_code << "}" ; if (IS_CXX_LANGUAGE) { if (!outline_function.is_member()) { Nodecl::NodeclBase nodecl_decl = Nodecl::CxxDecl::make( /* optative context */ nodecl_null(), outline_function, original_statements.get_locus()); Nodecl::Utils::prepend_to_enclosing_top_level_location(original_statements, nodecl_decl); } } } else if (IS_FORTRAN_LANGUAGE) { Source outline_function_addr; outline_src << instrument_before << "\n" << "CALL " << outline_name << "_forward(" << outline_function_addr << unpacked_arguments << ")\n" << instrument_after << "\n" << cleanup_code ; outline_function_addr << "LOC(" << unpacked_function.get_name() << ")"; if (!unpacked_arguments.empty()) { outline_function_addr << ", "; } // Copy USEd information to the outline and forward functions TL::Symbol *functions[] = { &outline_function, &forward_function, NULL }; for (int i = 0; functions[i] != NULL; i++) { TL::Symbol &function(*functions[i]); Nodecl::Utils::Fortran::append_used_modules(original_statements.retrieve_context(), function.get_related_scope()); add_used_types(data_items, function.get_related_scope()); } // Generate ancillary code in C add_forward_function_code_to_extra_c_code(outline_name, data_items, outline_function_body); } else { internal_error("Code unreachable", 0); } if (instrumentation_enabled()) { get_instrumentation_code( info._called_task, outline_function, outline_function_body, info._task_label, original_statements.get_locus(), instrument_before, instrument_after); } Nodecl::NodeclBase new_outline_body = outline_src.parse_statement(outline_function_body); outline_function_body.replace(new_outline_body); // Nodecl::Utils::prepend_to_enclosing_top_level_location(original_statements, outline_function_code); // //Dummy function call placeholder Source unpacked_ndr_code; unpacked_ndr_code << statement_placeholder(outline_placeholder); Nodecl::NodeclBase new_unpacked_ndr_code = unpacked_ndr_code.parse_statement(unpacked_function_body); outline_placeholder=new_unpacked_ndr_code; }
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); }
void loop_hlt_handler_post(TL::PragmaCustomStatement construct) { TL::PragmaCustomLine pragma_line = construct.get_pragma_line(); TL::PragmaCustomClause collapse = construct.get_pragma_line().get_clause("collapse"); if (!collapse.is_defined()) return; TL::ObjectList<Nodecl::NodeclBase> expr_list = collapse.get_arguments_as_expressions(construct); if (expr_list.size() != 1) { error_printf_at(construct.get_locus(), "'collapse' clause needs exactly one argument\n"); return; } Nodecl::NodeclBase expr = expr_list[0]; if (!expr.is_constant() || !is_any_int_type(expr.get_type().get_internal_type())) { error_printf_at(construct.get_locus(), "'collapse' clause requires an integer constant expression\n"); return; } int collapse_factor = const_value_cast_to_signed_int(expr.get_constant()); if (collapse_factor <= 0) { error_printf_at( construct.get_locus(), "Non-positive factor (%d) is not allowed in the 'collapse' clause\n", collapse_factor); } else if (collapse_factor == 1) { // Removing the collapse clause from the pragma pragma_line.remove_clause("collapse"); } else if (collapse_factor > 1) { Nodecl::NodeclBase loop = get_statement_from_pragma(construct); HLT::LoopCollapse loop_collapse; loop_collapse.set_loop(loop); loop_collapse.set_pragma_context(construct.retrieve_context()); loop_collapse.set_collapse_factor(collapse_factor); loop_collapse.collapse(); Nodecl::NodeclBase transformed_code = loop_collapse.get_whole_transformation(); TL::ObjectList<TL::Symbol> capture_symbols = loop_collapse.get_omp_capture_symbols(); // We may need to add some symbols that are used to implement the collapse clause to the pragma std::string names; for (TL::ObjectList<TL::Symbol>::iterator it = capture_symbols.begin(); it != capture_symbols.end(); it++) { if (it != capture_symbols.begin()) names += ","; names += it->get_name(); } Nodecl::List clauses = pragma_line.get_clauses().as<Nodecl::List>(); clauses.append(Nodecl::PragmaCustomClause::make(Nodecl::List::make(Nodecl::PragmaClauseArg::make(names)), "firstprivate")); // Removing the collapse clause from the pragma pragma_line.remove_clause("collapse"); // Create a new pragma over the new for stmt ERROR_CONDITION(!transformed_code.is<Nodecl::Context>(), "Unexpected node\n", 0); Nodecl::NodeclBase compound_statement = transformed_code.as<Nodecl::Context>().get_in_context().as<Nodecl::List>().front(); ERROR_CONDITION(!compound_statement.is<Nodecl::CompoundStatement>(), "Unexpected node\n", 0); Nodecl::Context context_for_stmt = compound_statement.as<Nodecl::CompoundStatement>().get_statements() .as<Nodecl::List>().find_first<Nodecl::Context>(); Nodecl::Utils::remove_from_enclosing_list(context_for_stmt); Nodecl::List stmt_list = compound_statement.as<Nodecl::CompoundStatement>().get_statements().as<Nodecl::List>(); ERROR_CONDITION(stmt_list.is_null(), "Unreachable code\n", 0); Nodecl::PragmaCustomStatement new_pragma = Nodecl::PragmaCustomStatement::make(pragma_line, Nodecl::List::make(context_for_stmt), construct.get_text(), construct.get_locus()); stmt_list.append(new_pragma); construct.replace(transformed_code); } }
int SuitableAlignmentVisitor::visit( const Nodecl::ArraySubscript& n ) { if( _nesting_level == 0 ) // Target access { _nesting_level++; int i; int alignment = 0; Nodecl::NodeclBase subscripted = n.get_subscripted( ); TL::Type element_type = subscripted.get_type( ); // TODO: subscript is aligned Nodecl::List subscripts = n.get_subscripts( ).as<Nodecl::List>( ); int num_subscripts = subscripts.size( ); // Get dimension sizes int *dimension_sizes = (int *)malloc( ( num_subscripts-1 ) * sizeof( int ) ); for( i = 0; i < (num_subscripts-1); i++ ) // Skip the first one. It does not have size { // Iterate on array subscript type if( element_type.is_array( ) ) { element_type = element_type.array_element( ); } else if( element_type.is_pointer( ) ) { element_type = element_type.points_to( ); } else { WARNING_MESSAGE( "Array subscript does not have array type or pointer to array type", 0 ); return -1; } if( !element_type.array_has_size( ) ) { WARNING_MESSAGE( "Array type does not have size", 0 ); return -1; } // Compute dimension alignment Nodecl::NodeclBase dimension_size_node = element_type.array_get_size( ); // If VLA, get the actual size if(dimension_size_node.is<Nodecl::Symbol>() && dimension_size_node.get_symbol().is_saved_expression()) { dimension_size_node = dimension_size_node.get_symbol().get_value(); } int dimension_size = -1; if( dimension_size_node.is_constant( ) ) { dimension_size = const_value_cast_to_signed_int( dimension_size_node.get_constant( ) ); if( is_suitable_constant( dimension_size * _type_size ) ) dimension_size = 0; } // If dimension size is suitable else if( is_suitable_expression( dimension_size_node ) ) { dimension_size = 0; } if( VERBOSE ) printf( "Dim %d, size %d\n", i, dimension_size ); dimension_sizes[i] = dimension_size; } int it_alignment; Nodecl::List::iterator it = subscripts.begin( ); // Multiply dimension sizes by indexes for( i=0; it != subscripts.end( ); i++ ) { it_alignment = walk( *it ); it++; if( it == subscripts.end( ) ) break; // Last dimmension does not have to be multiplied // a[i][j][k] -> i -> i*J*K for( int j = i; j < (num_subscripts-1); j++ ) { if( ( dimension_sizes[j] == 0 ) || ( it_alignment == 0 ) ) { it_alignment = 0; } else if( ( dimension_sizes[j] < 0 ) || ( it_alignment < 0 ) ) { it_alignment = -1; } else { it_alignment *= dimension_sizes[j]; } } if( it_alignment < 0 ) { return -1; } alignment += it_alignment; } // Add adjacent dimension alignment += it_alignment; free(dimension_sizes); _nesting_level--; return alignment; } // Nested array subscript else { if (is_suitable_expression(n)) { return 0; } return -1; } }
static void handle_ompss_opencl_allocate_intrinsic( Nodecl::FunctionCall function_call, std::map<std::pair<TL::Type, std::pair<int, bool> > , Symbol> &declared_ocl_allocate_functions, Nodecl::NodeclBase expr_stmt) { Nodecl::List arguments = function_call.get_arguments().as<Nodecl::List>(); ERROR_CONDITION(arguments.size() != 1, "More than one argument in 'ompss_opencl_allocate' call\n", 0); Nodecl::NodeclBase actual_argument = arguments[0]; ERROR_CONDITION(!actual_argument.is<Nodecl::FortranActualArgument>(), "Unexpected tree\n", 0); Nodecl::NodeclBase arg = actual_argument.as<Nodecl::FortranActualArgument>().get_argument(); ERROR_CONDITION(!arg.is<Nodecl::ArraySubscript>(), "Unreachable code\n", 0); Nodecl::NodeclBase subscripted = arg.as<Nodecl::ArraySubscript>().get_subscripted(); TL::Symbol subscripted_symbol = ::fortran_data_ref_get_symbol(subscripted.get_internal_nodecl()); ERROR_CONDITION( !(subscripted_symbol.get_type().is_fortran_array() && subscripted_symbol.is_allocatable()) && !(subscripted_symbol.get_type().is_pointer() && subscripted_symbol.get_type().points_to().is_fortran_array()), "The argument of 'ompss_opencl_allocate' intrinsic must be " "an allocatable array or a pointer to an array with all its bounds specified\n", 0); TL::Type array_type; int num_dimensions; bool is_allocatable; if (subscripted_symbol.is_allocatable()) { array_type = subscripted_symbol.get_type(); num_dimensions = subscripted_symbol.get_type().get_num_dimensions(); is_allocatable = true; } else { array_type = subscripted_symbol.get_type().points_to(); num_dimensions = array_type.get_num_dimensions(); is_allocatable = false; } TL::Type element_type = array_type; while (element_type.is_array()) { element_type = element_type.array_element(); } ERROR_CONDITION(!array_type.is_array(), "This type should be an array type", 0); std::pair<TL::Type, std::pair<int, bool> > key = std::make_pair(element_type, std::make_pair(num_dimensions, is_allocatable)); std::map<std::pair<TL::Type, std::pair<int, bool> > , Symbol>::iterator it_new_fun = declared_ocl_allocate_functions.find(key); // Reuse the auxiliar function if it already exists Symbol new_function_sym; if (it_new_fun != declared_ocl_allocate_functions.end()) { new_function_sym = it_new_fun->second; } else { new_function_sym = create_new_function_opencl_allocate( expr_stmt, subscripted_symbol, element_type, num_dimensions, is_allocatable); declared_ocl_allocate_functions[key] = new_function_sym; } // Replace the current intrinsic call by a call to the new function TL::Source actual_arg_array; Nodecl::NodeclBase subscripted_lvalue = subscripted.shallow_copy(); subscripted_lvalue.set_type(subscripted_symbol.get_type().no_ref().get_lvalue_reference_to()); actual_arg_array << as_expression(subscripted_lvalue); TL::Source actual_arg_bounds; Nodecl::List subscripts = arg.as<Nodecl::ArraySubscript>().get_subscripts().as<Nodecl::List>(); for (Nodecl::List::reverse_iterator it = subscripts.rbegin(); it != subscripts.rend(); it++) { Nodecl::NodeclBase subscript = *it, lower, upper; if (it != subscripts.rbegin()) actual_arg_bounds << ", "; if (subscript.is<Nodecl::Range>()) { lower = subscript.as<Nodecl::Range>().get_lower(); upper = subscript.as<Nodecl::Range>().get_upper(); } else { lower = nodecl_make_integer_literal( fortran_get_default_integer_type(), const_value_get_signed_int(1), make_locus("", 0, 0)); upper = subscript; } actual_arg_bounds << as_expression(lower) << "," << as_expression(upper); } TL::Source new_function_call; new_function_call << "CALL " << as_symbol(new_function_sym) << "(" << actual_arg_array << ", " << actual_arg_bounds << ")\n" ; expr_stmt.replace(new_function_call.parse_statement(expr_stmt)); }
void VectorizerVisitorExpression::visit(const Nodecl::Assignment& n) { Nodecl::NodeclBase lhs = n.get_lhs(); walk(n.get_rhs()); // Computing new vector type TL::Type vector_type = n.get_type(); /* if (vector_type.is_lvalue_reference()) { vector_type = vector_type.references_to(); } */ vector_type = get_qualified_vector_to(vector_type, _vector_length); if(lhs.is<Nodecl::ArraySubscript>()) { // Vector Store if(Vectorizer::_analysis_info->is_adjacent_access( Vectorizer::_analysis_scopes->back(), lhs)) { TL::Type basic_type = lhs.get_type(); if (basic_type.is_lvalue_reference()) { basic_type = basic_type.references_to(); } const Nodecl::VectorStore vector_store = Nodecl::VectorStore::make( Nodecl::Reference::make( Nodecl::ParenthesizedExpression::make( lhs.shallow_copy(), basic_type, n.get_locus()), basic_type.get_pointer_to(), n.get_locus()), n.get_rhs().shallow_copy(), vector_type, n.get_locus()); n.replace(vector_store); } else // Vector Scatter { const Nodecl::ArraySubscript lhs_array = lhs.as<Nodecl::ArraySubscript>(); const Nodecl::NodeclBase base = lhs_array.get_subscripted(); const Nodecl::List subscripts = lhs_array.get_subscripts().as<Nodecl::List>(); std::cerr << "Scatter: " << lhs_array.prettyprint() << "\n"; ERROR_CONDITION(subscripts.size() > 1, "Vectorizer: Scatter on multidimensional array is not supported yet!", 0); Nodecl::NodeclBase strides = *subscripts.begin(); walk(strides); const Nodecl::VectorScatter vector_scatter = Nodecl::VectorScatter::make( base.shallow_copy(), strides, n.get_rhs().shallow_copy(), vector_type, n.get_locus()); n.replace(vector_scatter); } } else // Register { walk(lhs); const Nodecl::VectorAssignment vector_assignment = Nodecl::VectorAssignment::make( lhs.shallow_copy(), n.get_rhs().shallow_copy(), vector_type, n.get_locus()); n.replace(vector_assignment); } }
void NanosMain::run(TL::DTO& dto) { this->PragmaCustomCompilerPhase::run(dto); TL::Symbol main_function = get_main_function_symbol(); if (!main_function.is_valid() || main_function.get_function_code().is_null()) return; bool new_ompss_main_api = Nanos::Version::interface_is_at_least("master", 5030); bool emit_main_instrumentation = _instrumentation_enabled && new_ompss_main_api; bool emit_nanos_main_call = (_nanos_main_enabled && Nanos::Version::interface_is_at_least("master", 5026)) || emit_main_instrumentation; if (!emit_main_instrumentation && !emit_nanos_main_call) return; Source initial_main_code_src; Nodecl::FunctionCode function_code = main_function.get_function_code().as<Nodecl::FunctionCode>(); if (emit_nanos_main_call) { if (new_ompss_main_api) { if (!IS_FORTRAN_LANGUAGE) { initial_main_code_src << "ompss_nanox_main_begin((void*)main," << "\"" << function_code.get_filename() << "\"," << function_code.get_line() << ");"; } else { initial_main_code_src << "int nanos_main_proxy_address = 0;" << "ompss_nanox_main_begin(&nanos_main_proxy_address," << "\"" << function_code.get_filename() << "\"," << "(int)" << function_code.get_line() << ");"; } } else { // Older version, used only for Cluster and Offload so far initial_main_code_src << "ompss_nanox_main();" ; } } if (emit_main_instrumentation) { initial_main_code_src << "nanos_atexit((void*)ompss_nanox_main_end);"; } if (IS_FORTRAN_LANGUAGE) { Source::source_language = SourceLanguage::C; } Nodecl::NodeclBase initial_main_code = initial_main_code_src.parse_statement(main_function.get_function_code()); Source::source_language = SourceLanguage::Current; // Now prepend the code Nodecl::Context context = function_code.get_statements().as<Nodecl::Context>(); Nodecl::List stmts = context.get_in_context().as<Nodecl::List>(); Nodecl::List statement_list; if (!IS_FORTRAN_LANGUAGE) { // In C/C++ inside a context there is always a singleton list with a compound statement Nodecl::CompoundStatement compound_stmt = stmts[0].as<Nodecl::CompoundStatement>(); stmts = compound_stmt.get_statements().as<Nodecl::List>(); } stmts.prepend(initial_main_code); }