void goto_symext::symex_free(const expr2tc &expr) { const code_free2t &code = to_code_free2t(expr); // Trigger 'free'-mode dereference of this pointer. Should generate various // dereference failure callbacks. expr2tc tmp = code.operand; dereference(tmp, false, true); address_of2tc addrof(code.operand->type, tmp); pointer_offset2tc ptr_offs(pointer_type2(), addrof); equality2tc eq(ptr_offs, zero_ulong); claim(eq, "Operand of free must have zero pointer offset"); // Clear the alloc bit, and set the deallocated bit. guardt guard; type2tc sym_type = type2tc(new array_type2t(get_bool_type(), expr2tc(), true)); pointer_object2tc ptr_obj(pointer_type2(), code.operand); symbol2tc dealloc_sym(sym_type, deallocd_arr_name); index2tc dealloc_index_expr(get_bool_type(), dealloc_sym, ptr_obj); expr2tc truth = true_expr; symex_assign_rec(dealloc_index_expr, truth, guard); symbol2tc valid_sym(sym_type, valid_ptr_arr_name); index2tc valid_index_expr(get_bool_type(), valid_sym, ptr_obj); expr2tc falsity = false_expr; symex_assign_rec(valid_index_expr, falsity, guard); }
void goto_symext::track_new_pointer( const expr2tc &ptr_obj, const type2tc &new_type, const expr2tc &size) { // Also update all the accounting data. // Mark that object as being dynamic, in the __ESBMC_is_dynamic array type2tc sym_type = type2tc(new array_type2t(get_bool_type(), expr2tc(), true)); symbol2tc sym(sym_type, dyn_info_arr_name); index2tc idx(get_bool_type(), sym, ptr_obj); expr2tc truth = gen_true_expr(); symex_assign(code_assign2tc(idx, truth), true); symbol2tc valid_sym(sym_type, valid_ptr_arr_name); index2tc valid_index_expr(get_bool_type(), valid_sym, ptr_obj); truth = gen_true_expr(); symex_assign(code_assign2tc(valid_index_expr, truth), true); symbol2tc dealloc_sym(sym_type, deallocd_arr_name); index2tc dealloc_index_expr(get_bool_type(), dealloc_sym, ptr_obj); expr2tc falseity = gen_false_expr(); symex_assign(code_assign2tc(dealloc_index_expr, falseity), true); type2tc sz_sym_type = type2tc(new array_type2t(pointer_type2(), expr2tc(), true)); symbol2tc sz_sym(sz_sym_type, alloc_size_arr_name); index2tc sz_index_expr(get_bool_type(), sz_sym, ptr_obj); expr2tc object_size_exp; if(is_nil_expr(size)) { try { mp_integer object_size = type_byte_size(new_type); object_size_exp = constant_int2tc(pointer_type2(), object_size.to_ulong()); } catch(array_type2t::dyn_sized_array_excp *e) { object_size_exp = typecast2tc(pointer_type2(), e->size); } } else { object_size_exp = size; } symex_assign(code_assign2tc(sz_index_expr, object_size_exp), true); }
void goto_symext::symex_free(const expr2tc &expr) { const code_free2t &code = to_code_free2t(expr); // Trigger 'free'-mode dereference of this pointer. Should generate various // dereference failure callbacks. expr2tc tmp = code.operand; dereference(tmp, dereferencet::FREE); // Don't rely on the output of dereference in free mode; instead fetch all // the internal dereference state for pointed at objects, and creates claims // that if pointed at, their offset is zero. internal_deref_items.clear(); tmp = code.operand; // Create temporary, dummy, dereference tmp = dereference2tc(get_uint8_type(), tmp); dereference(tmp, dereferencet::INTERNAL); // Only add assertions to check pointer offset if pointer check is enabled if(!options.get_bool_option("no-pointer-check")) { for(auto const &item : internal_deref_items) { guardt g = cur_state->guard; g.add(item.guard); expr2tc offset = item.offset; expr2tc eq = equality2tc(offset, gen_ulong(0)); g.guard_expr(eq); claim(eq, "Operand of free must have zero pointer offset"); } } // Clear the alloc bit, and set the deallocated bit. type2tc sym_type = type2tc(new array_type2t(get_bool_type(), expr2tc(), true)); expr2tc ptr_obj = pointer_object2tc(pointer_type2(), code.operand); dereference(ptr_obj, dereferencet::READ); symbol2tc dealloc_sym(sym_type, deallocd_arr_name); index2tc dealloc_index_expr(get_bool_type(), dealloc_sym, ptr_obj); expr2tc truth = gen_true_expr(); symex_assign(code_assign2tc(dealloc_index_expr, truth), true); symbol2tc valid_sym(sym_type, valid_ptr_arr_name); index2tc valid_index_expr(get_bool_type(), valid_sym, ptr_obj); expr2tc falsity = gen_false_expr(); symex_assign(code_assign2tc(valid_index_expr, falsity), true); }
void goto_symext::symex_free(const expr2tc &expr) { const code_free2t &code = to_code_free2t(expr); // Trigger 'free'-mode dereference of this pointer. Should generate various // dereference failure callbacks. expr2tc tmp = code.operand; dereference(tmp, false, true); // Don't rely on the output of dereference in free mode; instead fetch all // the internal dereference state for pointed at objects, and creates claims // that if pointed at, their offset is zero. internal_deref_items.clear(); tmp = code.operand; // Create temporary, dummy, dereference tmp = dereference2tc(get_uint8_type(), tmp); dereference(tmp, false, false, true); // 'internal' dereference for (const auto &item : internal_deref_items) { guardt g = cur_state->guard; g.add(item.guard); expr2tc offset = item.offset; expr2tc eq = equality2tc(offset, zero_ulong); g.guard_expr(eq); claim(eq, "Operand of free must have zero pointer offset"); } // Clear the alloc bit, and set the deallocated bit. guardt guard; type2tc sym_type = type2tc(new array_type2t(get_bool_type(), expr2tc(), true)); pointer_object2tc ptr_obj(pointer_type2(), code.operand); symbol2tc dealloc_sym(sym_type, deallocd_arr_name); index2tc dealloc_index_expr(get_bool_type(), dealloc_sym, ptr_obj); expr2tc truth = true_expr; symex_assign_rec(dealloc_index_expr, truth, guard); symbol2tc valid_sym(sym_type, valid_ptr_arr_name); index2tc valid_index_expr(get_bool_type(), valid_sym, ptr_obj); expr2tc falsity = false_expr; symex_assign_rec(valid_index_expr, falsity, guard); }
Type* type_check_not(Expr const* e1) { if (is_bool_type(e1->type())) return get_bool_type(); error("Expression not of bool type found in not expression: "); print(e1); print("\n"); return nullptr; }
Type* type_check_equality(Expr const* e1, Expr const* e2) { if (e1->type() == e2->type()) return get_bool_type(); else { error("Expressions of mismatched types found in equality expressions: "); print(e1); print(" and "); print(e2); print("\n"); } return nullptr; }
// Returns the type of a unary expression. // // The operand of a unary arithmetic expression (-e, +e, and ~e) // shall have integer type. The result type the expression is `int`. // // The operand of the unary logical expression (!e) shall have // boolean type. The result type the expression is `bool`. Type const* get_type(Unary_op op, Expr const* e) { Type const* z = get_int_type(); Type const* b = get_bool_type(); switch (op) { case num_neg_op: case num_pos_op: case bit_not_op: return expect_type(e, z, z); case log_not_op: return expect_type(e, b, b); default: break; } lingo_unreachable(); }
Type* type_check_ordering(Expr const* e1, Expr const* e2) { if (is_reals_type(e1->type())) { if (is_reals_type(e2->type())) return get_bool_type(); else { error("Expression not of integer or double type found in ordering expression: "); print(e2); print("\n"); } } else { error("Expression not of integer or double type found in ordering expression: "); print(e1); print("\n"); } return nullptr; }
Type* type_check_logical(Expr const* e1, Expr const* e2) { if (is_bool_type(e1->type())) { if (is_bool_type(e2->type())) return get_bool_type(); else { error("Expression not of bool type found in logical expression: "); print(e2); print("\n"); } } else { error("Expression not of bool type found in logical expression: "); print(e1); print("\n"); } return nullptr; }
// Returns the type of a binary expression. // // The operands of a binary arithmetic expression (e1 + e2, e1 - e2, // e1 * e2, e1 / e2, e1 % e2, e1 & e2, e1 | e2, e1 ^ e2, e1 << e2, // and e1 >> e2) shall have integer type. The result type the // expression is `int`. // // The operands of a binary relational expression (e1 < e2, e1 > e2, // e1 <= e2, e1 >= e2, e1 == e2, and e1 != e2) shall have integer or // boolean type. The result type the expression is `bool`. // // The operands of a binary logical expression (e1 && e2 and e1 || e2) // shall have boolean type. The result type the expression is `bool`. Type const* get_type(Binary_op op, Expr const* e1, Expr const* e2) { Type const* z = get_int_type(); Type const* b = get_bool_type(); switch (op) { case num_add_op: case num_sub_op: case num_mul_op: case num_div_op: case num_mod_op: case bit_and_op: case bit_or_op: case bit_xor_op: case bit_lsh_op: case bit_rsh_op: // Arithmetic expressions have integer opreands and results. return expect_type(e1, e2, z, z); case rel_eq_op: case rel_ne_op: case rel_lt_op: case rel_gt_op: case rel_le_op: case rel_ge_op: // Relational expressions have any type and the result // is bool. return b; case log_and_op: case log_or_op: // Logical expressions have boolean operands and result. return expect_type(e1, e2, b, b); default: break; } lingo_unreachable(); }
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); }
BinaryExpression* NodeBuilder::is_less_than_or_equal_to_exp(Expression* arg1, Expression* arg2) { check_numptr_types(arg1->get_result_type(), arg2->get_result_type()); return binary_exp("is_less_than_or_equal_to", get_bool_type(), arg1, arg2); }
Requires_expr& Builder::make_requires(Decl_list const& tps, Decl_list const& ps, Req_list const& rs) { return make<Requires_expr>(get_bool_type(), tps, ps, rs); }
// Make a concept check. The type is bool. Check_expr& Builder::make_check(Concept_decl& d, Term_list const& as) { return make<Check_expr>(get_bool_type(), d, as); }
Boolean_expr& Builder::get_bool(bool b) { return make<Boolean_expr>(get_bool_type(), b); }
expr2tc goto_symext::symex_mem( const bool is_malloc, const expr2tc &lhs, const sideeffect2t &code) { if (is_nil_expr(lhs)) return expr2tc(); // ignore // size type2tc type = code.alloctype; expr2tc size = code.size; bool size_is_one = false; if (is_nil_expr(size)) size_is_one=true; else { cur_state->rename(size); mp_integer i; if (is_constant_int2t(size) && to_constant_int2t(size).as_ulong() == 1) size_is_one = true; } if (is_nil_type(type)) type = char_type2(); else if (is_union_type(type)) { // Filter out creation of instantiated unions. They're now all byte arrays. size_is_one = false; type = char_type2(); } unsigned int &dynamic_counter = get_dynamic_counter(); dynamic_counter++; // value symbolt symbol; symbol.base_name = "dynamic_" + i2string(dynamic_counter) + (size_is_one ? "_value" : "_array"); symbol.name = "symex_dynamic::" + id2string(symbol.base_name); symbol.lvalue = true; typet renamedtype = ns.follow(migrate_type_back(type)); if(size_is_one) symbol.type=renamedtype; else { symbol.type=typet(typet::t_array); symbol.type.subtype()=renamedtype; symbol.type.size(migrate_expr_back(size)); } symbol.type.dynamic(true); symbol.mode="C"; new_context.add(symbol); type2tc new_type; migrate_type(symbol.type, new_type); address_of2tc rhs_addrof(get_empty_type(), expr2tc()); if(size_is_one) { rhs_addrof.get()->type = get_pointer_type(pointer_typet(symbol.type)); rhs_addrof.get()->ptr_obj = symbol2tc(new_type, symbol.name); } else { type2tc subtype; migrate_type(symbol.type.subtype(), subtype); expr2tc sym = symbol2tc(new_type, symbol.name); expr2tc idx_val = zero_ulong; expr2tc idx = index2tc(subtype, sym, idx_val); rhs_addrof.get()->type = get_pointer_type(pointer_typet(symbol.type.subtype())); rhs_addrof.get()->ptr_obj = idx; } expr2tc rhs = rhs_addrof; expr2tc ptr_rhs = rhs; if (!options.get_bool_option("force-malloc-success")) { symbol2tc null_sym(rhs->type, "NULL"); sideeffect2tc choice(get_bool_type(), expr2tc(), expr2tc(), std::vector<expr2tc>(), type2tc(), sideeffect2t::nondet); rhs = if2tc(rhs->type, choice, rhs, null_sym); replace_nondet(rhs); ptr_rhs = rhs; } if (rhs->type != lhs->type) rhs = typecast2tc(lhs->type, rhs); cur_state->rename(rhs); expr2tc rhs_copy(rhs); guardt guard; symex_assign_rec(lhs, rhs, guard); pointer_object2tc ptr_obj(pointer_type2(), ptr_rhs); track_new_pointer(ptr_obj, new_type); dynamic_memory.push_back(allocated_obj(rhs_copy, cur_state->guard, !is_malloc)); return rhs_addrof->ptr_obj; }
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; } }