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 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 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); }
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); } }