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 Core::collapse_check_loop(TL::PragmaCustomStatement construct) { 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("%s: error: collapse clause needs exactly one argument\n", locus_to_str(construct.get_locus())); return; } Nodecl::NodeclBase expr = expr_list[0]; if (!expr.is_constant() || !is_any_int_type(expr.get_type().get_internal_type())) { error_printf("%s: error: collapse clause requires an integer constant expression\n", locus_to_str(construct.get_locus())); return; } const_value_t* cval = expr.get_constant(); if (!const_value_is_one(cval)) { error_printf("%s: error: only collapse(1) is supported\n", locus_to_str(construct.get_locus())); return; } }
Nodecl::NodeclVisitor<void>::Ret AVX2StrideVisitorConv::unhandled_node(const Nodecl::NodeclBase& node) { //printf("Unsupported %d: %s\n", _vector_num_elements, node.prettyprint().c_str()); if (node.get_type().is_vector()) { Nodecl::NodeclBase new_node = node.shallow_copy().as<Nodecl::NodeclBase>(); new_node.set_type(TL::Type::get_int_type().get_vector_of_elements( _vector_num_elements)); // TODO better node.replace(new_node); Nodecl::NodeclBase::Children children = node.children(); for(Nodecl::NodeclBase::Children::iterator it = children.begin(); it != children.end(); it ++) { walk(*it); } } return Ret(); }
bool ArrayAccessInfoVisitor::unhandled_node( const Nodecl::NodeclBase& n ) { std::cerr << "Unhandled node while parsing Array Subscript '" << codegen_to_str( n.get_internal_nodecl( ), nodecl_retrieve_context( n.get_internal_nodecl( ) ) ) << "' of type '" << ast_print_node_type( n.get_kind( ) ) << "'" << std::endl; return false; }
Nodecl::NodeclVisitor<void>::Ret NeonVectorBackend::unhandled_node(const Nodecl::NodeclBase& n) { internal_error("NEON Backend: Unknown node %s at %s.", ast_print_node_type(n.get_kind()), locus_to_str(n.get_locus())); return Ret(); }
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); } }
Nodecl::NodeclVisitor<void>::Ret VectorizerVisitorFunction::unhandled_node(const Nodecl::NodeclBase& n) { std::cerr << "Function Visitor: Unknown node " << ast_print_node_type(n.get_kind()) << " at " << n.get_locus() << std::endl; return Ret(); }
void VectorizerVisitorPostprocessor::visit(const Nodecl::ObjectInit& n) { TL::Symbol sym = n.get_symbol(); Nodecl::NodeclBase init = sym.get_value(); if(!init.is_null()) { walk(init); } }
Type Type::get_array_to_with_descriptor(Nodecl::NodeclBase lower_bound, Nodecl::NodeclBase upper_bound, Scope sc) { type_t* result_type = this->_type_info; const decl_context_t* decl_context = sc.get_decl_context(); type_t* array_to = get_array_type_bounds_with_descriptor(result_type, lower_bound.get_internal_nodecl(), upper_bound.get_internal_nodecl(), decl_context); return Type(array_to); }
void SSEVectorLegalization::visit(const Nodecl::ObjectInit& node) { TL::Source intrin_src; TL::Symbol sym = node.get_symbol(); fix_mask_symbol(sym); // Vectorizing initialization Nodecl::NodeclBase init = sym.get_value(); if (!init.is_null()) { walk(init); } }
void NeonVectorBackend::visit(const Nodecl::ObjectInit& n) { TL::Source intrin_src; if(n.has_symbol()) { TL::Symbol sym = n.get_symbol(); // Vectorizing initialization Nodecl::NodeclBase init = sym.get_value(); if(!init.is_null()) { walk(init); } } }
void SimdVisitor::visit(const Nodecl::OpenMP::Simd& simd_node) { Nodecl::NodeclBase for_statement = simd_node.get_statement(); // Vectorize for Nodecl::NodeclBase epilog = _vectorizer.vectorize(for_statement.as<Nodecl::ForStatement>(), _device_name, _vector_length, NULL); // Add epilog if (!epilog.is_null()) { simd_node.append_sibling(epilog); } // Remove Simd node simd_node.replace(for_statement); }
Type Type::get_array_to(Nodecl::NodeclBase array_expr, Scope sc) { type_t* result_type = this->_type_info; const decl_context_t* decl_context = sc.get_decl_context(); type_t* array_to = get_array_type(result_type, array_expr.get_internal_nodecl(), decl_context); return Type(array_to); }
std::string as_statement(const Nodecl::NodeclBase& n) { std::stringstream ss; ss << nodecl_stmt_to_source(n.get_internal_nodecl()); if (IS_FORTRAN_LANGUAGE) ss << "\n"; return ss.str(); }
std::string statement_placeholder(Nodecl::NodeclBase& placeholder) { std::stringstream ss; ss << "@STATEMENT-PH::" << placeholder.get_internal_tree_address() << "@"; if (IS_FORTRAN_LANGUAGE) ss << "\n"; return ss.str(); }
TL::Symbol LoweringVisitor::create_reduction_cleanup_function(OpenMP::Reduction* red, Nodecl::NodeclBase construct) { if (IS_C_LANGUAGE || IS_CXX_LANGUAGE) { internal_error("Currently only valid in Fortran", 0); } reduction_map_t::iterator it = _reduction_cleanup_map.find(red); if (it != _reduction_cleanup_map.end()) { return it->second; } std::string fun_name; { std::stringstream ss; ss << "nanos_cleanup_" << red << "_" << simple_hash_str(construct.get_filename().c_str()); fun_name = ss.str(); } Source src; src << "SUBROUTINE " << fun_name << "(X)\n" << as_type(red->get_type()) << ", POINTER :: X(:)\n" << "DEALLOCATE(X)\n" << "END SUBROUTINE\n" ; Nodecl::NodeclBase function_code = src.parse_global(construct); TL::Symbol function_sym = ReferenceScope(construct).get_scope().get_symbol_from_name(fun_name); ERROR_CONDITION(!function_sym.is_valid(), "Symbol %s not found", fun_name.c_str()); _reduction_cleanup_map[red] = function_sym; Nodecl::Utils::append_to_enclosing_top_level_location(construct, function_code); Nodecl::Utils::Fortran::append_used_modules(construct.retrieve_context(), function_sym.get_related_scope()); return function_sym; }
Type Type::get_array_to_with_region(Nodecl::NodeclBase lower_bound, Nodecl::NodeclBase upper_bound, Nodecl::NodeclBase region_lower_bound, Nodecl::NodeclBase region_upper_bound, Scope sc) { type_t* result_type = this->_type_info; const decl_context_t* decl_context = sc.get_decl_context(); // Make the range of the region Nodecl::NodeclBase range = Nodecl::Range::make( region_lower_bound, region_upper_bound, const_value_to_nodecl(const_value_get_one(4, 1)), region_lower_bound.get_type(), region_lower_bound.get_locus()); type_t* array_to = get_array_type_bounds_with_regions( result_type, lower_bound.get_internal_nodecl(), upper_bound.get_internal_nodecl(), decl_context, range.get_internal_nodecl(), decl_context); return array_to; }
Nodecl::NodeclBase handle_task_statements( Nodecl::NodeclBase construct, Nodecl::NodeclBase task_statements, Nodecl::NodeclBase& task_placeholder, // Do not remove the reference TL::Source &new_stmts_src, // It should be a const reference const std::map<TL::Symbol, std::string> &reduction_symbols_map) { if (IS_FORTRAN_LANGUAGE) Source::source_language = SourceLanguage::C; Nodecl::NodeclBase new_statements = new_stmts_src.parse_statement(construct); if (IS_FORTRAN_LANGUAGE) Source::source_language = SourceLanguage::Current; TL::Scope new_scope = ReferenceScope(task_placeholder).get_scope(); std::map<TL::Symbol, Nodecl::NodeclBase> reduction_symbol_to_nodecl_map; for (std::map<TL::Symbol, std::string>::const_iterator it = reduction_symbols_map.begin(); it != reduction_symbols_map.end(); ++it) { TL::Symbol reduction_sym = it->first; std::string storage_name = it->second; TL::Symbol storage_sym = new_scope.get_symbol_from_name(storage_name); ERROR_CONDITION(!storage_sym.is_valid(), "This symbol is not valid", 0); Nodecl::NodeclBase deref_storage = Nodecl::Dereference::make( storage_sym.make_nodecl(/* set_ref_type */ true, storage_sym.get_locus()), storage_sym.get_type().points_to()); reduction_symbol_to_nodecl_map[reduction_sym] = deref_storage; } ReplaceReductionSymbols visitor(reduction_symbol_to_nodecl_map); Nodecl::NodeclBase copied_statements = task_statements.shallow_copy(); visitor.walk(copied_statements); task_placeholder.replace(copied_statements); return new_statements; }
void KNCVectorLegalization::visit(const Nodecl::VectorLoad& n) { const Nodecl::NodeclBase rhs = n.get_rhs(); const Nodecl::NodeclBase mask = n.get_mask(); const Nodecl::List flags = n.get_flags().as<Nodecl::List>(); walk(rhs); walk(mask); walk(flags); bool explicitly_aligned = !flags.find_first<Nodecl::AlignedFlag>().is_null(); // Turn unaligned load into gather if (!explicitly_aligned && (_prefer_gather_scatter || (_prefer_mask_gather_scatter && !mask.is_null()))) { VECTORIZATION_DEBUG() { fprintf(stderr, "KNC Legalization: Turn unaligned load '%s' into "\ "adjacent gather\n", rhs.prettyprint().c_str()); }
bool NodeclStaticInfo::is_simd_aligned_access( const Nodecl::NodeclBase& n, const TL::ObjectList<Nodecl::NodeclBase>* suitable_expressions, int unroll_factor, int alignment ) const { if( !n.is<Nodecl::ArraySubscript>( ) ) { std::cerr << "warning: returning false for is_simd_aligned_access when asking for nodecl '" << n.prettyprint( ) << "' which is not an array subscript" << std::endl; return false; } bool result = false; Nodecl::NodeclBase subscripted = n.as<Nodecl::ArraySubscript>( ).get_subscripted( ); int type_size = subscripted.get_type().basic_type().get_size(); SuitableAlignmentVisitor sa_v( _induction_variables, suitable_expressions, unroll_factor, type_size, alignment ); int subscript_alignment = sa_v.walk( n ); if( (subscript_alignment % alignment) == 0 ) result = true; return result; }
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 build_empty_body_for_function( TL::Symbol function_symbol, Nodecl::NodeclBase &function_code, Nodecl::NodeclBase &empty_stmt) { empty_stmt = Nodecl::EmptyStatement::make(make_locus("", 0, 0)); Nodecl::List stmt_list = Nodecl::List::make(empty_stmt); if (IS_C_LANGUAGE || IS_CXX_LANGUAGE) { Nodecl::CompoundStatement compound_statement = Nodecl::CompoundStatement::make(stmt_list, /* destructors */ Nodecl::NodeclBase::null(), make_locus("", 0, 0)); stmt_list = Nodecl::List::make(compound_statement); } Nodecl::NodeclBase context = Nodecl::Context::make( stmt_list, function_symbol.get_related_scope(), make_locus("", 0, 0)); function_symbol.get_internal_symbol()->defined = 1; if (function_symbol.is_dependent_function()) { function_code = Nodecl::TemplateFunctionCode::make(context, // Initializers Nodecl::NodeclBase::null(), function_symbol, make_locus("", 0, 0)); } else { function_code = Nodecl::FunctionCode::make(context, // Initializers Nodecl::NodeclBase::null(), function_symbol, make_locus("", 0, 0)); } function_symbol.get_internal_symbol()->entity_specs.function_code = function_code.get_internal_nodecl(); }
bool NodeclStaticInfo::is_suitable_expression( const Nodecl::NodeclBase& n, const TL::ObjectList<Nodecl::NodeclBase>* suitable_expressions, int unroll_factor, int alignment, int& vector_size_module ) const { bool result = false; int type_size = n.get_type().basic_type().get_size(); SuitableAlignmentVisitor sa_v( _induction_variables, suitable_expressions, unroll_factor, type_size, alignment ); int subscript_alignment = sa_v.walk( n ); printf("SUBSCRIPT ALIGNMENT %d\n", subscript_alignment); vector_size_module = ( ( subscript_alignment == -1 ) ? subscript_alignment : subscript_alignment % alignment ); if( vector_size_module == 0 ) result = true; return result; }
int SuitableAlignmentVisitor::visit( const Nodecl::Symbol& n ) { if (is_suitable_expression(n)) { return 0; } else if( n.is_constant( ) ) { int value = const_value_cast_to_signed_int( n.get_constant( )) * _type_size; if(is_suitable_constant(value)) return 0; else return value; } else if( Utils::induction_variable_list_contains_variable( _induction_variables, n ) ) { Utils::InductionVariableData* iv = Utils::get_induction_variable_from_list( _induction_variables, n ); Nodecl::Utils::ReduceExpressionVisitor v; Nodecl::NodeclBase lb = iv->get_lb( ).shallow_copy( ); v.walk( lb ); if( lb.is_constant( ) ) { Nodecl::NodeclBase incr = iv->get_increment( ).shallow_copy( ); v.walk( incr ); if( incr.is_constant( ) ) { return (const_value_cast_to_signed_int( lb.get_constant( ) ) + ( const_value_cast_to_signed_int( incr.get_constant( ) ) * _unroll_factor)) * _type_size; } } } return -1; }
void Symbol::set_value(Nodecl::NodeclBase n) { _symbol->value = n.get_internal_nodecl(); }
void LoweringVisitor::register_reductions( Nodecl::NodeclBase construct, OutlineInfo& outline_info, TL::Source& src) { TL::ObjectList<OutlineDataItem*> data_items = outline_info.get_data_items(); for (TL::ObjectList<OutlineDataItem*>::iterator it = data_items.begin(); it != data_items.end(); it++) { if (!(*it)->is_reduction()) continue; std::pair<TL::OpenMP::Reduction*, TL::Type> red_info_pair = (*it)->get_reduction_info(); TL::OpenMP::Reduction* reduction_info = red_info_pair.first; TL::Type reduction_type = red_info_pair.second.no_ref(); ERROR_CONDITION(!Nanos::Version::interface_is_at_least("task_reduction", 1001), "The version of the runtime being used does not support task reductions", 0); TL::Symbol reduction_item = (*it)->get_symbol(); ERROR_CONDITION(reduction_type.is_array() && (IS_C_LANGUAGE || IS_CXX_LANGUAGE) && !Nanos::Version::interface_is_at_least("task_reduction", 1002), "The version of the runtime being used does not support array reductions in C/C++", 0); // Note that at this point all the reduction must be registered. // For C/C++ array reductions, the registered_reduction type is the // element type TL::Type registered_reduction_type = reduction_type; while (!IS_FORTRAN_LANGUAGE && registered_reduction_type.is_array()) { registered_reduction_type = registered_reduction_type.array_element(); } LoweringVisitor::reduction_task_map_t::iterator task_red_info = _task_reductions_map.find(std::make_pair(reduction_info, registered_reduction_type)); ERROR_CONDITION(task_red_info == _task_reductions_map.end(), "Unregistered task reduction\n", 0); TL::Symbol reduction_function = task_red_info->second._reducer; TL::Symbol reduction_function_original_var = task_red_info->second._reducer_orig_var; TL::Symbol initializer_function = task_red_info->second._initializer; // Common case: the runtime will host the private copies of the list item if (!(IS_FORTRAN_LANGUAGE && reduction_type.is_array())) { // Array Reductions in C/C++ are defined over the elements of the array TL::Source reduction_size_src_opt; TL::Type element_type = registered_reduction_type; reduction_size_src_opt << "sizeof(" << as_type(reduction_type) <<"),"; TL::Source item_address = (reduction_item.get_type().is_pointer() ? "" : "&") + (*it)->get_field_name(); src << "nanos_err = nanos_task_reduction_register(" << "(void *) " << item_address << "," // object address << reduction_size_src_opt // whole reduction size << "sizeof(" << as_type(element_type) << ")," // element size << "(void (*)(void *, void *)) &" << initializer_function.get_name() << "," // initializer << "(void (*)(void *, void *)) &" << reduction_function.get_name() << ");" // reducer ; } else { // Specific case for Fortran Array Reductions: the runtime will // host a private array descriptor for each thread. Later, in // the initializer function, this array descriptors will be // initialized and their array storage will be allocated TL::Source target_address; size_t size_array_descriptor = fortran_size_of_array_descriptor( fortran_get_rank0_type(reduction_type.get_internal_type()), fortran_get_rank_of_type(reduction_type.get_internal_type())); if (reduction_type.array_requires_descriptor()) { TL::Symbol ptr_of_sym = get_function_ptr_of(reduction_item, construct.retrieve_context()); target_address << ptr_of_sym.get_name() << "( " << (*it)->get_symbol().get_name() << ")"; } else { target_address << "(void *) &" << (*it)->get_field_name(); } src << "nanos_err = nanos_task_fortran_array_reduction_register(" << target_address << "," // Address to the array descriptor << "(void *) & " << (*it)->get_field_name() << "," // Address to the storage << size_array_descriptor << "," // size << "(void (*)(void *, void *)) &" << initializer_function.get_name() << "," // initializer << "(void (*)(void *, void *)) &" << reduction_function.get_name() << "," // reducer << "(void (*)(void *, void *)) &" << reduction_function_original_var.get_name() << ");" // reducer ori ; } } }
bool LoweringVisitor::handle_reductions_on_task( Nodecl::NodeclBase construct, OutlineInfo& outline_info, Nodecl::NodeclBase statements, bool generate_final_stmts, Nodecl::NodeclBase& final_statements) { int num_reductions = 0; TL::Source reductions_stuff, final_clause_stuff, // This source represents an expression which is used to check if // we can do an optimization in the final code. This optimization // consists on calling the original code (with a serial closure) if // we are in a final context and the reduction variables that we // are using have not been registered previously final_clause_opt_expr, extra_array_red_memcpy; std::map<TL::Symbol, std::string> reduction_symbols_map; TL::ObjectList<OutlineDataItem*> data_items = outline_info.get_data_items(); for (TL::ObjectList<OutlineDataItem*>::iterator it = data_items.begin(); it != data_items.end(); it++) { if (!(*it)->is_reduction()) continue; std::pair<TL::OpenMP::Reduction*, TL::Type> red_info_pair = (*it)->get_reduction_info(); TL::OpenMP::Reduction* reduction_info = red_info_pair.first; TL::Type reduction_type = red_info_pair.second.no_ref(); TL::Symbol reduction_item = (*it)->get_symbol(); TL::Type reduction_item_type = reduction_item.get_type().no_ref(); std::string storage_var_name = (*it)->get_field_name() + "_storage"; TL::Type storage_var_type = reduction_type.get_pointer_to(); TL::Symbol reduction_function, reduction_function_original_var, initializer_function; // Checking if the current reduction type has been treated before // Note that if that happens we can reuse the combiner and // initializer function. // // C/C++: note that if the type of the list item is an array type, // we regiter the reduction over its element type TL::Type registered_reduction_type = reduction_type; while (!IS_FORTRAN_LANGUAGE && registered_reduction_type.is_array()) { registered_reduction_type = registered_reduction_type.array_element(); } LoweringVisitor::reduction_task_map_t::iterator task_red_info = _task_reductions_map.find(std::make_pair(reduction_info, registered_reduction_type)); if (task_red_info != _task_reductions_map.end()) { reduction_function = task_red_info->second._reducer; reduction_function_original_var = task_red_info->second._reducer_orig_var; initializer_function = task_red_info->second._initializer; } else { create_reduction_functions(reduction_info, construct, registered_reduction_type, reduction_item, reduction_function, reduction_function_original_var); create_initializer_function(reduction_info, construct, registered_reduction_type, initializer_function); _task_reductions_map.insert( std::make_pair( std::make_pair(reduction_info, registered_reduction_type), TaskReductionsInfo(reduction_function, reduction_function_original_var, initializer_function) )); } // Mandatory TL::Sources to be filled by any reduction TL::Source orig_address, // address of the original reduction variable storage_var; // variable which holds the address of the storage // Specific TL::Sources to be filled only by Fortran array reduction TL::Source extra_array_red_decl; if (IS_C_LANGUAGE || IS_CXX_LANGUAGE) { storage_var << storage_var_name; orig_address << (reduction_item_type.is_pointer() ? "" : "&") << (*it)->get_field_name(); final_clause_stuff << "if (" << storage_var_name << " == 0)" << "{" << storage_var_name << " = " << "(" << as_type(storage_var_type) << ")" << orig_address << ";" << "}" ; } else { orig_address << "&" << (*it)->get_field_name(); if (reduction_item_type.is_array()) { size_t size_of_array_descriptor = fortran_size_of_array_descriptor( fortran_get_rank0_type(reduction_item_type.get_internal_type()), fortran_get_rank_of_type(reduction_item_type.get_internal_type())); storage_var << storage_var_name << "_indirect"; extra_array_red_decl << "void *" << storage_var << ";"; extra_array_red_memcpy << "nanos_err = nanos_memcpy(" << "(void **) &" << storage_var_name << "," << storage_var << "," << size_of_array_descriptor << ");" ; final_clause_stuff << "if (" << storage_var << " == 0)" << "{" << "nanos_err = nanos_memcpy(" << "(void **) &" << storage_var_name << "," << "(void *) "<< orig_address << "," << size_of_array_descriptor << ");" << "}" << "else" << "{" << extra_array_red_memcpy << "}" ; } else { // We need to convert a void* type into a pointer to the reduction type. // As a void* in FORTRAN is represented as an INTEGER(8), we cannot do this // conversion directly in the FORTRAN source. For this reason we introduce // a new function that will be defined in a C file. TL::Symbol func = TL::Nanox::get_function_ptr_conversion( // Destination reduction_item_type.get_pointer_to(), // Origin TL::Type::get_void_type().get_pointer_to(), construct.retrieve_context()); storage_var << storage_var_name; final_clause_stuff << "if (" << storage_var << " == 0)" << "{" << storage_var_name << " = " << func.get_name() << "(" << orig_address << ");" << "}" ; } } if (num_reductions > 0) final_clause_opt_expr << " && "; final_clause_opt_expr << storage_var << " == 0 "; num_reductions++; reductions_stuff << extra_array_red_decl << as_type(storage_var_type) << " " << storage_var_name << ";" << "nanos_err = nanos_task_reduction_get_thread_storage(" << "(void *)" << orig_address << "," << "(void **) &" << storage_var << ");" ; reduction_symbols_map[reduction_item] = storage_var_name; } if (num_reductions != 0) { // Generating the final code if needed if (generate_final_stmts) { std::map<Nodecl::NodeclBase, Nodecl::NodeclBase>::iterator it4 = _final_stmts_map.find(construct); ERROR_CONDITION(it4 == _final_stmts_map.end(), "Unreachable code", 0); Nodecl::NodeclBase placeholder; TL::Source new_statements_src; new_statements_src << "{" << "nanos_err_t nanos_err;" << reductions_stuff << "if (" << final_clause_opt_expr << ")" << "{" << as_statement(it4->second) << "}" << "else" << "{" << final_clause_stuff << statement_placeholder(placeholder) << "}" << "}" ; final_statements = handle_task_statements( construct, statements, placeholder, new_statements_src, reduction_symbols_map); } // Generating the task code { TL::Source new_statements_src; Nodecl::NodeclBase placeholder; new_statements_src << "{" << "nanos_err_t nanos_err;" << reductions_stuff << extra_array_red_memcpy << statement_placeholder(placeholder) << "}" ; Nodecl::NodeclBase new_statements = handle_task_statements( construct, statements, placeholder, new_statements_src, reduction_symbols_map); statements.replace(new_statements); } } ERROR_CONDITION(num_reductions != 0 && !Nanos::Version::interface_is_at_least("task_reduction", 1001), "The version of the runtime begin used does not support task reductions", 0); return (num_reductions != 0); }
static TL::Symbol create_initializer_function_fortran( OpenMP::Reduction* red, TL::Type reduction_type, Nodecl::NodeclBase construct) { std::string fun_name; { std::stringstream ss; ss << "nanos_ini_" << red << "_" << reduction_type.get_internal_type() << "_" << simple_hash_str(construct.get_filename().c_str()); fun_name = ss.str(); } Nodecl::NodeclBase initializer = red->get_initializer().shallow_copy(); TL::Type omp_out_type = reduction_type, omp_ori_type = reduction_type; // These sources are only used in array reductions TL::Source omp_out_extra_attributes, extra_stuff_array_red; if (reduction_type.is_array()) { Source dims_descr; TL::Type t = reduction_type; int rank = 0; if (t.is_fortran_array()) { rank = t.fortran_rank(); } dims_descr << "("; omp_out_extra_attributes << ", POINTER, DIMENSION("; int i; for (i = 0; i < rank; i++) { if (i != 0) { dims_descr << ","; omp_out_extra_attributes << ","; } dims_descr << "LBOUND(omp_orig, DIM = " << (rank - i) << ")" << ":" << "UBOUND(omp_orig, DIM = " << (rank - i) << ")" ; omp_out_extra_attributes << ":"; t = t.array_element(); } dims_descr << ")"; omp_out_extra_attributes << ")"; omp_out_type = t; extra_stuff_array_red << "ALLOCATE(omp_out" << dims_descr <<")\n"; } Source src; src << "SUBROUTINE " << fun_name << "(omp_out, omp_orig)\n" << "IMPLICIT NONE\n" << as_type(omp_out_type) << omp_out_extra_attributes << " :: omp_out\n" << as_type(omp_ori_type) << " :: omp_orig\n" << extra_stuff_array_red << "omp_out = " << as_expression(initializer) << "\n" << "END SUBROUTINE " << fun_name << "\n" ; TL::Scope global_scope = construct.retrieve_context().get_global_scope(); Nodecl::NodeclBase function_code = src.parse_global(global_scope); TL::Symbol function_sym = global_scope.get_symbol_from_name(fun_name); ERROR_CONDITION(!function_sym.is_valid(), "Symbol %s not found", fun_name.c_str()); // As the initializer function is needed during the instantiation of // the task, this function should be inserted before the construct Nodecl::Utils::prepend_to_enclosing_top_level_location(construct, function_code); return function_sym; }
static TL::Symbol create_initializer_function_c( OpenMP::Reduction* red, TL::Type reduction_type, Nodecl::NodeclBase construct) { std::string fun_name; { std::stringstream ss; ss << "nanos_ini_" << red << "_" << reduction_type.get_internal_type() << "_" << simple_hash_str(construct.get_filename().c_str()); fun_name = ss.str(); } Nodecl::NodeclBase function_body; Source src; src << "void " << fun_name << "(" << as_type(reduction_type.no_ref().get_lvalue_reference_to()) << " omp_priv," << as_type(reduction_type.no_ref().get_lvalue_reference_to()) << " omp_orig)" << "{" << statement_placeholder(function_body) << "}" ; Nodecl::NodeclBase function_code = src.parse_global(construct.retrieve_context().get_global_scope()); TL::Scope inside_function = ReferenceScope(function_body).get_scope(); TL::Symbol param_omp_priv = inside_function.get_symbol_from_name("omp_priv"); ERROR_CONDITION(!param_omp_priv.is_valid(), "Symbol omp_priv not found", 0); TL::Symbol param_omp_orig = inside_function.get_symbol_from_name("omp_orig"); ERROR_CONDITION(!param_omp_orig.is_valid(), "Symbol omp_orig not found", 0); TL::Symbol function_sym = inside_function.get_symbol_from_name(fun_name); ERROR_CONDITION(!function_sym.is_valid(), "Symbol %s not found", fun_name.c_str()); Nodecl::NodeclBase initializer = red->get_initializer().shallow_copy(); if (initializer.is<Nodecl::StructuredValue>()) { Nodecl::StructuredValue structured_value = initializer.as<Nodecl::StructuredValue>(); if (structured_value.get_form().is<Nodecl::StructuredValueBracedImplicit>()) { structured_value.set_form(Nodecl::StructuredValueCompoundLiteral::make()); } } Nodecl::Utils::SimpleSymbolMap translation_map; translation_map.add_map(red->get_omp_priv(), param_omp_priv); translation_map.add_map(red->get_omp_orig(), param_omp_orig); Nodecl::NodeclBase new_initializer = Nodecl::Utils::deep_copy(initializer, inside_function, translation_map); if (red->get_is_initialization()) { // The original initializer was something like 'omp_priv = expr1', but the // new_initializer only represents the lhs expression (in our example, expr1). // For this reason we create manually an assignment expression. Nodecl::NodeclBase param_omp_priv_ref = Nodecl::Symbol::make(param_omp_priv); param_omp_priv_ref.set_type(param_omp_priv.get_type()); function_body.replace( Nodecl::List::make( Nodecl::ExpressionStatement::make( Nodecl::Assignment::make( param_omp_priv_ref, new_initializer, param_omp_priv_ref.get_type().no_ref()) ))); } else { function_body.replace( Nodecl::List::make(Nodecl::ExpressionStatement::make(new_initializer))); } // As the initializer function is needed during the instantiation of // the task, this function should be inserted before the construct Nodecl::Utils::prepend_to_enclosing_top_level_location(construct, function_code); return function_sym; }
std::string as_expression(const Nodecl::NodeclBase& n) { ERROR_CONDITION (n.is_null(), "Cannot create a literal expression from a null node", 0); return nodecl_expr_to_source(n.get_internal_nodecl()); }