void pre_erase_term(Term* term) { // If this term declares a Type, then clear the Type.declaringTerm pointer, // before it becomes invalid. if (is_type(term) && as_type(term_value(term))->declaringTerm == term) as_type(term_value(term))->declaringTerm = NULL; }
void tv_static_type_query(Type* type, StaticTypeQuery* query) { Term* subject = query->subject; Type* subjectType = query->subjectType; // If the type doesn't have a specific size, then accept any list. if (!list_type_has_specific_size(&type->parameter)) { if (is_list_based_type(subjectType)) return query->succeed(); else return query->fail(); } caValue* expectedElementTypes = list_get_type_list_from_type(type); // Special case when looking at a call to list(); look at inputs instead of // looking at the result. if (subject && subject->function == FUNCS.list) { if (subject->numInputs() != circa_count(expectedElementTypes)) return query->fail(); for (int i=0; i < circa_count(expectedElementTypes); i++) if (!circa::term_output_always_satisfies_type( subject->input(i), as_type(circa_index(expectedElementTypes, i)))) return query->fail(); return query->succeed(); } // Look at the subject's type. if (!list_type_has_specific_size(&subjectType->parameter)) return query->fail(); caValue* subjectElementTypes = list_get_type_list_from_type(subjectType); bool anyUnableToDetermine = false; for (int i=0; i < circa_count(expectedElementTypes); i++) { if (i >= circa_count(subjectElementTypes)) return query->fail(); StaticTypeQuery::Result result = run_static_type_query( as_type(circa_index(expectedElementTypes,i)), as_type(circa_index(subjectElementTypes,i))); // If any of these fail, then fail. if (result == StaticTypeQuery::FAIL) return query->fail(); if (result == StaticTypeQuery::UNABLE_TO_DETERMINE) anyUnableToDetermine = true; } if (anyUnableToDetermine) return query->unableToDetermine(); else return query->succeed(); }
void test_find_common_type() { test_assert(find_common_type(&INT_T,&INT_T) == &INT_T); test_assert(find_common_type(&FLOAT_T,&FLOAT_T) == &FLOAT_T); //test_assert(find_common_type(&INT_T,&FLOAT_T) == &FLOAT_T); test_assert(find_common_type(&BOOL_T,&STRING_T) == &ANY_T); test_assert(find_common_type(as_type(KERNEL->get("Point")), as_type(KERNEL->get("Rect"))) == &LIST_T); }
Type* Type_cast_specializeType(Term* caller) { if (is_value(caller->input(0)) && is_type(caller->input(0))) return as_type(term_value(caller->input(0))); return NULL; }
void print(Value x) { if (is_nil(x)) prints("nil"); else if (is_eof(x)) printf("#eof"); else if (is_fixnum(x)) printf("%d", as_fixnum(x)); else if (is_bool(x)) printf("%s", as_bool(x) ? "true" : "false"); else if (is_char(x)) printf("'%c'", as_char(x)); else if (is_pair(x)) print_list(x); else if (is_symbol(x)) prints(as_symbol(x)->value); else if (is_string(x)) print_string(as_string(x)); else if (is_procedure(x)) printf("#<procedure %s>", as_procedure(x)->name->value); else if (is_module(x)) printf("#<module>"); else if (is_type(x)) printf("#<type %s>", as_type(x)->name->value); else if (is_ptr(x)) printf("#<object %p>", as_ptr(x)); else if (is_undefined(x)) printf("#undefined"); else printf("#ufo"); }
Type* get_field_specializeType(Term* caller) { Type* head = caller->input(0)->type; for (int nameIndex=1; nameIndex < caller->numInputs(); nameIndex++) { // Abort if input type is not correct if (!is_string(term_value(caller->input(1)))) return TYPES.any; if (!is_list_based_type(head)) return TYPES.any; Value* name = term_value(caller->input(1)); int fieldIndex = list_find_field_index_by_name(head, name); if (fieldIndex == -1) return TYPES.any; head = as_type(get_index(list_get_type_list_from_type(head),fieldIndex)); } return head; }
void Type__property(caStack* stack) { Type* type = as_type(circa_input(stack, 0)); const char* str = as_cstring(circa_input(stack, 1)); caValue* prop = get_type_property(type, str); if (prop == NULL) set_null(circa_output(stack, 0)); else copy(prop, circa_output(stack, 0)); }
Type* type_make_specializeType(Term* caller) { Term* input = caller->input(0); if (input == NULL) return TYPES.any; if (is_value(input) && is_type(input)) return as_type(input); return TYPES.any; }
Type* specializeType(Term* caller) { Term* input = caller->input(0); if (input == NULL) return &ANY_T; if (is_value(input) && is_type(input)) return as_type(input); return &ANY_T; }
void tv_initialize(Type* type, caValue* value) { ca_assert(value->value_data.ptr == NULL); // If the parameter has a fixed size list, then initialize to that. if (list_type_has_specific_size(&type->parameter)) { caValue* typeList = list_get_type_list_from_type(type); int count = list_length(typeList); list_resize(value, count); for (int i=0; i < count; i++) make(as_type(list_get(typeList, i)), list_get(value, i)); } }
std::string generate_cpp_headers(Branch* branch) { std::stringstream out; for (int i=0; i < branch->length(); i++) { if (branch->get(i) == NULL) continue; Term* term = branch->get(i); if (is_type(term)) out << cpp_accessor_for_type(as_type(term_value(term))); } return out.str(); }
void repl_evaluate_line(Stack* context, std::string const& input, std::ostream& output) { Branch* branch = top_branch(context); int previousHead = branch->length(); parser::compile(branch, parser::statement_list, input); int newHead = branch->length(); bool anyErrors = false; int resultIndex = -1; for (int i=previousHead; i < newHead; i++) { Term* result = branch->get(i); if (has_static_error(result)) { output << "error: "; print_static_error(result, output); output << std::endl; anyErrors = true; break; } Frame* frame = top_frame(context); frame->pc = i; frame->endPc = i + 1; run_interpreter(context); if (error_occurred(context)) { output << "error: "; print_error_stack(context, std::cout); anyErrors = true; break; } resultIndex = i; } // Print results of the last expression if (!anyErrors && resultIndex != -1) { Term* result = branch->get(resultIndex); if (result->type != as_type(VOID_TYPE)) { output << find_stack_value_for_term(context, result, 0)->toString() << std::endl; } } clear_error(context); }
Type* migrate_type(Type* type, Migration* migration) { if (type->declaringTerm == NULL) return NULL; Term* newTerm = migrate_term_pointer(type->declaringTerm, migration); if (newTerm == NULL) return NULL; if (newTerm == type->declaringTerm) return type; if (!is_type(newTerm)) return NULL; return as_type(newTerm); }
void tv_cast(CastResult* result, caValue* value, Type* type, bool checkOnly) { if (!is_list(value)) { result->success = false; return; } int sourceLength = list_length(value); // If the requested type doesn't have a specific size restriction, then // the input data is fine as-is. if (!list_type_has_specific_size(&type->parameter)) { if (!checkOnly) value->value_type = type; return; } List& destTypes = *List::checkCast(list_get_type_list_from_type(type)); // Check for correct number of elements. if (sourceLength != destTypes.length()) { result->success = false; return; } if (!checkOnly) { INCREMENT_STAT(Touch_ListCast); list_touch(value); value->value_type = type; } for (int i=0; i < sourceLength; i++) { caValue* sourceElement = list_get(value, i); Type* expectedType = as_type(destTypes[i]); INCREMENT_STAT(Cast_ListCastElement); cast(result, sourceElement, expectedType, checkOnly); if (!result->success) return; } }
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* find_common_type(caValue* list) { if (list_length(list) == 0) return TYPES.any; // Check if every type in this list is the same. bool all_equal = true; for (int i=1; i < list_length(list); i++) { if (as_type(list_get(list,0)) != as_type(list_get(list,i))) { all_equal = false; break; } } if (all_equal) return as_type(list_get(list,0)); // Special case, allow ints to go into floats bool all_are_ints_or_floats = true; for (int i=0; i < list_length(list); i++) { if ((as_type(list_get(list,i)) != TYPES.int_type) && (as_type(list_get(list,i)) != TYPES.float_type)) { all_are_ints_or_floats = false; break; } } if (all_are_ints_or_floats) return TYPES.float_type; // Another special case, if all types are lists then use List bool all_are_lists = true; for (int i=0; i < list_length(list); i++) { if (!is_list_based_type(as_type(list_get(list,i)))) all_are_lists = false; } if (all_are_lists) return TYPES.list; // Otherwise give up return TYPES.any; }
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; }
Type* as_type(Term* term) { return as_type(term_value(term)); }
TL::Symbol LoweringVisitor::create_basic_reduction_function_fortran(OpenMP::Reduction* red, Nodecl::NodeclBase construct) { reduction_map_t::iterator it = _basic_reduction_map_openmp.find(red); if (it != _basic_reduction_map_openmp.end()) { return it->second; } std::string fun_name; { std::stringstream ss; ss << "nanos_red_" << red << "_" << simple_hash_str(construct.get_filename().c_str()); fun_name = ss.str(); } Nodecl::NodeclBase function_body; Source src; src << "SUBROUTINE " << fun_name << "(omp_out, omp_in, num_scalars)\n" << "IMPLICIT NONE\n" << as_type(red->get_type()) << " :: omp_out(num_scalars)\n" << as_type(red->get_type()) << " :: omp_in(num_scalars)\n" << "INTEGER, VALUE :: num_scalars\n" << "INTEGER :: I\n" << statement_placeholder(function_body) << "\n" << "END SUBROUTINE " << fun_name << "\n"; ; Nodecl::NodeclBase function_code = src.parse_global(construct); TL::Scope inside_function = ReferenceScope(function_body).get_scope(); TL::Symbol param_omp_in = inside_function.get_symbol_from_name("omp_in"); ERROR_CONDITION(!param_omp_in.is_valid(), "Symbol omp_in not found", 0); TL::Symbol param_omp_out = inside_function.get_symbol_from_name("omp_out"); ERROR_CONDITION(!param_omp_out.is_valid(), "Symbol omp_out 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()); TL::Symbol index = inside_function.get_symbol_from_name("i"); ERROR_CONDITION(!index.is_valid(), "Symbol %s not found", "i"); TL::Symbol num_scalars = inside_function.get_symbol_from_name("num_scalars"); ERROR_CONDITION(!num_scalars.is_valid(), "Symbol %s not found", "num_scalars"); Nodecl::NodeclBase num_scalars_ref = Nodecl::Symbol::make(num_scalars); num_scalars_ref.set_type(num_scalars.get_type().no_ref().get_lvalue_reference_to()); Nodecl::Symbol nodecl_index = Nodecl::Symbol::make(index); nodecl_index.set_type(index.get_type().get_lvalue_reference_to()); Nodecl::NodeclBase loop_header = Nodecl::RangeLoopControl::make( nodecl_index, const_value_to_nodecl(const_value_get_signed_int(1)), num_scalars_ref, Nodecl::NodeclBase::null()); Nodecl::NodeclBase expanded_combiner = red->get_combiner().shallow_copy(); BasicReductionExpandVisitor expander_visitor( red->get_omp_in(), param_omp_in, red->get_omp_out(), param_omp_out, index); expander_visitor.walk(expanded_combiner); function_body.replace( Nodecl::ForStatement::make(loop_header, Nodecl::List::make( Nodecl::ExpressionStatement::make( expanded_combiner)), Nodecl::NodeclBase::null())); _basic_reduction_map_openmp[red] = function_sym; if (IS_FORTRAN_LANGUAGE) { Nodecl::Utils::Fortran::append_used_modules(construct.retrieve_context(), function_sym.get_related_scope()); } Nodecl::Utils::append_to_enclosing_top_level_location(construct, function_code); return function_sym; }
static Symbol create_new_function_opencl_allocate( Nodecl::NodeclBase expr_stmt, Symbol subscripted_symbol, Type element_type, int num_dimensions, bool is_allocatable) { std::string alloca_or_pointer = is_allocatable ? "ALLOCATABLE" : "POINTER"; TL::Source dummy_arguments_bounds, dimension_attr, allocate_dims; dimension_attr << "DIMENSION("; for (int i = 1; i <= num_dimensions; ++i) { if (i != 1) { allocate_dims << ", "; dummy_arguments_bounds <<", "; dimension_attr << ", "; } dummy_arguments_bounds <<"LB" << i <<", " << "UB" << i; dimension_attr << ":"; allocate_dims << "LB" << i << ":" << "UB" << i; } dimension_attr << ")"; size_t size_of_array_descriptor = fortran_size_of_array_descriptor( fortran_get_rank0_type(subscripted_symbol.get_type().get_internal_type()), fortran_get_rank_of_type(subscripted_symbol.get_type().get_internal_type())); TL::Source new_function_name; new_function_name << "NANOX_OPENCL_ALLOCATE_INTERNAL_" << (ptrdiff_t) subscripted_symbol.get_internal_symbol() ; Nodecl::NodeclBase nodecl_body; TL::Source new_function; new_function << "SUBROUTINE " << new_function_name << "(ARR, " << dummy_arguments_bounds << ")\n" << as_type(element_type) << ", " << dimension_attr << ", " << alloca_or_pointer << " :: ARR\n" << as_type(element_type) << ", " << dimension_attr << ", ALLOCATABLE :: TMP\n" << "INTEGER :: " << dummy_arguments_bounds << "\n" << "INTEGER :: ERR \n" << "ALLOCATE(TMP(" << allocate_dims << "))\n" << statement_placeholder(nodecl_body) << "DEALLOCATE(TMP)\n" << "END SUBROUTINE " << new_function_name << "\n" ; Nodecl::NodeclBase function_code = new_function.parse_global(expr_stmt.retrieve_context().get_global_scope()); TL::Scope inside_function = ReferenceScope(nodecl_body).get_scope(); TL::Symbol new_function_sym = inside_function.get_symbol_from_name(strtolower(new_function_name.get_source().c_str())); TL::Symbol arr_sym = inside_function.get_symbol_from_name("arr"); TL::Symbol tmp_sym = inside_function.get_symbol_from_name("tmp"); TL::Symbol ptr_of_arr_sym = get_function_ptr_of(arr_sym, inside_function); TL::Symbol ptr_of_tmp_sym = get_function_ptr_of(tmp_sym, inside_function); TL::Source aux; aux << "ERR = NANOS_MEMCPY(" << ptr_of_arr_sym.get_name() << "(ARR)," << ptr_of_tmp_sym.get_name() << "(TMP)," << "INT(" << size_of_array_descriptor << "," << type_get_size(get_ptrdiff_t_type()) << "))\n" << "CALL NANOS_OPENCL_ALLOCATE_FORTRAN(" << "SIZEOF(TMP)," << ptr_of_arr_sym.get_name() << "(ARR))\n" ; nodecl_body.replace(aux.parse_statement(inside_function)); Nodecl::Utils::prepend_to_enclosing_top_level_location(expr_stmt, function_code); return new_function_sym; }
void bootstrap_kernel() { // First, instanciate the types that are used by Type. TYPES.dict = create_type_uninitialized(); TYPES.null = create_type_uninitialized(); TYPES.string = create_type_uninitialized(); TYPES.type = create_type_uninitialized(); initialize_type(TYPES.dict); initialize_type(TYPES.null); initialize_type(TYPES.string); initialize_type(TYPES.type); string_setup_type(TYPES.string); // Initialize remaining global types. TYPES.any = create_type(); TYPES.block = create_type(); TYPES.bool_type = create_type(); TYPES.error = create_type(); TYPES.eval_context = create_type(); TYPES.float_type = create_type(); TYPES.function = create_type(); TYPES.int_type = create_type(); TYPES.list = create_type(); TYPES.map = create_type(); TYPES.opaque_pointer = create_type(); TYPES.symbol = create_type(); TYPES.term = create_type(); TYPES.void_type = create_type(); any_t::setup_type(TYPES.any); block_setup_type(TYPES.block); bool_t::setup_type(TYPES.bool_type); dict_t::setup_type(TYPES.dict); eval_context_t::setup_type(TYPES.eval_context); function_t::setup_type(TYPES.function); hashtable_setup_type(TYPES.map); int_t::setup_type(TYPES.int_type); list_t::setup_type(TYPES.list); symbol_setup_type(TYPES.symbol); null_t::setup_type(TYPES.null); number_t::setup_type(TYPES.float_type); opaque_pointer_t::setup_type(TYPES.opaque_pointer); term_setup_type(TYPES.term); string_setup_type(TYPES.error); // errors are just stored as strings for now type_t::setup_type(TYPES.type); void_t::setup_type(TYPES.void_type); // Start building World g_world = alloc_world(); g_world->bootstrapStatus = sym_Bootstrapping; // Create root Block. g_world->root = new Block(); Block* kernel = g_world->root; // Create value function Term* valueFunc = kernel->appendNew(); rename(valueFunc, "value"); FUNCS.value = valueFunc; // Create Type type Term* typeType = kernel->appendNew(); typeType->function = FUNCS.value; typeType->type = TYPES.type; term_value(typeType)->value_type = TYPES.type; term_value(typeType)->value_data.ptr = TYPES.type; TYPES.type->declaringTerm = typeType; rename(typeType, "Type"); // Create Any type Term* anyType = kernel->appendNew(); anyType->function = valueFunc; anyType->type = TYPES.type; term_value(anyType)->value_type = TYPES.type; term_value(anyType)->value_data.ptr = TYPES.any; TYPES.any->declaringTerm = anyType; rename(anyType, "any"); // Create Function type Term* functionType = kernel->appendNew(); functionType->function = valueFunc; functionType->type = TYPES.type; TYPES.function->declaringTerm = functionType; term_value(functionType)->value_type = TYPES.type; term_value(functionType)->value_data.ptr = TYPES.function; rename(functionType, "Function"); // Initialize value() func valueFunc->type = TYPES.function; valueFunc->function = valueFunc; make(TYPES.function, term_value(valueFunc)); function_t::initialize(TYPES.function, term_value(valueFunc)); initialize_function(valueFunc); as_function(valueFunc)->name = "value"; block_set_evaluation_empty(function_contents(valueFunc), true); // Initialize primitive types (this requires value() function) create_type_value(kernel, TYPES.bool_type, "bool"); create_type_value(kernel, TYPES.block, "Block"); create_type_value(kernel, TYPES.dict, "Dict"); create_type_value(kernel, TYPES.float_type, "number"); create_type_value(kernel, TYPES.int_type, "int"); create_type_value(kernel, TYPES.list, "List"); create_type_value(kernel, TYPES.opaque_pointer, "opaque_pointer"); create_type_value(kernel, TYPES.string, "String"); create_type_value(kernel, TYPES.symbol, "Symbol"); create_type_value(kernel, TYPES.term, "Term"); create_type_value(kernel, TYPES.void_type, "void"); create_type_value(kernel, TYPES.map, "Map"); // Finish initializing World (this requires List and Hashtable types) world_initialize(g_world); // Create global symbol table (requires Hashtable type) symbol_initialize_global_table(); // Setup output_placeholder() function, needed to declare functions properly. FUNCS.output = create_value(kernel, TYPES.function, "output_placeholder"); function_t::initialize(TYPES.function, term_value(FUNCS.output)); initialize_function(FUNCS.output); as_function(FUNCS.output)->name = "output_placeholder"; as_function(FUNCS.output)->evaluate = NULL; as_function(FUNCS.output)->specializeType = output_placeholder_specializeType; ca_assert(function_get_output_type(FUNCS.output, 0) == TYPES.any); // Fix some holes in value() function { Function* attrs = as_function(valueFunc); Term* output = append_output_placeholder(function_contents(attrs), NULL); change_declared_type(output, TYPES.any); finish_building_function(function_contents(attrs)); } ca_assert(function_get_output_type(valueFunc, 0) == TYPES.any); // input_placeholder() is needed before we can declare a function with inputs FUNCS.input = import_function(kernel, NULL, "input_placeholder() -> any"); block_set_evaluation_empty(function_contents(FUNCS.input), true); // Now that we have input_placeholder() let's declare one input on output_placeholder() apply(function_contents(as_function(FUNCS.output)), FUNCS.input, TermList())->setBoolProp("optional", true); namespace_function::early_setup(kernel); // Setup declare_field() function, needed to represent compound types. FUNCS.declare_field = import_function(kernel, NULL, "declare_field() -> any"); // Initialize a few more types Term* set_type = create_value(kernel, TYPES.type, "Set"); set_t::setup_type(unbox_type(set_type)); Term* indexableType = create_value(kernel, TYPES.type, "Indexable"); indexable_t::setup_type(unbox_type(indexableType)); TYPES.selector = unbox_type(create_value(kernel, TYPES.type, "Selector")); list_t::setup_type(TYPES.selector); control_flow_setup_funcs(kernel); selector_setup_funcs(kernel); loop_setup_functions(kernel); // Setup all the builtin functions defined in src/functions setup_builtin_functions(kernel); FUNCS.section_block = import_function(kernel, NULL, "def section_block() -> any"); as_function(FUNCS.section_block)->formatSource = section_block_formatSource; // Create IMPLICIT_TYPES (deprecated) type_initialize_kernel(kernel); // Now we can build derived functions // Create overloaded functions FUNCS.add = create_overloaded_function(kernel, "add(any a,any b) -> any"); append_to_overloaded_function(FUNCS.add, FUNCS.add_i); append_to_overloaded_function(FUNCS.add, FUNCS.add_f); Term* less_than = create_overloaded_function(kernel, "less_than(any a,any b) -> bool"); append_to_overloaded_function(less_than, kernel->get("less_than_i")); append_to_overloaded_function(less_than, kernel->get("less_than_f")); Term* less_than_eq = create_overloaded_function(kernel, "less_than_eq(any a,any b) -> bool"); append_to_overloaded_function(less_than_eq, kernel->get("less_than_eq_i")); append_to_overloaded_function(less_than_eq, kernel->get("less_than_eq_f")); Term* greater_than = create_overloaded_function(kernel, "greater_than(any a,any b) -> bool"); append_to_overloaded_function(greater_than, kernel->get("greater_than_i")); append_to_overloaded_function(greater_than, kernel->get("greater_than_f")); Term* greater_than_eq = create_overloaded_function(kernel, "greater_than_eq(any a,any b) -> bool"); append_to_overloaded_function(greater_than_eq, kernel->get("greater_than_eq_i")); append_to_overloaded_function(greater_than_eq, kernel->get("greater_than_eq_f")); Term* max_func = create_overloaded_function(kernel, "max(any a,any b) -> any"); append_to_overloaded_function(max_func, kernel->get("max_i")); append_to_overloaded_function(max_func, kernel->get("max_f")); Term* min_func = create_overloaded_function(kernel, "min(any a,any b) -> any"); append_to_overloaded_function(min_func, kernel->get("min_i")); append_to_overloaded_function(min_func, kernel->get("min_f")); Term* remainder_func = create_overloaded_function(kernel, "remainder(any a,any b) -> any"); append_to_overloaded_function(remainder_func, kernel->get("remainder_i")); append_to_overloaded_function(remainder_func, kernel->get("remainder_f")); Term* mod_func = create_overloaded_function(kernel, "mod(any a,any b) -> any"); append_to_overloaded_function(mod_func, kernel->get("mod_i")); append_to_overloaded_function(mod_func, kernel->get("mod_f")); FUNCS.mult = create_overloaded_function(kernel, "mult(any a,any b) -> any"); append_to_overloaded_function(FUNCS.mult, kernel->get("mult_i")); append_to_overloaded_function(FUNCS.mult, kernel->get("mult_f")); FUNCS.neg = create_overloaded_function(kernel, "neg(any n) -> any"); append_to_overloaded_function(FUNCS.neg, kernel->get("neg_i")); append_to_overloaded_function(FUNCS.neg, kernel->get("neg_f")); as_function(FUNCS.neg)->formatSource = neg_function::formatSource; FUNCS.sub = create_overloaded_function(kernel, "sub(any a,any b) -> any"); append_to_overloaded_function(FUNCS.sub, kernel->get("sub_i")); append_to_overloaded_function(FUNCS.sub, kernel->get("sub_f")); // Create vectorized functions Term* add_v = create_function(kernel, "add_v"); create_function_vectorized_vv(function_contents(add_v), FUNCS.add, TYPES.list, TYPES.list); Term* add_s = create_function(kernel, "add_s"); create_function_vectorized_vs(function_contents(add_s), FUNCS.add, TYPES.list, TYPES.any); append_to_overloaded_function(FUNCS.add, add_v); append_to_overloaded_function(FUNCS.add, add_s); Term* sub_v = create_function(kernel, "sub_v"); create_function_vectorized_vv(function_contents(sub_v), FUNCS.sub, TYPES.list, TYPES.list); Term* sub_s = create_function(kernel, "sub_s"); create_function_vectorized_vs(function_contents(sub_s), FUNCS.sub, TYPES.list, TYPES.any); append_to_overloaded_function(FUNCS.sub, sub_v); append_to_overloaded_function(FUNCS.sub, sub_s); // Create vectorized mult() functions Term* mult_v = create_function(kernel, "mult_v"); create_function_vectorized_vv(function_contents(mult_v), FUNCS.mult, TYPES.list, TYPES.list); Term* mult_s = create_function(kernel, "mult_s"); create_function_vectorized_vs(function_contents(mult_s), FUNCS.mult, TYPES.list, TYPES.any); append_to_overloaded_function(FUNCS.mult, mult_v); append_to_overloaded_function(FUNCS.mult, mult_s); Term* div_s = create_function(kernel, "div_s"); create_function_vectorized_vs(function_contents(div_s), FUNCS.div, TYPES.list, TYPES.any); // Need dynamic_method before any hosted functions FUNCS.dynamic_method = import_function(kernel, dynamic_method_call, "def dynamic_method(any inputs :multiple) -> any"); // Load the standard library from stdlib.ca parser::compile(kernel, parser::statement_list, STDLIB_CA_TEXT); // Install C functions static const ImportRecord records[] = { {"assert", hosted_assert}, {"cppbuild:build_module", cppbuild_function::build_module}, {"file:version", file__version}, {"file:exists", file__exists}, {"file:read_text", file__read_text}, {"length", length}, {"from_string", from_string}, {"to_string_repr", to_string_repr}, {"call_actor", call_actor_func}, {"send", send_func}, {"test_spy", test_spy}, {"test_oracle", test_oracle}, {"refactor:rename", refactor__rename}, {"refactor:change_function", refactor__change_function}, {"reflect:this_block", reflect__this_block}, {"reflect:kernel", reflect__kernel}, {"sys:module_search_paths", sys__module_search_paths}, {"sys:perf_stats_reset", sys__perf_stats_reset}, {"sys:perf_stats_dump", sys__perf_stats_dump}, {"Dict.count", Dict__count}, {"Dict.get", Dict__get}, {"Dict.set", Dict__set}, {"Function.block", Function__block}, {"empty_list", empty_list}, {"List.append", List__append}, {"List.concat", List__concat}, {"List.resize", List__resize}, {"List.count", List__count}, {"List.insert", List__insert}, {"List.length", List__length}, {"List.join", List__join}, {"List.slice", List__slice}, {"List.get", List__get}, {"List.set", List__set}, {"Map.contains", Map__contains}, {"Map.remove", Map__remove}, {"Map.get", Map__get}, {"Map.set", Map__set}, {"Map.insertPairs", Map__insertPairs}, {"Mutable.get", Mutable__get}, {"Mutable.set", Mutable__set}, {"String.char_at", String__char_at}, {"String.ends_with", String__ends_with}, {"String.length", String__length}, {"String.substr", String__substr}, {"String.slice", String__slice}, {"String.starts_with", String__starts_with}, {"String.split", String__split}, {"String.to_camel_case", String__to_camel_case}, {"String.to_upper", String__to_upper}, {"String.to_lower", String__to_lower}, {"Type.name", Type__name}, {"Type.property", Type__property}, {"Type.declaringTerm", Type__declaringTerm}, {"type", typeof_func}, {"static_type", static_type_func}, {NULL, NULL} }; install_function_list(kernel, records); closures_install_functions(kernel); modules_install_functions(kernel); reflection_install_functions(kernel); interpreter_install_functions(kernel); // Fetch refereneces to certain builtin funcs. FUNCS.block_dynamic_call = kernel->get("Block.call"); FUNCS.dll_patch = kernel->get("sys:dll_patch"); FUNCS.dynamic_call = kernel->get("dynamic_call"); FUNCS.has_effects = kernel->get("has_effects"); FUNCS.length = kernel->get("length"); FUNCS.list_append = kernel->get("List.append"); FUNCS.native_patch = kernel->get("native_patch"); FUNCS.not_func = kernel->get("not"); FUNCS.output_explicit = kernel->get("output"); FUNCS.type = kernel->get("type"); block_set_has_effects(nested_contents(FUNCS.has_effects), true); // Finish setting up some hosted types TYPES.actor = as_type(kernel->get("Actor")); TYPES.color = as_type(kernel->get("Color")); TYPES.closure = as_type(kernel->get("Closure")); callable_t::setup_type(as_type(kernel->get("Callable"))); TYPES.frame = as_type(kernel->get("Frame")); TYPES.point = as_type(kernel->get("Point")); TYPES.file_signature = as_type(kernel->get("FileSignature")); Type* mutableType = as_type(kernel->get("Mutable")); circa_setup_object_type(mutableType, sizeof(Value), MutableRelease); mutableType->initialize = MutableInitialize; color_t::setup_type(TYPES.color); as_function(FUNCS.list_append)->specializeType = List__append_specializeType; }
void Type__declaringTerm(caStack* stack) { Type* type = as_type(circa_input(stack, 0)); set_term_ref(circa_output(stack, 0), type->declaringTerm); }
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; } }
void Type__name(caStack* stack) { Type* type = as_type(circa_input(stack, 0)); copy(&type->name, circa_output(stack, 0)); }
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)); }
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 ; } } }
void LoweringVisitor::loop_spawn_worksharing(OutlineInfo& outline_info, Nodecl::NodeclBase construct, Nodecl::List distribute_environment, Nodecl::RangeLoopControl& range, const std::string& outline_name, TL::Symbol structure_symbol, TL::Symbol slicer_descriptor, Nodecl::NodeclBase task_label) { Symbol enclosing_function = Nodecl::Utils::get_enclosing_function(construct); Nodecl::OpenMP::Schedule schedule = distribute_environment.find_first<Nodecl::OpenMP::Schedule>(); ERROR_CONDITION(schedule.is_null(), "Schedule tree is missing", 0); Nodecl::NodeclBase lower = range.get_lower(); Nodecl::NodeclBase upper = range.get_upper(); Nodecl::NodeclBase step = range.get_step(); Source struct_size, dynamic_size, struct_arg_type_name; struct_arg_type_name << ((structure_symbol.get_type().is_template_specialized_type() && structure_symbol.get_type().is_dependent()) ? "typename " : "") << structure_symbol.get_qualified_name(enclosing_function.get_scope()) ; struct_size << "sizeof( " << struct_arg_type_name << " )" << dynamic_size; Source immediate_decl; allocate_immediate_structure( structure_symbol.get_user_defined_type(), outline_info, struct_arg_type_name, struct_size, // out immediate_decl, dynamic_size); Source call_outline_function; Source schedule_setup; schedule_setup << "int nanos_chunk;" ; if (schedule.get_text() == "runtime") { schedule_setup << "nanos_omp_sched_t nanos_runtime_sched;" << "nanos_err = nanos_omp_get_schedule(&nanos_runtime_sched, &nanos_chunk);" << "if (nanos_err != NANOS_OK)" << "nanos_handle_error(nanos_err);" << "nanos_ws_t current_ws_policy = nanos_omp_find_worksharing(nanos_runtime_sched);" ; } else { Source schedule_name; if (Nanos::Version::interface_is_at_least("openmp", 8)) { schedule_name << "nanos_omp_sched_" << schedule.get_text(); } else { // We used nanos_omp_sched in versions prior to 8 schedule_name << "omp_sched_" << schedule.get_text(); } schedule_setup << "nanos_ws_t current_ws_policy = nanos_omp_find_worksharing(" << schedule_name << ");" << "if (current_ws_policy == 0)" << "nanos_handle_error(NANOS_UNIMPLEMENTED);" << "nanos_chunk = " << as_expression(schedule.get_chunk()) << ";" ; } Source worksharing_creation; if (IS_CXX_LANGUAGE) { worksharing_creation << as_statement(Nodecl::CxxDef::make(Nodecl::NodeclBase::null(), slicer_descriptor)); } worksharing_creation << "nanos_err = nanos_worksharing_create(" << "&" << as_symbol(slicer_descriptor) << "," << "current_ws_policy," << "(void**)&nanos_setup_info_loop," << "&single_guard);" << "if (nanos_err != NANOS_OK)" << "nanos_handle_error(nanos_err);" ; Nodecl::NodeclBase fill_outline_arguments_tree, fill_immediate_arguments_tree; TL::Source pm_specific_code; if (!_lowering->in_ompss_mode()) { // OpenMP pm_specific_code << immediate_decl << statement_placeholder(fill_immediate_arguments_tree) << "smp_" << outline_name << "(imm_args);" ; } else { // OmpSs std::string wd_description = (!task_label.is_null()) ? task_label.get_text() : enclosing_function.get_name(); Source const_wd_info; const_wd_info << fill_const_wd_info(struct_arg_type_name, /* is_untied */ false, /* mandatory_creation */ true, /* is_function_task */ false, wd_description, outline_info, construct); std::string dyn_props_var = "nanos_wd_dyn_props"; Source dynamic_wd_info; dynamic_wd_info << "nanos_wd_dyn_props_t " << dyn_props_var << ";"; fill_dynamic_properties(dyn_props_var, /* priority_expr */ nodecl_null(), /* final_expr */ nodecl_null(), /* is_implicit */ 0, dynamic_wd_info); pm_specific_code << struct_arg_type_name << " *ol_args = (" << struct_arg_type_name <<"*) 0;" << const_wd_info << "nanos_wd_t nanos_wd_ = (nanos_wd_t) 0;" << dynamic_wd_info << "static nanos_slicer_t replicate = (nanos_slicer_t)0;" << "if (replicate == (nanos_slicer_t)0)" << "replicate = nanos_find_slicer(\"replicate\");" << "if (replicate == (nanos_slicer_t)0)" << "nanos_handle_error(NANOS_UNIMPLEMENTED);" << "nanos_err = nanos_create_sliced_wd(&nanos_wd_, " << "nanos_wd_const_data.base.num_devices, nanos_wd_const_data.devices, " << "(size_t)" << struct_size << ", nanos_wd_const_data.base.data_alignment, " << "(void**)&ol_args, nanos_current_wd(), replicate," << "&nanos_wd_const_data.base.props, &" << dyn_props_var << ", 0, (nanos_copy_data_t**)0," << "0, (nanos_region_dimension_internal_t**)0" << ");" << "if (nanos_err != NANOS_OK)" << "nanos_handle_error(nanos_err);" << statement_placeholder(fill_outline_arguments_tree) << "nanos_err = nanos_submit(nanos_wd_, 0, (nanos_data_access_t *) 0, (nanos_team_t) 0);" << "if (nanos_err != NANOS_OK)" << "nanos_handle_error(nanos_err);" ; } TL::Source implicit_barrier_or_tw; if (!distribute_environment.find_first<Nodecl::OpenMP::BarrierAtEnd>().is_null()) { implicit_barrier_or_tw << get_implicit_sync_end_construct_source(); } Source spawn_code; spawn_code << "{" << as_type(get_bool_type()) << " single_guard;" << "nanos_err_t nanos_err;" << schedule_setup << "nanos_ws_info_loop_t nanos_setup_info_loop;" << "nanos_setup_info_loop.lower_bound = " << as_expression(lower) << ";" << "nanos_setup_info_loop.upper_bound = " << as_expression(upper) << ";" << "nanos_setup_info_loop.loop_step = " << as_expression(step) << ";" << "nanos_setup_info_loop.chunk_size = nanos_chunk;" << worksharing_creation << pm_specific_code << implicit_barrier_or_tw << "}" ; Source fill_outline_arguments, fill_immediate_arguments; fill_arguments(construct, outline_info, fill_outline_arguments, fill_immediate_arguments); if (IS_FORTRAN_LANGUAGE) Source::source_language = SourceLanguage::C; Nodecl::NodeclBase spawn_code_tree = spawn_code.parse_statement(construct); if (IS_FORTRAN_LANGUAGE) Source::source_language = SourceLanguage::Current; Nodecl::NodeclBase arguments_tree; TL::Source *fill_arguments; if (!_lowering->in_ompss_mode()) { // OpenMP arguments_tree = fill_immediate_arguments_tree; fill_arguments = &fill_immediate_arguments; } else { // OmpSs arguments_tree = fill_outline_arguments_tree; fill_arguments = &fill_outline_arguments; } // Now attach the slicer symbol to its final scope (see tl-lower-for-worksharing.cpp) const decl_context_t* spawn_inner_context = arguments_tree.retrieve_context().get_decl_context(); slicer_descriptor.get_internal_symbol()->decl_context = spawn_inner_context; ::insert_entry(spawn_inner_context->current_scope, slicer_descriptor.get_internal_symbol()); // Parse the arguments Nodecl::NodeclBase new_tree = fill_arguments->parse_statement(arguments_tree); arguments_tree.replace(new_tree); // Finally, replace the construct by the tree that represents the spawn code construct.replace(spawn_code_tree); }
void LoweringVisitor::visit(const Nodecl::OpenMP::TaskExpression& task_expr) { Nodecl::NodeclBase join_task = task_expr.get_join_task(); Nodecl::List task_calls = task_expr.get_task_calls().as<Nodecl::List>(); if (!_lowering->final_clause_transformation_disabled() && Nanos::Version::interface_is_at_least("master", 5024)) { ERROR_CONDITION(!task_expr.get_parent().is<Nodecl::ExpressionStatement>(), "Unexpected node", 0); Nodecl::NodeclBase expr_stmt = task_expr.get_parent(); TL::Source code; code << "{" << as_type(TL::Type::get_bool_type()) << "mcc_is_in_final;" << "nanos_err_t mcc_err_in_final = nanos_in_final(&mcc_is_in_final);" << "if (mcc_err_in_final != NANOS_OK) nanos_handle_error(mcc_err_in_final);" << "if (mcc_is_in_final)" << "{" << as_statement(task_expr.get_sequential_code()) << "}" << "else" << "{" << as_statement(Nodecl::ExpressionStatement::make(task_expr)) << "}" << "}" ; std::cout << "In expression\n"; if (IS_FORTRAN_LANGUAGE) Source::source_language = SourceLanguage::C; Nodecl::NodeclBase if_else_tree = code.parse_statement(expr_stmt); if (IS_FORTRAN_LANGUAGE) Source::source_language = SourceLanguage::Current; expr_stmt.replace(if_else_tree); } Nodecl::NodeclBase placeholder_task_expr_transformation; if (join_task.is<Nodecl::OpenMP::Task>()) { // Note: don't walk over the OpenMP::Task node because Its visitor ignores // the placeholder and sets to false the 'inside_task_expression' boolean visit_task( join_task.as<Nodecl::OpenMP::Task>(), /* inside_task_expression */ true, &placeholder_task_expr_transformation); } else if (join_task.is<Nodecl::ExpressionStatement>() && join_task.as<Nodecl::ExpressionStatement>().get_nest().is<Nodecl::OpenMP::TaskCall>()) { visit_task_call( join_task.as<Nodecl::ExpressionStatement>().get_nest().as<Nodecl::OpenMP::TaskCall>(), /* inside_task_expression */ true, &placeholder_task_expr_transformation); } else { internal_error("Unreachable code", 0); } // Note: don't walk over the OpenMP::TaskCall because It's visitor sets to // false the 'inside_task_expression' boolean for (Nodecl::List::iterator it = task_calls.begin(); it != task_calls.end(); ++it) { Nodecl::ExpressionStatement current_expr_stmt = it->as<Nodecl::ExpressionStatement>(); Nodecl::OpenMP::TaskCall current_task_call = current_expr_stmt.get_nest().as<Nodecl::OpenMP::TaskCall>(); visit_task_call(current_task_call, /* inside_task_expression */ true, /* placeholder_task_expr_transformation */ NULL); Nodecl::Utils::prepend_items_before(placeholder_task_expr_transformation, *it); } ERROR_CONDITION(!task_expr.get_parent().is<Nodecl::ExpressionStatement>(), "Unexpected node", 0); Nodecl::NodeclBase expr_stmt = task_expr.get_parent(); Nodecl::Utils::prepend_items_before(expr_stmt, task_expr.get_join_task()); // Finally, remove from the tree the TaskExpression node Nodecl::Utils::remove_from_enclosing_list(expr_stmt); }