void NeonVectorBackend::visit(const Nodecl::VectorAdd& n) { walk(n.get_lhs()); walk(n.get_rhs()); TL::Type t = n.get_type(); ERROR_CONDITION(!t.is_vector(), "Invalid type", 0); TL::Type element = t.vector_element(); ERROR_CONDITION(!element.is_float(), "Not implemented: %s", print_declarator(element.get_internal_type())); TL::Symbol builtin_fun = TL::Scope::get_global_scope().get_symbol_from_name("vaddq_f32"); ERROR_CONDITION(!builtin_fun.is_valid(), "Symbol not found", 0); n.replace( Nodecl::FunctionCall::make( builtin_fun.make_nodecl(/* set_ref_type */ true), Nodecl::List::make( n.get_lhs(), n.get_rhs()), /* alternate-name */ Nodecl::NodeclBase::null(), /* function-form */ Nodecl::NodeclBase::null(), n.get_type(), n.get_locus() ) ); }
Nodecl::Symbol Symbol::make_nodecl(bool set_ref_type, const locus_t* locus) const { Nodecl::Symbol sym = Nodecl::Symbol::make(*this, locus); if (set_ref_type) { TL::Type t = this->get_type(); if (!t.is_any_reference()) t = t.get_lvalue_reference_to(); sym.set_type(t); } else { sym.set_type(this->get_type()); } // Set constant (currently only for variables) if (this->is_variable() && this->get_type().is_const() && !this->is_parameter() // avoid 'void f(const int n = 3)' && !this->get_value().is_null() && this->get_value().is_constant()) { sym.set_constant(this->get_value().get_constant()); } return sym; }
void KNCModuleVisitor::visit(const Nodecl::VectorBitwiseXor& node) { TL::Type type = node.get_type().basic_type(); // Intrinsic name file << "_mm512_xor"; // Postfix if (type.is_float()) { file << "_ps"; } else if (type.is_integral_type()) { file << "_si128"; } else { running_error("KNC Codegen: Node %s at %s has an unsupported type.", ast_print_node_type(node.get_kind()), node.get_locus_str().c_str()); } file << "("; walk(node.get_lhs()); file << ", "; walk(node.get_rhs()); file << ")"; }
TL::Type get_array_of_vector(TL::Type t) { ERROR_CONDITION(!t.is_vector(), "Invalid type", 0); return t.vector_element().get_array_to( const_value_to_nodecl( const_value_get_signed_int(t.vector_num_elements()) ), TL::Scope::get_global_scope()); }
Nodecl::Symbol Symbol::make_nodecl(bool set_ref_type, const locus_t* locus) const { Nodecl::Symbol sym = Nodecl::Symbol::make(*this, locus); if (set_ref_type) { TL::Type t = this->get_type(); if (!t.is_any_reference()) t = t.get_lvalue_reference_to(); sym.set_type(t); } return sym; }
TL::Type get_array_of_mask(TL::Type t) { ERROR_CONDITION(!t.is_mask(), "Invalid type", 0); int n = (t.get_mask_num_elements() / 8) + !!(t.get_mask_num_elements() % 8); return TL::Type::get_unsigned_char_type().get_array_to( const_value_to_nodecl( const_value_get_signed_int(n) ), TL::Scope::get_global_scope()); }
void LoweringVisitor::create_reduction_function(OpenMP::Reduction* red, Nodecl::NodeclBase construct, TL::Type reduction_type, TL::Symbol& basic_reduction_function, TL::Symbol& vector_reduction_function) { if (IS_C_LANGUAGE || IS_CXX_LANGUAGE) { basic_reduction_function = create_basic_reduction_function_c(red, construct); // This is not yet well supported in Nanos++ if (!reduction_type.is_array()) { vector_reduction_function = create_vector_reduction_function_c(red, construct); } } else if (IS_FORTRAN_LANGUAGE) { basic_reduction_function = create_basic_reduction_function_fortran(red, construct); } else { internal_error("Code unreachable", 0); } }
void KNCModuleVisitor::visit(const Nodecl::VectorMinus& node) { TL::Type type = node.get_type().basic_type(); // Intrinsic name file << "_mm512_sub"; // Postfix if (type.is_float()) { file << "_ps"; } else if (type.is_double()) { file << "_pd"; } else if (type.is_signed_int() || type.is_unsigned_int()) { file << "_epi32"; } else if (type.is_signed_short_int() || type.is_unsigned_short_int()) { file << "_epi16"; } else if (type.is_char() || type.is_signed_char() || type.is_unsigned_char()) { file << "_epi8"; } else { running_error("KNC Codegen: Node %s at %s has an unsupported type.", ast_print_node_type(node.get_kind()), node.get_locus_str().c_str()); } file << "("; walk(node.get_lhs()); file << ", "; walk(node.get_rhs()); file << ")"; }
bool VectorizerVectorReduction::is_supported_reduction(bool is_builtin, const std::string& reduction_name, const TL::Type& reduction_type) { if(is_builtin) { if(_environment._device.compare("smp") == 0) { if(reduction_name.compare("+") == 0) { if(reduction_type.is_signed_int()) { return true; } } } else if(_environment._device.compare("knc") == 0) { if((reduction_name.compare("+") == 0) || (reduction_name.compare("-") == 0)) { if(reduction_type.is_signed_int()) { return true; } else if(reduction_type.is_float()) { return true; } else if (reduction_type.is_double()) { return true; } } } } return false; }
static TL::Symbol create_initializer_function_c( OpenMP::Reduction* red, TL::Type reduction_type, Nodecl::NodeclBase construct) { std::string fun_name; { std::stringstream ss; ss << "nanos_ini_" << red << "_" << reduction_type.get_internal_type() << "_" << simple_hash_str(construct.get_filename().c_str()); fun_name = ss.str(); } Nodecl::NodeclBase function_body; Source src; src << "void " << fun_name << "(" << as_type(reduction_type.no_ref().get_lvalue_reference_to()) << " omp_priv," << as_type(reduction_type.no_ref().get_lvalue_reference_to()) << " omp_orig)" << "{" << statement_placeholder(function_body) << "}" ; Nodecl::NodeclBase function_code = src.parse_global(construct.retrieve_context().get_global_scope()); TL::Scope inside_function = ReferenceScope(function_body).get_scope(); TL::Symbol param_omp_priv = inside_function.get_symbol_from_name("omp_priv"); ERROR_CONDITION(!param_omp_priv.is_valid(), "Symbol omp_priv not found", 0); TL::Symbol param_omp_orig = inside_function.get_symbol_from_name("omp_orig"); ERROR_CONDITION(!param_omp_orig.is_valid(), "Symbol omp_orig not found", 0); TL::Symbol function_sym = inside_function.get_symbol_from_name(fun_name); ERROR_CONDITION(!function_sym.is_valid(), "Symbol %s not found", fun_name.c_str()); Nodecl::NodeclBase initializer = red->get_initializer().shallow_copy(); if (initializer.is<Nodecl::StructuredValue>()) { Nodecl::StructuredValue structured_value = initializer.as<Nodecl::StructuredValue>(); if (structured_value.get_form().is<Nodecl::StructuredValueBracedImplicit>()) { structured_value.set_form(Nodecl::StructuredValueCompoundLiteral::make()); } } Nodecl::Utils::SimpleSymbolMap translation_map; translation_map.add_map(red->get_omp_priv(), param_omp_priv); translation_map.add_map(red->get_omp_orig(), param_omp_orig); Nodecl::NodeclBase new_initializer = Nodecl::Utils::deep_copy(initializer, inside_function, translation_map); if (red->get_is_initialization()) { // The original initializer was something like 'omp_priv = expr1', but the // new_initializer only represents the lhs expression (in our example, expr1). // For this reason we create manually an assignment expression. Nodecl::NodeclBase param_omp_priv_ref = Nodecl::Symbol::make(param_omp_priv); param_omp_priv_ref.set_type(param_omp_priv.get_type()); function_body.replace( Nodecl::List::make( Nodecl::ExpressionStatement::make( Nodecl::Assignment::make( param_omp_priv_ref, new_initializer, param_omp_priv_ref.get_type().no_ref()) ))); } else { function_body.replace( Nodecl::List::make(Nodecl::ExpressionStatement::make(new_initializer))); } // As the initializer function is needed during the instantiation of // the task, this function should be inserted before the construct Nodecl::Utils::prepend_to_enclosing_top_level_location(construct, function_code); return function_sym; }
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); }
std::string as_type(TL::Type t) { return type_to_source(t.get_internal_type()); }
bool casting_needs_reinterpr_or_pack(TL::Type& casted_type, TL::Type& cast_type) { if (casted_type.is_float()) { if (cast_type.is_float()) return false; else return true; } else if (casted_type.is_double()) { if (cast_type.is_double()) return false; else return true; } else if (casted_type.is_signed_int() || casted_type.is_unsigned_int()) { if (cast_type.is_signed_int() || cast_type.is_unsigned_int()) return false; else return true; } else if (casted_type.is_signed_short_int() || casted_type.is_unsigned_short_int()) { if (cast_type.is_signed_short_int() || cast_type.is_unsigned_short_int()) return false; else return true; } else if (casted_type.is_signed_char() || casted_type.is_unsigned_char() || casted_type.is_char()) { if (cast_type.is_signed_char() || cast_type.is_unsigned_char() || cast_type.is_char()) return false; else return true; } else { fatal_error("error: casting_needs_reinterpr_or_pack does not support this casting in HLT SIMD.\n"); } }
TL::Source LoopBlocking::do_blocking() { Source result, block_loops; result << block_loops ; ObjectList<ForStatement> nest_loops = _for_nest_info.get_nest_list(); _nesting = std::min(_nest_factors.size(), nest_loops.size()); TL::Source *current_innermost_part = &block_loops; // For every loop declare its block loop variable and the inter-block loop ObjectList<TL::Expression>::iterator current_factor = _nest_factors.begin(); ObjectList<TL::ForStatement>::iterator current_for = nest_loops.begin(); for (int current_nest = 0; current_nest < _nesting; current_nest++, current_for++, current_factor++) { TL::IdExpression induction_var = current_for->get_induction_variable(); TL::Symbol sym = induction_var.get_symbol(); TL::Type type = sym.get_type(); std::string var = "_blk_" + sym.get_name(); TL::Source *new_innermost_part = new TL::Source(); (*current_innermost_part) << "for(" << type.get_declaration(sym.get_scope(), var) << " = " << current_for->get_lower_bound() << ";" << var << current_for->get_bound_operator() << current_for->get_upper_bound() << ";" << var << "+= ( " << current_for->get_step() << ") * " << current_factor->prettyprint() << ")" << (*new_innermost_part) ; current_innermost_part = new_innermost_part; } // Now for every loop, declare the intra-loop current_factor = _nest_factors.begin(); current_for = nest_loops.begin(); for (int current_nest = 0; current_nest < _nesting; current_nest++, current_for++, current_factor++) { TL::IdExpression induction_var = current_for->get_induction_variable(); TL::Symbol sym = induction_var.get_symbol(); TL::Type type = sym.get_type(); std::string var = induction_var.prettyprint(); std::string init_var = var; // If the loop declares the iterator in the for statement // declare it again AST_t loop_init = current_for->get_iterating_init(); if (Declaration::predicate(loop_init)) { // Fix init_var to be a declaration init_var = type.get_declaration(sym.get_scope(), var); } std::string blk_var = "_blk_" + sym.get_name(); TL::Source min_code; TL::Source *new_innermost_part = new TL::Source(); (*current_innermost_part) << "for(" << init_var << " = " << blk_var << ";" << var << current_for->get_bound_operator() << min_code << ";" << var << "+= ( " << current_for->get_step() << "))" << (*new_innermost_part) ; TL::Source a, b; min_code << "((" << a << ") < (" << b << ") ? (" << a << ") : (" << b << "))" ; a << blk_var << " + (" << current_for->get_step() << ") * (" << current_factor->prettyprint() << " - 1 )"; b << current_for->get_upper_bound(); current_innermost_part = new_innermost_part; } // And now the innermost loop (*current_innermost_part) << nest_loops[_nesting - 1].get_loop_body() ; return result; }
void LoweringVisitor::reduction_initialization_code( OutlineInfo& outline_info, Nodecl::NodeclBase ref_tree, Nodecl::NodeclBase construct) { ERROR_CONDITION(ref_tree.is_null(), "Invalid tree", 0); if (!Nanos::Version::interface_is_at_least("master", 5023)) { running_error("%s: error: a newer version of Nanos++ (>=5023) is required for reductions support\n", construct.get_locus_str().c_str()); } TL::ObjectList<OutlineDataItem*> reduction_items = outline_info.get_data_items().filter( predicate(lift_pointer(functor(&OutlineDataItem::is_reduction)))); ERROR_CONDITION (reduction_items.empty(), "No reductions to process", 0); Source result; Source reduction_declaration, thread_initializing_reduction_info, thread_fetching_reduction_info; result << reduction_declaration << "{" << as_type(get_bool_type()) << " red_single_guard;" << "nanos_err_t err;" << "err = nanos_enter_sync_init(&red_single_guard);" << "if (err != NANOS_OK)" << "nanos_handle_error(err);" << "if (red_single_guard)" << "{" << "int nanos_num_threads = nanos_omp_get_num_threads();" << thread_initializing_reduction_info << "err = nanos_release_sync_init();" << "if (err != NANOS_OK)" << "nanos_handle_error(err);" << "}" << "else" << "{" << "err = nanos_wait_sync_init();" << "if (err != NANOS_OK)" << "nanos_handle_error(err);" << thread_fetching_reduction_info << "}" << "}" ; for (TL::ObjectList<OutlineDataItem*>::iterator it = reduction_items.begin(); it != reduction_items.end(); it++) { std::string nanos_red_name = "nanos_red_" + (*it)->get_symbol().get_name(); std::pair<OpenMP::Reduction*, TL::Type> reduction_info = (*it)->get_reduction_info(); OpenMP::Reduction* reduction = reduction_info.first; TL::Type reduction_type = reduction_info.second; if (reduction_type.is_any_reference()) reduction_type = reduction_type.references_to(); TL::Type reduction_element_type = reduction_type; if (IS_FORTRAN_LANGUAGE) { while (reduction_element_type.is_fortran_array()) reduction_element_type = reduction_element_type.array_element(); } else { while (reduction_element_type.is_array()) reduction_element_type = reduction_element_type.array_element(); } Source element_size; if (IS_FORTRAN_LANGUAGE) { if (reduction_type.is_fortran_array()) { // We need to parse this bit in Fortran Source number_of_bytes; number_of_bytes << "SIZE(" << (*it)->get_symbol().get_name() << ") * " << reduction_element_type.get_size(); element_size << as_expression(number_of_bytes.parse_expression(construct)); } else { element_size << "sizeof(" << as_type(reduction_type) << ")"; } } else { element_size << "sizeof(" << as_type(reduction_type) << ")"; } reduction_declaration << "nanos_reduction_t* " << nanos_red_name << ";" ; Source allocate_private_buffer, cleanup_code; Source num_scalars; TL::Symbol basic_reduction_function, vector_reduction_function; create_reduction_function(reduction, construct, reduction_type, basic_reduction_function, vector_reduction_function); (*it)->reduction_set_basic_function(basic_reduction_function); thread_initializing_reduction_info << "err = nanos_malloc((void**)&" << nanos_red_name << ", sizeof(nanos_reduction_t), " << "\"" << construct.get_filename() << "\", " << construct.get_line() << ");" << "if (err != NANOS_OK)" << "nanos_handle_error(err);" << nanos_red_name << "->original = (void*)" << (reduction_type.is_array() ? "" : "&") << (*it)->get_symbol().get_name() << ";" << allocate_private_buffer << nanos_red_name << "->vop = " << (vector_reduction_function.is_valid() ? as_symbol(vector_reduction_function) : "0") << ";" << nanos_red_name << "->bop = (void(*)(void*,void*,int))" << as_symbol(basic_reduction_function) << ";" << nanos_red_name << "->element_size = " << element_size << ";" << nanos_red_name << "->num_scalars = " << num_scalars << ";" << cleanup_code << "err = nanos_register_reduction(" << nanos_red_name << ");" << "if (err != NANOS_OK)" << "nanos_handle_error(err);" ; if (IS_C_LANGUAGE || IS_CXX_LANGUAGE) { if (reduction_type.is_array()) { num_scalars << "sizeof(" << as_type(reduction_type) << ") / sizeof(" << as_type(reduction_element_type) <<")"; } else { num_scalars << "1"; } allocate_private_buffer << "err = nanos_malloc(&" << nanos_red_name << "->privates, sizeof(" << as_type(reduction_type) << ") * nanos_num_threads, " << "\"" << construct.get_filename() << "\", " << construct.get_line() << ");" << "if (err != NANOS_OK)" << "nanos_handle_error(err);" << nanos_red_name << "->descriptor = " << nanos_red_name << "->privates;" << "rdv_" << (*it)->get_field_name() << " = (" << as_type( (*it)->get_private_type().get_pointer_to() ) << ")" << nanos_red_name << "->privates;" ; thread_fetching_reduction_info << "err = nanos_reduction_get(&" << nanos_red_name << ", " << (reduction_type.is_array() ? "" : "&") << (*it)->get_symbol().get_name() << ");" << "if (err != NANOS_OK)" << "nanos_handle_error(err);" << "rdv_" << (*it)->get_field_name() << " = (" << as_type( (*it)->get_private_type().get_pointer_to() ) << ")" << nanos_red_name << "->privates;" ; cleanup_code << nanos_red_name << "->cleanup = nanos_free0;" ; } else if (IS_FORTRAN_LANGUAGE) { Type private_reduction_vector_type; Source extra_dims; { TL::Type t = (*it)->get_symbol().get_type().no_ref(); int rank = 0; if (t.is_fortran_array()) { rank = t.fortran_rank(); } if (rank != 0) { // We need to parse this bit in Fortran Source size_call; size_call << "SIZE(" << (*it)->get_symbol().get_name() << ")"; num_scalars << as_expression(size_call.parse_expression(construct)); } else { num_scalars << "1"; } private_reduction_vector_type = fortran_get_n_ranked_type_with_descriptor( get_void_type(), rank + 1, construct.retrieve_context().get_decl_context()); int i; for (i = 0; i < rank; i++) { Source lbound_src; lbound_src << "LBOUND(" << (*it)->get_symbol().get_name() << ", DIM = " << (rank - i) << ")"; Source ubound_src; ubound_src << "UBOUND(" << (*it)->get_symbol().get_name() << ", DIM = " << (rank - i) << ")"; extra_dims << "[" << as_expression(lbound_src.parse_expression(construct)) << ":" << as_expression(ubound_src.parse_expression(construct)) << "]"; t = t.array_element(); } } allocate_private_buffer << "@FORTRAN_ALLOCATE@((*rdv_" << (*it)->get_field_name() << ")[0:(nanos_num_threads-1)]" << extra_dims <<");" << nanos_red_name << "->privates = &(*rdv_" << (*it)->get_field_name() << ");" << "err = nanos_malloc(&" << nanos_red_name << "->descriptor, sizeof(" << as_type(private_reduction_vector_type) << "), " << "\"" << construct.get_filename() << "\", " << construct.get_line() << ");" << "if (err != NANOS_OK)" << "nanos_handle_error(err);" << "err = nanos_memcpy(" << nanos_red_name << "->descriptor, " "&rdv_" << (*it)->get_field_name() << ", sizeof(" << as_type(private_reduction_vector_type) << "));" << "if (err != NANOS_OK)" << "nanos_handle_error(err);" ; thread_fetching_reduction_info << "err = nanos_reduction_get(&" << nanos_red_name << ", &" << (*it)->get_symbol().get_name() << ");" << "if (err != NANOS_OK)" << "nanos_handle_error(err);" << "err = nanos_memcpy(" << "&rdv_" << (*it)->get_field_name() << "," << nanos_red_name << "->descriptor, " << "sizeof(" << as_type(private_reduction_vector_type) << "));" << "if (err != NANOS_OK)" << "nanos_handle_error(err);" ; TL::Symbol reduction_cleanup = create_reduction_cleanup_function(reduction, construct); cleanup_code << nanos_red_name << "->cleanup = " << as_symbol(reduction_cleanup) << ";" ; } else { internal_error("Code unreachable", 0); } } FORTRAN_LANGUAGE() { Source::source_language = SourceLanguage::C; } ref_tree.replace(result.parse_statement(ref_tree)); FORTRAN_LANGUAGE() { Source::source_language = SourceLanguage::Current; } }
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; }
TL::Source LoopDistribution::do_distribution() { TL::Statement loop_body = _for_stmt.get_loop_body(); if (!loop_body.is_compound_statement()) { return _for_stmt.prettyprint(); } TL::Source result; TL::Source distributed_loops, expanded_scalars; result << "{" << expanded_scalars << distributed_loops << "}" ; TL::ReplaceIdExpression escalar_expansion; if (!_expand.empty()) { if (!_for_stmt.is_regular_loop()) { return _for_stmt.prettyprint(); } expanded_scalars << "int __loop_trip = (" << _for_stmt.get_upper_bound() << ") - (" << _for_stmt.get_lower_bound() << " + 1);" // Absolute value (calculated this way allows for conditional move instructions) << "__loop_trip = (__loop_trip < 0) ? (-__loop_trip) : __loop_trip;" ; // We need this because of array nature TL::AST_t array_expr; { TL::AST_t array_expr_ref_tree; Source temporal_parse; temporal_parse << "{" << expanded_scalars << statement_placeholder(array_expr_ref_tree) << "}" ; temporal_parse.parse_statement(_for_stmt.get_ast(), _for_stmt.get_scope_link()); array_expr = Source("__loop_trip").parse_expression(array_expr_ref_tree, _for_stmt.get_scope_link()); } for (TL::ObjectList<TL::Symbol>::iterator it = _expand.begin(); it != _expand.end(); it++) { TL::Symbol &sym(*it); std::string expanded_scalar_name = "_" + sym.get_name(); TL::Type type = sym.get_type(); TL::Type array_type = type.get_array_to(array_expr, _for_stmt.get_scope_link().get_scope(array_expr)); expanded_scalars << array_type.get_declaration(it->get_scope(), expanded_scalar_name) << ";"; escalar_expansion.add_replacement(sym, expanded_scalar_name + "[" + _for_stmt.get_induction_variable().prettyprint() + "]" ); } } TL::ObjectList<TL::Statement> statement_list = loop_body.get_inner_statements(); for (TL::ObjectList<TL::Statement>::iterator it = statement_list.begin(); it != statement_list.end(); it++) { Statement &stmt(*it); distributed_loops << "for ( " << _for_stmt.get_iterating_init().prettyprint() // This one already includes ';' << _for_stmt.get_iterating_condition() << ";" << _for_stmt.get_iterating_expression() << ")" << "{" << escalar_expansion.replace(stmt) << "}" ; } return result; }
void LoweringVisitor::perform_partial_reduction(OutlineInfo& outline_info, Nodecl::NodeclBase ref_tree) { ERROR_CONDITION(ref_tree.is_null(), "Invalid tree", 0); Source reduction_code; TL::ObjectList<OutlineDataItem*> reduction_items = outline_info.get_data_items().filter( predicate(lift_pointer(functor(&OutlineDataItem::is_reduction)))); if (!reduction_items.empty()) { for (TL::ObjectList<OutlineDataItem*>::iterator it = reduction_items.begin(); it != reduction_items.end(); it++) { if (IS_C_LANGUAGE || IS_CXX_LANGUAGE) { if ((*it)->get_private_type().is_array()) { reduction_code << "__builtin_memcpy(rdv_" << (*it)->get_field_name() << "[nanos_omp_get_thread_num()]," << "rdp_" << (*it)->get_symbol().get_name() << "," << " sizeof(" << as_type((*it)->get_private_type()) << "));" ; } else { reduction_code << "rdv_" << (*it)->get_field_name() << "[nanos_omp_get_thread_num()] " << "= rdp_" << (*it)->get_symbol().get_name() << ";" ; } } else if (IS_FORTRAN_LANGUAGE) { Source extra_dims; { TL::Type t = (*it)->get_symbol().get_type().no_ref(); int rank = 0; if (t.is_fortran_array()) { rank = t.fortran_rank(); } int i; for (i = 0; i < rank; i++) { extra_dims << ":,"; } } reduction_code << "rdv_" << (*it)->get_field_name() << "( " << extra_dims << "nanos_omp_get_thread_num() ) = rdp_" << (*it)->get_symbol().get_name() << "\n" ; } else { internal_error("Code unreachable", 0); } } } ref_tree.replace(reduction_code.parse_statement(ref_tree)); }
static TL::Symbol create_initializer_function_fortran( OpenMP::Reduction* red, TL::Type reduction_type, Nodecl::NodeclBase construct) { std::string fun_name; { std::stringstream ss; ss << "nanos_ini_" << red << "_" << reduction_type.get_internal_type() << "_" << simple_hash_str(construct.get_filename().c_str()); fun_name = ss.str(); } Nodecl::NodeclBase initializer = red->get_initializer().shallow_copy(); TL::Type omp_out_type = reduction_type, omp_ori_type = reduction_type; // These sources are only used in array reductions TL::Source omp_out_extra_attributes, extra_stuff_array_red; if (reduction_type.is_array()) { Source dims_descr; TL::Type t = reduction_type; int rank = 0; if (t.is_fortran_array()) { rank = t.fortran_rank(); } dims_descr << "("; omp_out_extra_attributes << ", POINTER, DIMENSION("; int i; for (i = 0; i < rank; i++) { if (i != 0) { dims_descr << ","; omp_out_extra_attributes << ","; } dims_descr << "LBOUND(omp_orig, DIM = " << (rank - i) << ")" << ":" << "UBOUND(omp_orig, DIM = " << (rank - i) << ")" ; omp_out_extra_attributes << ":"; t = t.array_element(); } dims_descr << ")"; omp_out_extra_attributes << ")"; omp_out_type = t; extra_stuff_array_red << "ALLOCATE(omp_out" << dims_descr <<")\n"; } Source src; src << "SUBROUTINE " << fun_name << "(omp_out, omp_orig)\n" << "IMPLICIT NONE\n" << as_type(omp_out_type) << omp_out_extra_attributes << " :: omp_out\n" << as_type(omp_ori_type) << " :: omp_orig\n" << extra_stuff_array_red << "omp_out = " << as_expression(initializer) << "\n" << "END SUBROUTINE " << fun_name << "\n" ; TL::Scope global_scope = construct.retrieve_context().get_global_scope(); Nodecl::NodeclBase function_code = src.parse_global(global_scope); TL::Symbol function_sym = global_scope.get_symbol_from_name(fun_name); ERROR_CONDITION(!function_sym.is_valid(), "Symbol %s not found", fun_name.c_str()); // As the initializer function is needed during the instantiation of // the task, this function should be inserted before the construct Nodecl::Utils::prepend_to_enclosing_top_level_location(construct, function_code); return function_sym; }
TL::Source LoopUnroll::do_unroll() { if (!_for_stmt.regular_loop()) { return silly_unroll(); } // Get parts of the loop IdExpression induction_var = _for_stmt.get_induction_variable(); Expression lower_bound = _for_stmt.get_lower_bound(); Expression upper_bound = _for_stmt.get_upper_bound(); Expression step = _for_stmt.get_step(); TL::Source operator_bound = _for_stmt.get_bound_operator(); Statement loop_body = _for_stmt.get_loop_body(); TL::Source result, epilogue, main, induction_var_decl, before_main, after_main; std::stringstream ss; ss << _factor; result << "{" << induction_var_decl << before_main << main << after_main << epilogue << "}" ; Source replicated_body; Source epilogue_body; if (_factor > 1) { AST_t init = _for_stmt.get_iterating_init(); if (Declaration::predicate(init)) { TL::Symbol sym = induction_var.get_symbol(); TL::Type type = sym.get_type(); // Declare it since it will have local scope induction_var_decl << type.get_declaration(sym.get_scope(), sym.get_name()) << ";" ; } main << "for (" << induction_var << " = " << lower_bound << ";" << induction_var << operator_bound << "((" << upper_bound << ") - (" << _factor << " - 1)* (" << step << "));" << induction_var << "+= (" << step << ") * " << _factor << ")" << "{" << replicated_body << "}" ; // FIXME - It could help to initialize here another variable and make both loops independent epilogue << "for ( ; " // No initialization, keep using the old induction var << induction_var << operator_bound << upper_bound << ";" << induction_var << "+= (" << step << "))" << epilogue_body ; if (!_remove_tasks) { epilogue_body << loop_body; } else { std::cerr << "Do not create task " << __FILE__ << ":" << __LINE__ << std::endl; running_error("Path not supported yet", 0); // epilogue_body << loop_body.get_ast().prettyprint_with_callback(functor(ignore_tasks)); } } else { // Leave it as is main << "for(" << _for_stmt.get_iterating_init().prettyprint() << _for_stmt.get_iterating_condition() << ";" << _for_stmt.get_iterating_expression() << ")" << "{" << replicated_body << "}" ; } // Replicate the body bool consider_omp = false; if (TaskAggregation::contains_relevant_openmp(loop_body)) { consider_omp = true; } if (_ignore_omp || !consider_omp) { simple_replication(_factor, replicated_body, epilogue_body, induction_var, loop_body); } else { omp_replication(_factor, replicated_body, epilogue_body, induction_var, loop_body, before_main, after_main); } return result; }
Type Type::fix_references_() { if ((IS_C_LANGUAGE && this->is_any_reference()) || (IS_CXX_LANGUAGE && this->is_rebindable_reference())) { TL::Type ref = this->references_to(); if (ref.is_array()) { // T (&a)[10] -> T * const // T (&a)[10][20] -> T (* const)[20] ref = ref.array_element(); } // T &a -> T * const a TL::Type ptr = ref.get_pointer_to(); if (!this->is_rebindable_reference()) { ptr = ptr.get_const_type(); } return ptr; } else if (IS_FORTRAN_LANGUAGE && this->is_any_reference()) { return this->references_to(); } else if (this->is_array()) { if (this->array_is_region()) { Nodecl::NodeclBase lb, reg_lb, ub, reg_ub; this->array_get_bounds(lb, ub); this->array_get_region_bounds(reg_lb, reg_ub); TL::Scope sc = array_type_get_region_size_expr_context(this->get_internal_type()); return this->array_element().fix_references_().get_array_to_with_region(lb, ub, reg_lb, reg_ub, sc); } else { Nodecl::NodeclBase size = this->array_get_size(); TL::Scope sc = array_type_get_array_size_expr_context(this->get_internal_type()); return this->array_element().fix_references_().get_array_to(size, sc); } } else if (this->is_pointer()) { TL::Type fixed = this->points_to().fix_references_().get_pointer_to(); cv_qualifier_t cv_qualif = CV_NONE; ::advance_over_typedefs_with_cv_qualif(this->get_internal_type(), &cv_qualif); fixed = ::get_cv_qualified_type(fixed.get_internal_type(), cv_qualif); return fixed; } else if (this->is_function()) { // Do not fix unprototyped functions if (this->lacks_prototype()) return (*this); cv_qualifier_t cv_qualif = CV_NONE; ::advance_over_typedefs_with_cv_qualif(this->get_internal_type(), &cv_qualif); ref_qualifier_t ref_qualifier = function_type_get_ref_qualifier(this->get_internal_type()); TL::Type fixed_result = this->returns().fix_references_(); bool has_ellipsis = 0; TL::ObjectList<TL::Type> fixed_parameters = this->parameters(has_ellipsis); for (TL::ObjectList<TL::Type>::iterator it = fixed_parameters.begin(); it != fixed_parameters.end(); it++) { *it = it->fix_references_(); } TL::ObjectList<TL::Type> nonadjusted_fixed_parameters = this->nonadjusted_parameters(); for (TL::ObjectList<TL::Type>::iterator it = nonadjusted_fixed_parameters.begin(); it != nonadjusted_fixed_parameters.end(); it++) { *it = it->fix_references_(); } TL::Type fixed_function = fixed_result.get_function_returning( fixed_parameters, nonadjusted_fixed_parameters, has_ellipsis, ref_qualifier); fixed_function = TL::Type(get_cv_qualified_type(fixed_function.get_internal_type(), cv_qualif)); return fixed_function; } // Note: we are not fixing classes else { // Anything else must be left untouched return (*this); } }