This patch applies the rule that functions defined in FOO.c must be declared in FOO.h. One of the worst offenders in the code base is tree.h, unsurprisingly. The patch creates several new headers: attribs.h calls.h fold-const.h gcc-symtab.h print-rtl.h print-tree.h stmt.h stor-layout.h stringpool.h tree-nested.h tree-object-size.h varasm.h. Functions in each corresponding .c file got moved to those headers and others that already existed. I wanted to make this patch as mechanical as possible, so I made no attempt to fix problems like having build_addr defined in tree-inline.c. I left that for later. There were some declarations that I could not move out of tree.h because of header poisoning or the use of target macros. We forbid the inclusion of things like expr.h from FE files. While that's a reasonable idea, the FE file *still* manage to at expr.c functionality because the declarations they want to use were defined in tree.h. The affected files are builtins.h, emit-rtl.h and expr.h. If that functionality is allowed to be accessed from the FEs, then I will later move those functions out of expr.c into tree.c. I have moved these declarations to the bottom of tree.h so they are easy to identify later. There is a namespace collision with libcpp. The file gcc/symtab.c cannot use gcc/symtab.h because the #include command picks up libcpp/include/symtab.h first. So I named this file gcc-symtab.h for now. Finally, I added a new header to PLUGIN_HEADERS to account for the tree.h refactoring. I did not add all headers factored out of tree.h because it is unclear (and impossible to tell) what plugins need. This adds the one header used by the plugins in the testsuite. This will be changing quite dramatically as we progress with the header refactoring. This patch should offer some minimal incremental build advantages by reducing the size of tree.h. Changes that would otherwise affected tree.h, will now go to other headers which are less frequently included. * tree.h: Include fold-const.h. (aggregate_value_p): Moved to function.h. (alloca_call_p): Moved to calls.h. (allocate_struct_function): Moved to function.h. (apply_tm_attr): Moved to attribs.h. (array_at_struct_end_p): Moved to expr.h. (array_ref_element_size): Moved to tree-dfa.h. (array_ref_low_bound): Moved to tree-dfa.h. (array_ref_up_bound): Moved to tree.h. (assemble_alias): Moved to cgraph.h. (bit_from_pos): Moved to stor-layout.h. (build_addr): Moved to tree-nested.h. (build_duplicate_type): Moved to tree-inline.h. (build_fold_addr_expr): Moved to fold-const.h. (build_fold_addr_expr_with_type): Moved to fold-const.h. (build_fold_addr_expr_with_type_loc): Moved to fold-const.h. (build_fold_indirect_ref): Moved to fold-const.h. (build_fold_indirect_ref_loc): Moved to fold-const.h. (build_personality_function): Moved to tree.h. (build_range_check): Moved to fold-const.h. (build_simple_mem_ref): Moved to fold-const.h. (build_simple_mem_ref_loc): Moved to fold-const.h. (build_tm_abort_call): Moved to trans-mem.h. (byte_from_pos): Moved to stor-layout.h. (call_expr_flags): Moved to calls.h. (can_move_by_pieces): Moved to expr.h. (categorize_ctor_elements): Moved to expr.h. (change_decl_assembler_name): Moved to gcc-symtab.h. (combine_comparisons): Moved to fold-const.h. (complete_ctor_at_level_p): Moved to tree.h. (component_ref_field_offset): Moved to tree-dfa.h. (compute_builtin_object_size): Moved to tree-object-size.h. (compute_record_mode): Moved to stor-layout.h. (constant_boolean_node): Moved to fold-const.h. (constructor_static_from_elts_p): Moved to varasm.h. (cxx11_attribute_p): Moved to attribs.h. (debug_body): Moved to print-tree.h. (debug_find_tree): Moved to tree-inline.h. (debug_fold_checksum): Moved to fold-const.h. (debug_head): Moved to print-tree.h. (debug_head): Moved to print-tree.h. (debug_raw): Moved to print-tree.h. (debug_tree): Moved to print-tree.h. (debug_vec_tree): Moved to print-tree.h. (debug_verbose): Moved to print-tree.h. (debug_verbose): Moved to print-tree.h. (decl_attributes): Moved to attribs.h. (decl_binds_to_current_def_p): Moved to varasm.h. (decl_default_tls_model): Moved to varasm.h. (decl_replaceable_p): Moved to varasm.h. (div_if_zero_remainder): Moved to fold-const.h. (double_int mem_ref_offset): Moved to fold-const.h. (dump_addr): Moved to print-tree.h. (element_precision): Moved to machmode.h. (expand_dummy_function_end): Moved to function.h. (expand_function_end): Moved to function.h. (expand_function_start): Moved to function.h. (expand_label): Moved to stmt.h. (expr_first): Moved to tree-iterator.h. (expr_last): Moved to tree-iterator.h. (finalize_size_functions): Moved to stor-layout.h. (finish_builtin_struct): Moved to stor-layout.h. (finish_record_layout): Moved to stor-layout.h. (fixup_signed_type): Moved to stor-layout.h. (fixup_unsigned_type): Moved to stor-layout.h. (flags_from_decl_or_type): Moved to calls.h. (fold): Moved to fold-const.h. (fold_abs_const): Moved to fold-const.h. (fold_binary): Moved to fold-const.h. (fold_binary_loc): Moved to fold-const.h. (fold_binary_to_constant): Moved to fold-const.h. (fold_build1): Moved to fold-const.h. (fold_build1_initializer_loc): Moved to fold-const.h. (fold_build1_loc): Moved to fold-const.h. (fold_build1_stat_loc): Moved to fold-const.h. (fold_build2): Moved to fold-const.h. (fold_build2_initializer_loc): Moved to fold-const.h. (fold_build2_loc): Moved to fold-const.h. (fold_build2_stat_loc): Moved to fold-const.h. (fold_build3): Moved to fold-const.h. (fold_build3_loc): Moved to fold-const.h. (fold_build3_stat_loc): Moved to fold-const.h. (fold_build_call_array): Moved to fold-const.h. (fold_build_call_array_initializer): Moved to fold-const.h. (fold_build_call_array_initializer_loc): Moved to fold-const.h. (fold_build_call_array_loc): Moved to fold-const.h. (fold_build_cleanup_point_expr): Moved to fold-const.h. (fold_convert): Moved to fold-const.h. (fold_convert_loc): Moved to fold-const.h. (fold_convertible_p): Moved to fold-const.h. (fold_defer_overflow_warnings): Moved to fold-const.h. (fold_deferring_overflow_warnings_p): Moved to fold-const.h. (fold_fma): Moved to fold-const.h. (fold_ignored_result): Moved to fold-const.h. (fold_indirect_ref): Moved to fold-const.h. (fold_indirect_ref_1): Moved to fold-const.h. (fold_indirect_ref_loc): Moved to fold-const.h. (fold_read_from_constant_string): Moved to fold-const.h. (fold_real_zero_addition_p): Moved to fold-const.h. (fold_single_bit_test): Moved to fold-const.h. (fold_strip_sign_ops): Moved to fold-const.h. (fold_ternary): Moved to fold-const.h. (fold_ternary_loc): Moved to fold-const.h. (fold_unary): Moved to tree-data-ref.h. (fold_unary_ignore_overflow): Moved to fold-const.h. (fold_unary_ignore_overflow_loc): Moved to fold-const.h. (fold_unary_loc): Moved to fold-const.h. (fold_unary_to_constant): Moved to fold-const.h. (fold_undefer_and_ignore_overflow_warnings): Moved to fold-const.h. (fold_undefer_overflow_warnings): Moved to fold-const.h. (folding_initializer): Moved to fold-const.h. (free_temp_slots): Moved to function.h. (generate_setjmp_warnings): Moved to function.h. (get_attribute_name): Moved to attribs.h. (get_identifier): Moved to stringpool.h. (get_identifier_with_length): Moved to stringpool.h. (get_inner_reference): Moved to tree.h. (gimple_alloca_call_p): Moved to calls.h. (gimplify_parameters): Moved to function.h. (highest_pow2_factor): Moved to expr.h. (indent_to): Moved to print-tree.h. (init_attributes): Moved to attribs.h. (init_dummy_function_start): Moved to function.h. (init_function_start): Moved to function.h. (init_inline_once): Moved to tree-inline.h. (init_object_sizes): Moved to tree-object-size.h. (init_temp_slots): Moved to function.h. (init_tree_optimization_optabs): Moved to optabs.h. (initialize_sizetypes): Moved to stor-layout.h. (initializer_constant_valid_for_bitfield_p): Moved to varasm.h. (initializer_constant_valid_p): Moved to varasm.h. (int_const_binop): Moved to fold-const.h. (internal_reference_types): Moved to stor-layout.h. (invert_tree_comparison): Moved to fold-const.h. (invert_truthvalue): Moved to fold-const.h. (invert_truthvalue_loc): Moved to fold-const.h. (is_tm_ending_fndecl): Moved to trans-mem.h. (is_tm_may_cancel_outer): Moved to trans-mem.h. (is_tm_pure): Moved to trans-mem.h. (is_tm_safe): Moved to trans-mem.h. (layout_decl): Moved to stor-layout.h. (layout_type): Moved to stor-layout.h. (lookup_attribute_spec): Moved to attribs.h. (make_accum_type): Moved to stor-layout.h. (make_decl_one_only): Moved to varasm.h. (make_decl_rtl): Moved to tree.h. (make_decl_rtl_for_debug): Moved to varasm.h. (make_fract_type): Moved to stor-layout.h. (make_or_reuse_sat_signed_accum_type): Moved to stor-layout.h. (make_or_reuse_sat_signed_fract_type): Moved to stor-layout.h. (make_or_reuse_sat_unsigned_accum_type): Moved to stor-layout.h. (make_or_reuse_sat_unsigned_fract_type): Moved to stor-layout.h. (make_or_reuse_signed_accum_type): Moved to stor-layout.h. (make_or_reuse_signed_fract_type): Moved to stor-layout.h. (make_or_reuse_unsigned_accum_type): Moved to stor-layout.h. (make_or_reuse_unsigned_fract_type): Moved to stor-layout.h. (make_range): Moved to fold-const.h. (make_range_step): Moved to fold-const.h. (make_sat_signed_accum_type): Moved to stor-layout.h. (make_sat_signed_fract_type): Moved to stor-layout.h. (make_sat_unsigned_accum_type): Moved to stor-layout.h. (make_sat_unsigned_fract_type): Moved to stor-layout.h. (make_signed_accum_type): Moved to stor-layout.h. (make_signed_fract_type): Moved to stor-layout.h. (make_signed_type): Moved to stor-layout.h. (make_unsigned_accum_type): Moved to stor-layout.h. (make_unsigned_fract_type): Moved to stor-layout.h. (make_unsigned_type): Moved to stor-layout.h. (mark_decl_referenced): Moved to varasm.h. (mark_referenced): Moved to varasm.h. (may_negate_without_overflow_p): Moved to fold-const.h. (maybe_get_identifier): Moved to stringpool.h. (merge_ranges): Moved to fold-const.h. (merge_weak): Moved to varasm.h. (mode_for_size_tree): Moved to stor-layout.h. (multiple_of_p): Moved to fold-const.h. (must_pass_in_stack_var_size): Moved to calls.h. (must_pass_in_stack_var_size_or_pad): Moved to calls.h. (native_encode_expr): Moved to fold-const.h. (native_interpret_expr): Moved to fold-const.h. (non_lvalue): Moved to fold-const.h. (non_lvalue_loc): Moved to fold-const.h. (normalize_offset): Moved to stor-layout.h. (normalize_rli): Moved to stor-layout.h. (notice_global_symbol): Moved to varasm.h. (omit_one_operand): Moved to fold-const.h. (omit_one_operand_loc): Moved to fold-const.h. (omit_two_operands): Moved to fold-const.h. (omit_two_operands_loc): Moved to fold-const.h. (operand_equal_p): Moved to tree-data-ref.h. (parse_input_constraint): Moved to stmt.h. (parse_output_constraint): Moved to stmt.h. (place_field): Moved to stor-layout.h. (pop_function_context): Moved to function.h. (pop_temp_slots): Moved to function.h. (pos_from_bit): Moved to stor-layout.h. (preserve_temp_slots): Moved to function.h. (print_node): Moved to print-tree.h. (print_node_brief): Moved to print-tree.h. (print_rtl): Moved to rtl.h. (process_pending_assemble_externals): Moved to varasm.h. (ptr_difference_const): Moved to fold-const.h. (push_function_context): Moved to function.h. (push_struct_function): Moved to function.h. (push_temp_slots): Moved to function.h. (record_tm_replacement): Moved to trans-mem.h. (relayout_decl): Moved to stor-layout.h. (resolve_asm_operand_names): Moved to stmt.h. (resolve_unique_section): Moved to varasm.h. (rli_size_so_far): Moved to stor-layout.h. (rli_size_unit_so_far): Moved to stor-layout.h. (round_down): Moved to fold-const.h. (round_down_loc): Moved to fold-const.h. (round_up): Moved to fold-const.h. (round_up_loc): Moved to fold-const.h. (set_decl_incoming_rtl): Moved to emit-rtl.h. (set_decl_rtl): Moved to tree.h. (set_min_and_max_values_for_integral_type): Moved to stor-layout.h. (set_user_assembler_name): Moved to varasm.h. (setjmp_call_p): Moved to calls.h. (size_binop): Moved to fold-const.h. (size_binop_loc): Moved to fold-const.h. (size_diffop): Moved to fold-const.h. (size_diffop_loc): Moved to fold-const.h. (size_int_kind): Moved to fold-const.h. (stack_protect_epilogue): Moved to function.h. (start_record_layout): Moved to stor-layout.h. (supports_one_only): Moved to varasm.h. (swap_tree_comparison): Moved to fold-const.h. (tm_malloc_replacement): Moved to trans-mem.h. (tree build_fold_addr_expr_loc): Moved to fold-const.h. (tree build_invariant_address): Moved to fold-const.h. (tree_binary_nonnegative_warnv_p): Moved to fold-const.h. (tree_binary_nonzero_warnv_p): Moved to fold-const.h. (tree_call_nonnegative_warnv_p): Moved to fold-const.h. (tree_expr_nonnegative_p): Moved to fold-const.h. (tree_expr_nonnegative_warnv_p): Moved to fold-const.h. (tree_output_constant_def): Moved to varasm.h. (tree_overlaps_hard_reg_set): Moved to stmt.h. (tree_single_nonnegative_warnv_p): Moved to fold-const.h. (tree_single_nonzero_warnv_p): Moved to fold-const.h. (tree_swap_operands_p): Moved to fold-const.h. (tree_unary_nonnegative_warnv_p): Moved to fold-const.h. (tree_unary_nonzero_warnv_p): Moved to fold-const.h. (update_alignment_for_field): Moved to stor-layout.h. (use_register_for_decl): Moved to function.h. (variable_size): Moved to rtl.h. (vector_type_mode): Moved to stor-layout.h. * cgraph.h: Corresponding changes. * emit-rtl.h: Corresponding changes. * expr.h: Corresponding changes. * function.h: Corresponding changes. * optabs.h: Corresponding changes. * trans-mem.h: Corresponding changes. Protect against multiple inclusion. * tree-inline.h: Corresponding changes. * tree-iterator.h: Corresponding changes. * tree-dfa.h: Include expr.h. * tree-ssanames.h: Include stringpool.h. * attribs.h: New file. * calls.h: New file. * fold-const.h: New file. * gcc-symtab.h: New file. * print-rtl.h: New file. * print-tree.h: New file. * stmt.h: New file. * stor-layout.h: New file. * strinpool.h: New file. * tree-nested.h: New file * tree-object-size.h: New file. * varasm.h: New file. * Makefile.in (PLUGIN_HEADERS): Add stringpool.h. * alias.c: Include varasm.h. Include expr.h. * asan.c: Include calls.h. Include stor-layout.h. Include varasm.h. * attribs.c: Include stringpool.h. Include attribs.h. Include stor-layout.h. * builtins.c: Include stringpool.h. Include stor-layout.h. Include calls.h. Include varasm.h. Include tree-object-size.h. * calls.c: Include stor-layout.h. Include varasm.h. Include stringpool.h. Include attribs.h. * cfgexpand.c: Include stringpool.h. Include varasm.h. Include stor-layout.h. Include stmt.h. Include print-tree.h. * cgraph.c: Include varasm.h. Include calls.h. Include print-tree.h. * cgraphclones.c: Include stringpool.h. Include function.h. Include emit-rtl.h. Move inclusion of rtl.h earlier in the file. * cgraphunit.c: Include varasm.h. Include stor-layout.h. Include stringpool.h. * cilk-common.c: Include stringpool.h. Include stor-layout.h. * combine.c: Include stor-layout.h. * config/aarch64/aarch64-builtins.c: Include stor-layout.h. Include stringpool.h. Include calls.h. * config/aarch64/aarch64.c: Include stringpool.h. Include stor-layout.h. Include calls.h. Include varasm.h. * config/alpha/alpha.c: Include stor-layout.h. Include calls.h. Include varasm.h. * config/arc/arc.c: Include varasm.h. Include stor-layout.h. Include stringpool.h. Include calls.h. * config/arm/arm.c: Include stringpool.h. Include stor-layout.h. Include calls.h. Include varasm.h. * config/avr/avr-c.c: Include stor-layout.h. * config/avr/avr-log.c: Include print-tree.h. * config/avr/avr.c: Include print-tree.h. Include calls.h. Include stor-layout.h. Include stringpool.h. * config/bfin/bfin.c: Include varasm.h. Include calls.h. * config/c6x/c6x.c: Include stor-layout.h. Include varasm.h. Include calls.h. Include stringpool.h. * config/cr16/cr16.c: Include stor-layout.h. Include calls.h. * config/cris/cris.c: Include varasm.h. Include stor-layout.h. Include calls.h. Include stmt.h. * config/darwin.c: Include stringpool.h. Include varasm.h. Include stor-layout.h. * config/epiphany/epiphany.c: Include stor-layout.h. Include varasm.h. Include calls.h. Include stringpool.h. * config/fr30/fr30.c: Include stor-layout.h. Include varasm.h. * config/frv/frv.c: Include varasm.h. Include stor-layout.h. Include stringpool.h. * config/h8300/h8300.c: Include stor-layout.h. Include varasm.h. Include calls.h. Include stringpool.h. * config/i386/i386.c: Include stringpool.h. Include attribs.h. Include calls.h. Include stor-layout.h. Include varasm.h. * config/i386/winnt-cxx.c: Include stringpool.h. Include attribs.h. * config/i386/winnt.c: Include stringpool.h. Include varasm.h. * config/ia64/ia64-c.c: Include stringpool.h. * config/ia64/ia64.c: Include stringpool.h. Include stor-layout.h. Include calls.h. Include varasm.h. * config/iq2000/iq2000.c: Include stor-layout.h. Include calls.h. Include varasm.h. * config/lm32/lm32.c: Include calls.h. * config/m32c/m32c.c: Include stor-layout.h. Include varasm.h. Include calls.h. * config/m32r/m32r.c: Include stor-layout.h. Include varasm.h. Include stringpool.h. Include calls.h. * config/m68k/m68k.c: Include calls.h. Include stor-layout.h. Include varasm.h. * config/mcore/mcore.c: Include stor-layout.h. Include varasm.h. Include stringpool.h. Include calls.h. * config/mep/mep.c: Include varasm.h. Include calls.h. Include stringpool.h. Include stor-layout.h. * config/microblaze/microblaze.c: Include varasm.h. Include stor-layout.h. Include calls.h. * config/mips/mips.c: Include varasm.h. Include stringpool.h. Include stor-layout.h. Include calls.h. * config/mmix/mmix.c: Include varasm.h. Include stor-layout.h. Include calls.h. * config/mn10300/mn10300.c: Include stor-layout.h. Include varasm.h. Include calls.h. * config/moxie/moxie.c: Include stor-layout.h. Include varasm.h. Include calls.h. * config/msp430/msp430.c: Include stor-layout.h. Include calls.h. * config/nds32/nds32.c: Include stor-layout.h. Include varasm.h. Include calls.h. * config/pa/pa.c: Include stor-layout.h. Include stringpool.h. Include varasm.h. Include calls.h. * config/pdp11/pdp11.c: Include stor-layout.h. Include varasm.h. Include calls.h. * config/picochip/picochip.c: Include calls.h. Include stor-layout.h. Include stringpool.h. Include varasm.h. * config/rl78/rl78.c: Include varasm.h. Include stor-layout.h. Include calls.h. * config/rs6000/rs6000-c.c: Include stor-layout.h. Include stringpool.h. * config/rs6000/rs6000.c: Include stringpool.h. Include stor-layout.h. Include calls.h. Include print-tree.h. Include varasm.h. * config/rx/rx.c: Include varasm.h. Include stor-layout.h. Include calls.h. * config/s390/s390.c: Include print-tree.h. Include stringpool.h. Include stor-layout.h. Include varasm.h. Include calls.h. * config/score/score.c: Include stringpool.h. Include calls.h. Include varasm.h. Include stor-layout.h. * config/sh/sh-c.c: Include stringpool.h. Include attribs.h.h. * config/sh/sh.c: Include stringpool.h. Include stor-layout.h. Include calls.h. Include varasm.h. * config/sol2-c.c: Include stringpool.h. Include attribs.h. * config/sol2-cxx.c: Include stringpool.h. * config/sol2.c: Include stringpool.h. Include varasm.h. * config/sparc/sparc.c: Include stringpool.h. Include stor-layout.h. Include calls.h. Include varasm.h. * config/spu/spu-c.c: Include stringpool.h. * config/spu/spu.c: Include stringpool.h. Include stor-layout.h. Include calls.h. Include varasm.h. * config/stormy16/stormy16.c: Include stringpool.h. Include stor-layout.h. Include varasm.h. Include calls.h. * config/tilegx/tilegx.c: Include stringpool.h. Include stor-layout.h. Include varasm.h. Include calls.h. * config/tilepro/tilepro.c: Include stringpool.h. Include stor-layout.h. Include varasm.h. Include calls.h. * config/v850/v850-c.c: Include stringpool.h. Include attribs.h. * config/v850/v850.c: Include stringpool.h. Include stor-layout.h. Include varasm.h. Include calls.h. * config/vax/vax.c: Include calls.h. Include varasm.h. * config/vms/vms.c: Include stringpool.h. * config/vxworks.c: Include stringpool.h. * config/xtensa/xtensa.c: Include stringpool.h. Include stor-layout.h. Include calls.h. Include varasm.h. * convert.c: Include stor-layout.h. * coverage.c: Include stringpool.h. Include stor-layout.h. * dbxout.c: Include varasm.h. Include stor-layout.h. * dojump.c: Include stor-layout.h. * dse.c: Include stor-layout.h. * dwarf2asm.c: Include stringpool.h. Include varasm.h. * dwarf2cfi.c: Include stor-layout.h. * dwarf2out.c: Include rtl.h. Include stringpool.h. Include stor-layout.h. Include varasm.h. Include function.h. Include emit-rtl.h. Move inclusion of rtl.h earlier in the file. * emit-rtl.c: Include varasm.h. * except.c: Include stringpool.h. Include stor-layout.h. * explow.c: Include stor-layout.h. * expmed.c: Include stor-layout.h. * expr.c: Include stringpool.h. Include stor-layout.h. Include attribs.h. Include varasm.h. * final.c: Include varasm.h. * fold-const.c: Include stor-layout.h. Include calls.h. Include tree-iterator.h. * function.c: Include stor-layout.h. Include varasm.h. Include stringpool.h. * genattrtab.c (write_header): Emit includes for varasm.h, stor-layout.h and calls.h. * genautomata.c (main): Likewise. * genemit.c: Likewise. * genopinit.c: Likewise. * genoutput.c (output_prologue): Likewise. * genpeep.c: Likewise. * genpreds.c (write_insn_preds_c): Likewise. * gengtype.c (open_base_files): Add stringpool.h. * gimple-expr.c: Include stringpool.h. Include stor-layout.h. * gimple-fold.c: Include stringpool.h. Include expr.h. Include stmt.h. Include stor-layout.h. * gimple-low.c: Include tree-nested.h. Include calls.h. * gimple-pretty-print.c: Include stringpool.h. * gimple-ssa-strength-reduction.c: Include stor-layout.h. Include expr.h. * gimple-walk.c: Include stmt.h. * gimple.c: Include calls.h. Include stmt.h. Include stor-layout.h. * gimplify.c: Include stringpool.h. Include calls.h. Include varasm.h. Include stor-layout.h. Include stmt.h. Include print-tree.h. Include expr.h. * gimplify-me.c: Include stmt.h Include stor-layout.h * internal-fn.c: Include stor-layout.h. * ipa-devirt.c: Include print-tree.h. Include calls.h. * ipa-inline-analysis.c: Include stor-layout.h. Include stringpool.h. Include print-tree.h. * ipa-inline.c: Include trans-mem.h. Include calls.h. * ipa-prop.c: Include expr.h. Include stor-layout.h. Include print-tree.h. * ipa-pure-const.c: Include print-tree.h. Include calls.h. * ipa-reference.c: Include calls.h. * ipa-split.c: Include stringpool.h. Include expr.h. Include calls.h. * ipa.c: Include calls.h. Include stringpool.h. * langhooks.c: Include stringpool.h. Include attribs.h. * lto-cgraph.c: Include stringpool.h. * lto-streamer-in.c: Include stringpool.h. * lto-streamer-out.c: Include stor-layout.h. Include stringpool.h. * omp-low.c: Include stringpool.h. Include stor-layout.h. Include expr.h. * optabs.c: Include stor-layout.h. Include stringpool.h. Include varasm.h. * passes.c: Include varasm.h. * predict.c: Include calls.h. * print-rtl.c: Include print-tree.h. * print-tree.c: Include varasm.h. Include print-rtl.h. Include stor-layout.h. * realmpfr.c: Include stor-layout.h. * reg-stack.c: Include varasm.h. * sdbout.c: Include varasm.h. Include stor-layout.h. * simplify-rtx.c: Include varasm.h. * stmt.c: Include varasm.h. Include stor-layout.h. * stor-layout.c: Include stor-layout.h. Include stringpool.h. Include varasm.h. Include print-tree.h. * symtab.c: Include rtl.h. Include print-tree.h. Include varasm.h. Include function.h. Include emit-rtl.h. * targhooks.c: Include stor-layout.h. Include varasm.h. * toplev.c: Include varasm.h. Include tree-inline.h. * trans-mem.c: Include calls.h. Include function.h. Include rtl.h. Include emit-rtl.h. * tree-affine.c: Include expr.h. * tree-browser.c: Include print-tree.h. * tree-call-cdce.c: Include stor-layout.h. * tree-cfg.c: Include trans-mem.h. Include stor-layout.h. Include print-tree.h. * tree-complex.c: Include stor-layout.h. * tree-data-ref.c: Include expr.h. * tree-dfa.c: Include stor-layout.h. * tree-eh.c: Include expr.h. Include calls.h. * tree-emutls.c: Include stor-layout.h. Include varasm.h. * tree-if-conv.c: Include stor-layout.h. * tree-inline.c: Include stor-layout.h. Include calls.h. * tree-loop-distribution.c: Include stor-layout.h. * tree-nested.c: Include stringpool.h. Include stor-layout.h. * tree-object-size.c: Include tree-object-size.h. * tree-outof-ssa.c: Include stor-layout.h. * tree-parloops.c: Include stor-layout.h. Include tree-nested.h. * tree-pretty-print.c: Include stor-layout.h. Include expr.h. * tree-profile.c: Include varasm.h. Include tree-nested.h. * tree-scalar-evolution.c: Include expr.h. * tree-sra.c: Include stor-layout.h. * tree-ssa-address.c: Include stor-layout.h. * tree-ssa-ccp.c: Include stor-layout.h. * tree-ssa-dce.c: Include calls.h. * tree-ssa-dom.c: Include stor-layout.h. * tree-ssa-forwprop.c: Include stor-layout.h. * tree-ssa-ifcombine.c: Include stor-layout.h. * tree-ssa-loop-ivopts.c: Include stor-layout.h. * tree-ssa-loop-niter.c: Include calls.h. Include expr.h. * tree-ssa-loop-prefetch.c: Include stor-layout.h. * tree-ssa-math-opts.c: Include stor-layout.h. * tree-ssa-operands.c: Include stmt.h. Include print-tree.h. * tree-ssa-phiopt.c: Include stor-layout.h. * tree-ssa-reassoc.c: Include stor-layout.h. * tree-ssa-sccvn.c: Include stor-layout.h. * tree-ssa-sink.c: Include stor-layout.h. * tree-ssa-strlen.c: Include stor-layout.h. * tree-ssa-structalias.c: Include stor-layout.h. Include stmt.h. * tree-ssa-tail-merge.c: Include stor-layout.h. Include trans-mem.h. * tree-ssa-uncprop.c: Include stor-layout.h. * tree-ssa.c: Include stor-layout.h. * tree-ssanames.c: Include stor-layout.h. * tree-streamer-in.c: Include stringpool.h. * tree-streamer-out.c: Include stor-layout.h. * tree-switch-conversion.c: Include varasm.h. Include stor-layout.h. * tree-tailcall.c: Include stor-layout.h. * tree-vect-data-refs.c: Include stor-layout.h. * tree-vect-generic.c: Include stor-layout.h. * tree-vect-loop.c: Include stor-layout.h. * tree-vect-patterns.c: Include stor-layout.h. * tree-vect-slp.c: Include stor-layout.h. * tree-vect-stmts.c: Include stor-layout.h. * tree-vectorizer.c: Include stor-layout.h. * tree-vrp.c: Include stor-layout.h. Include calls.h. * tree.c: Include stor-layout.h. Include calls.h. Include attribs.h. Include varasm.h. * tsan.c: Include expr.h. * ubsan.c: Include stor-layout.h. Include stringpool.h. * value-prof.c: Include tree-nested.h. Include calls.h. * var-tracking.c: Include varasm.h. Include stor-layout.h. * varasm.c: Include stor-layout.h. Include stringpool.h. Include gcc-symtab.h. Include varasm.h. * varpool.c: Include varasm.h. * vmsdbgout.c: Include varasm.h. * xcoffout.c: Include varasm.h. ada/ChangeLog * gcc-interface/decl.c: Include stringpool.h Include stor-layout.h * gcc-interface/misc.c: Include stor-layout.h Include print-tree.h * gcc-interface/trans.c: Include stringpool.h Include stor-layout.h Include stmt.h Include varasm.h * gcc-interface/utils.c: Include stringpool.h Include stor-layout.h Include attribs.h Include varasm.h * gcc-interface/utils2.c: Include stringpool.h Include stor-layout.h Include attribs.h Include varasm.h c-family/ChangeLog * c-common.c: Include fold-const.h. Include stor-layout.h. Include calls.h. Include stringpool.h. Include attribs.h. Include varasm.h. Include trans-mem.h. * c-cppbuiltin.c: Include stor-layout.h. Include stringpool.h. * c-format.c: Include stringpool.h. * c-lex.c: Include stringpool.h. Include stor-layout.h. * c-pragma.c: Include stringpool.h. Include attribs.h. Include varasm.h. Include gcc-symtab.h. * c-pretty-print.c: Include stor-layout.h. Include attribs.h. * cilk.c: Include stringpool.h. Include calls.h. c/ChangeLog * c-decl.c: Include print-tree.h. Include stor-layout.h. Include varasm.h. Include attribs.h. Include stringpool.h. * c-lang.c: Include fold-const.h. * c-parser.c: Include stringpool.h. Include attribs.h. Include stor-layout.h. Include varasm.h. Include trans-mem.h. * c-typeck.c: Include stor-layout.h. Include trans-mem.h. Include varasm.h. Include stmt.h. cp/ChangeLog * call.c: Include stor-layout.h. Include trans-mem.h. Include stringpool.h. * class.c: Include stringpool.h. Include stor-layout.h. Include attribs.h. * cp-gimplify.c: Include stor-layout.h. * cvt.c: Include stor-layout.h. * decl.c: Include stringpool.h. Include stor-layout.h. Include varasm.h. Include attribs.h. Include calls.h. * decl2.c: Include stringpool.h. Include varasm.h. Include attribs.h. Include stor-layout.h. Include calls.h. * error.c: Include stringpool.h. * except.c: Include stringpool.h. Include trans-mem.h. Include attribs.h. * init.c: Include stringpool.h. Include varasm.h. * lambda.c: Include stringpool.h. * lex.c: Include stringpool.h. * mangle.c: Include stor-layout.h. Include stringpool.h. * method.c: Include stringpool.h. Include varasm.h. * name-lookup.c: Include stringpool.h. Include print-tree.h. Include attribs.h. * optimize.c: Include stringpool.h. * parser.c: Include print-tree.h. Include stringpool.h. Include attribs.h. Include trans-mem.h. * pt.c: Include stringpool.h. Include varasm.h. Include attribs.h. Include stor-layout.h. * ptree.c: Include print-tree.h. * repo.c: Include stringpool.h. * rtti.c: Include stringpool.h. Include stor-layout.h. * semantics.c: Include stmt.h. Include varasm.h. Include stor-layout.h. Include stringpool.h. * tree.c: Include stor-layout.h. Include print-tree.h. Include tree-iterator.h. * typeck.c: Include stor-layout.h. Include varasm.h. * typeck2.c: Include stor-layout.h. Include varasm.h. * vtable-class-hierarchy.c: Include stringpool.h. Include stor-layout.h. fortran/ChangeLog * decl.c: Include stringpool.h. * iresolve.c: Include stringpool.h. * match.c: Include stringpool.h. * module.c: Include stringpool.h. * target-memory.c: Include stor-layout.h. * trans-common.c: Include stringpool.h. Include stor-layout.h. Include varasm.h. * trans-const.c: Include stor-layout.h. * trans-decl.c: Include stringpool.h. Include stor-layout.h. Include varasm.h. Include attribs.h. * trans-expr.c: Include stringpool.h. * trans-intrinsic.c: Include stringpool.h. Include tree-nested.h. Include stor-layout.h. * trans-io.c: Include stringpool.h. Include stor-layout.h. * trans-openmp.c: Include stringpool.h. * trans-stmt.c: Include stringpool.h. * trans-types.c: Include stor-layout.h. Include stringpool.h. * trans.c: Include stringpool.h. go/ChangeLog * go-backend.c: Include stor-layout.h. * go-gcc.cc: Include stringpool.h. Include stor-layout.h. Include varasm.h. * go-lang.c: Include stor-layout.h. java/ChangeLog * builtins.c: Include stor-layout.h. Include stringpool.h. * class.c: Include stringpool.h. Include stor-layout.h. Include varasm.h. * constants.c: Include stringpool.h. Include stor-layout.h. * decl.c: Include stor-layout.h. Include stringpool.h. Include varasm.h. * except.c: Include stringpool.h. Include stor-layout.h. * expr.c: Include stringpool.h. Include stor-layout.h. * jcf-parse.c: Include stringpool.h. * mangle.c: Include stringpool.h. * resource.c: Include stringpool.h. Include stor-layout.h. * typeck.c: Include stor-layout.h. Include stringpool.h. * verify-glue.c: Include stringpool.h. lto/ChangeLog * lto-lang.c: Include stringpool.h. Include stor-layout.h. * lto-partition.c: Include gcc-symtab.h. * lto.c: Include stor-layout.h. objc/ChangeLog * objc-act.c: Include stringpool.h. Include stor-layout.h. Include attribs.h. * objc-encoding.c: Include stringpool.h. Include stor-layout.h. * objc-gnu-runtime-abi-01.c: Include stringpool.h. * objc-next-runtime-abi-01.c: Include stringpool.h. * objc-next-runtime-abi-02.c: Include stringpool.h. * objc-runtime-shared-support.c: Include stringpool.h. testsuite/ChangeLog * gcc.dg/plugin/selfassign.c: Include stringpool.h. * gcc.dg/plugin/start_unit_plugin.c: Likewise. From-SVN: r205023
1960 lines
56 KiB
C
1960 lines
56 KiB
C
/* OpenMP directive translation -- generate GCC trees from gfc_code.
|
|
Copyright (C) 2005-2013 Free Software Foundation, Inc.
|
|
Contributed by Jakub Jelinek <jakub@redhat.com>
|
|
|
|
This file is part of GCC.
|
|
|
|
GCC is free software; you can redistribute it and/or modify it under
|
|
the terms of the GNU General Public License as published by the Free
|
|
Software Foundation; either version 3, or (at your option) any later
|
|
version.
|
|
|
|
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with GCC; see the file COPYING3. If not see
|
|
<http://www.gnu.org/licenses/>. */
|
|
|
|
|
|
#include "config.h"
|
|
#include "system.h"
|
|
#include "coretypes.h"
|
|
#include "tree.h"
|
|
#include "gimple.h"
|
|
#include "gimplify.h" /* For create_tmp_var_raw. */
|
|
#include "stringpool.h"
|
|
#include "diagnostic-core.h" /* For internal_error. */
|
|
#include "gfortran.h"
|
|
#include "trans.h"
|
|
#include "trans-stmt.h"
|
|
#include "trans-types.h"
|
|
#include "trans-array.h"
|
|
#include "trans-const.h"
|
|
#include "arith.h"
|
|
#include "omp-low.h"
|
|
|
|
int ompws_flags;
|
|
|
|
/* True if OpenMP should privatize what this DECL points to rather
|
|
than the DECL itself. */
|
|
|
|
bool
|
|
gfc_omp_privatize_by_reference (const_tree decl)
|
|
{
|
|
tree type = TREE_TYPE (decl);
|
|
|
|
if (TREE_CODE (type) == REFERENCE_TYPE
|
|
&& (!DECL_ARTIFICIAL (decl) || TREE_CODE (decl) == PARM_DECL))
|
|
return true;
|
|
|
|
if (TREE_CODE (type) == POINTER_TYPE)
|
|
{
|
|
/* Array POINTER/ALLOCATABLE have aggregate types, all user variables
|
|
that have POINTER_TYPE type and don't have GFC_POINTER_TYPE_P
|
|
set are supposed to be privatized by reference. */
|
|
if (GFC_POINTER_TYPE_P (type))
|
|
return false;
|
|
|
|
if (!DECL_ARTIFICIAL (decl)
|
|
&& TREE_CODE (TREE_TYPE (type)) != FUNCTION_TYPE)
|
|
return true;
|
|
|
|
/* Some arrays are expanded as DECL_ARTIFICIAL pointers
|
|
by the frontend. */
|
|
if (DECL_LANG_SPECIFIC (decl)
|
|
&& GFC_DECL_SAVED_DESCRIPTOR (decl))
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/* True if OpenMP sharing attribute of DECL is predetermined. */
|
|
|
|
enum omp_clause_default_kind
|
|
gfc_omp_predetermined_sharing (tree decl)
|
|
{
|
|
if (DECL_ARTIFICIAL (decl)
|
|
&& ! GFC_DECL_RESULT (decl)
|
|
&& ! (DECL_LANG_SPECIFIC (decl)
|
|
&& GFC_DECL_SAVED_DESCRIPTOR (decl)))
|
|
return OMP_CLAUSE_DEFAULT_SHARED;
|
|
|
|
/* Cray pointees shouldn't be listed in any clauses and should be
|
|
gimplified to dereference of the corresponding Cray pointer.
|
|
Make them all private, so that they are emitted in the debug
|
|
information. */
|
|
if (GFC_DECL_CRAY_POINTEE (decl))
|
|
return OMP_CLAUSE_DEFAULT_PRIVATE;
|
|
|
|
/* Assumed-size arrays are predetermined shared. */
|
|
if (TREE_CODE (decl) == PARM_DECL
|
|
&& GFC_ARRAY_TYPE_P (TREE_TYPE (decl))
|
|
&& GFC_TYPE_ARRAY_AKIND (TREE_TYPE (decl)) == GFC_ARRAY_UNKNOWN
|
|
&& GFC_TYPE_ARRAY_UBOUND (TREE_TYPE (decl),
|
|
GFC_TYPE_ARRAY_RANK (TREE_TYPE (decl)) - 1)
|
|
== NULL)
|
|
return OMP_CLAUSE_DEFAULT_SHARED;
|
|
|
|
/* Dummy procedures aren't considered variables by OpenMP, thus are
|
|
disallowed in OpenMP clauses. They are represented as PARM_DECLs
|
|
in the middle-end, so return OMP_CLAUSE_DEFAULT_FIRSTPRIVATE here
|
|
to avoid complaining about their uses with default(none). */
|
|
if (TREE_CODE (decl) == PARM_DECL
|
|
&& TREE_CODE (TREE_TYPE (decl)) == POINTER_TYPE
|
|
&& TREE_CODE (TREE_TYPE (TREE_TYPE (decl))) == FUNCTION_TYPE)
|
|
return OMP_CLAUSE_DEFAULT_FIRSTPRIVATE;
|
|
|
|
/* COMMON and EQUIVALENCE decls are shared. They
|
|
are only referenced through DECL_VALUE_EXPR of the variables
|
|
contained in them. If those are privatized, they will not be
|
|
gimplified to the COMMON or EQUIVALENCE decls. */
|
|
if (GFC_DECL_COMMON_OR_EQUIV (decl) && ! DECL_HAS_VALUE_EXPR_P (decl))
|
|
return OMP_CLAUSE_DEFAULT_SHARED;
|
|
|
|
if (GFC_DECL_RESULT (decl) && ! DECL_HAS_VALUE_EXPR_P (decl))
|
|
return OMP_CLAUSE_DEFAULT_SHARED;
|
|
|
|
return OMP_CLAUSE_DEFAULT_UNSPECIFIED;
|
|
}
|
|
|
|
/* Return decl that should be used when reporting DEFAULT(NONE)
|
|
diagnostics. */
|
|
|
|
tree
|
|
gfc_omp_report_decl (tree decl)
|
|
{
|
|
if (DECL_ARTIFICIAL (decl)
|
|
&& DECL_LANG_SPECIFIC (decl)
|
|
&& GFC_DECL_SAVED_DESCRIPTOR (decl))
|
|
return GFC_DECL_SAVED_DESCRIPTOR (decl);
|
|
|
|
return decl;
|
|
}
|
|
|
|
/* Return true if DECL in private clause needs
|
|
OMP_CLAUSE_PRIVATE_OUTER_REF on the private clause. */
|
|
bool
|
|
gfc_omp_private_outer_ref (tree decl)
|
|
{
|
|
tree type = TREE_TYPE (decl);
|
|
|
|
if (GFC_DESCRIPTOR_TYPE_P (type)
|
|
&& GFC_TYPE_ARRAY_AKIND (type) == GFC_ARRAY_ALLOCATABLE)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
/* Return code to initialize DECL with its default constructor, or
|
|
NULL if there's nothing to do. */
|
|
|
|
tree
|
|
gfc_omp_clause_default_ctor (tree clause, tree decl, tree outer)
|
|
{
|
|
tree type = TREE_TYPE (decl), rank, size, esize, ptr, cond, then_b, else_b;
|
|
stmtblock_t block, cond_block;
|
|
|
|
if (! GFC_DESCRIPTOR_TYPE_P (type)
|
|
|| GFC_TYPE_ARRAY_AKIND (type) != GFC_ARRAY_ALLOCATABLE)
|
|
return NULL;
|
|
|
|
if (OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_REDUCTION)
|
|
return NULL;
|
|
|
|
gcc_assert (outer != NULL);
|
|
gcc_assert (OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_PRIVATE
|
|
|| OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_LASTPRIVATE);
|
|
|
|
/* Allocatable arrays in PRIVATE clauses need to be set to
|
|
"not currently allocated" allocation status if outer
|
|
array is "not currently allocated", otherwise should be allocated. */
|
|
gfc_start_block (&block);
|
|
|
|
gfc_init_block (&cond_block);
|
|
|
|
gfc_add_modify (&cond_block, decl, outer);
|
|
rank = gfc_rank_cst[GFC_TYPE_ARRAY_RANK (type) - 1];
|
|
size = gfc_conv_descriptor_ubound_get (decl, rank);
|
|
size = fold_build2_loc (input_location, MINUS_EXPR, gfc_array_index_type,
|
|
size, gfc_conv_descriptor_lbound_get (decl, rank));
|
|
size = fold_build2_loc (input_location, PLUS_EXPR, gfc_array_index_type,
|
|
size, gfc_index_one_node);
|
|
if (GFC_TYPE_ARRAY_RANK (type) > 1)
|
|
size = fold_build2_loc (input_location, MULT_EXPR, gfc_array_index_type,
|
|
size, gfc_conv_descriptor_stride_get (decl, rank));
|
|
esize = fold_convert (gfc_array_index_type,
|
|
TYPE_SIZE_UNIT (gfc_get_element_type (type)));
|
|
size = fold_build2_loc (input_location, MULT_EXPR, gfc_array_index_type,
|
|
size, esize);
|
|
size = gfc_evaluate_now (fold_convert (size_type_node, size), &cond_block);
|
|
|
|
ptr = gfc_create_var (pvoid_type_node, NULL);
|
|
gfc_allocate_using_malloc (&cond_block, ptr, size, NULL_TREE);
|
|
gfc_conv_descriptor_data_set (&cond_block, decl, ptr);
|
|
|
|
then_b = gfc_finish_block (&cond_block);
|
|
|
|
gfc_init_block (&cond_block);
|
|
gfc_conv_descriptor_data_set (&cond_block, decl, null_pointer_node);
|
|
else_b = gfc_finish_block (&cond_block);
|
|
|
|
cond = fold_build2_loc (input_location, NE_EXPR, boolean_type_node,
|
|
fold_convert (pvoid_type_node,
|
|
gfc_conv_descriptor_data_get (outer)),
|
|
null_pointer_node);
|
|
gfc_add_expr_to_block (&block, build3_loc (input_location, COND_EXPR,
|
|
void_type_node, cond, then_b, else_b));
|
|
|
|
return gfc_finish_block (&block);
|
|
}
|
|
|
|
/* Build and return code for a copy constructor from SRC to DEST. */
|
|
|
|
tree
|
|
gfc_omp_clause_copy_ctor (tree clause, tree dest, tree src)
|
|
{
|
|
tree type = TREE_TYPE (dest), ptr, size, esize, rank, call;
|
|
tree cond, then_b, else_b;
|
|
stmtblock_t block, cond_block;
|
|
|
|
if (! GFC_DESCRIPTOR_TYPE_P (type)
|
|
|| GFC_TYPE_ARRAY_AKIND (type) != GFC_ARRAY_ALLOCATABLE)
|
|
return build2_v (MODIFY_EXPR, dest, src);
|
|
|
|
gcc_assert (OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_FIRSTPRIVATE);
|
|
|
|
/* Allocatable arrays in FIRSTPRIVATE clauses need to be allocated
|
|
and copied from SRC. */
|
|
gfc_start_block (&block);
|
|
|
|
gfc_init_block (&cond_block);
|
|
|
|
gfc_add_modify (&cond_block, dest, src);
|
|
rank = gfc_rank_cst[GFC_TYPE_ARRAY_RANK (type) - 1];
|
|
size = gfc_conv_descriptor_ubound_get (dest, rank);
|
|
size = fold_build2_loc (input_location, MINUS_EXPR, gfc_array_index_type,
|
|
size, gfc_conv_descriptor_lbound_get (dest, rank));
|
|
size = fold_build2_loc (input_location, PLUS_EXPR, gfc_array_index_type,
|
|
size, gfc_index_one_node);
|
|
if (GFC_TYPE_ARRAY_RANK (type) > 1)
|
|
size = fold_build2_loc (input_location, MULT_EXPR, gfc_array_index_type,
|
|
size, gfc_conv_descriptor_stride_get (dest, rank));
|
|
esize = fold_convert (gfc_array_index_type,
|
|
TYPE_SIZE_UNIT (gfc_get_element_type (type)));
|
|
size = fold_build2_loc (input_location, MULT_EXPR, gfc_array_index_type,
|
|
size, esize);
|
|
size = gfc_evaluate_now (fold_convert (size_type_node, size), &cond_block);
|
|
|
|
ptr = gfc_create_var (pvoid_type_node, NULL);
|
|
gfc_allocate_using_malloc (&cond_block, ptr, size, NULL_TREE);
|
|
gfc_conv_descriptor_data_set (&cond_block, dest, ptr);
|
|
|
|
call = build_call_expr_loc (input_location,
|
|
builtin_decl_explicit (BUILT_IN_MEMCPY),
|
|
3, ptr,
|
|
fold_convert (pvoid_type_node,
|
|
gfc_conv_descriptor_data_get (src)),
|
|
size);
|
|
gfc_add_expr_to_block (&cond_block, fold_convert (void_type_node, call));
|
|
then_b = gfc_finish_block (&cond_block);
|
|
|
|
gfc_init_block (&cond_block);
|
|
gfc_conv_descriptor_data_set (&cond_block, dest, null_pointer_node);
|
|
else_b = gfc_finish_block (&cond_block);
|
|
|
|
cond = fold_build2_loc (input_location, NE_EXPR, boolean_type_node,
|
|
fold_convert (pvoid_type_node,
|
|
gfc_conv_descriptor_data_get (src)),
|
|
null_pointer_node);
|
|
gfc_add_expr_to_block (&block, build3_loc (input_location, COND_EXPR,
|
|
void_type_node, cond, then_b, else_b));
|
|
|
|
return gfc_finish_block (&block);
|
|
}
|
|
|
|
/* Similarly, except use an assignment operator instead. */
|
|
|
|
tree
|
|
gfc_omp_clause_assign_op (tree clause ATTRIBUTE_UNUSED, tree dest, tree src)
|
|
{
|
|
tree type = TREE_TYPE (dest), rank, size, esize, call;
|
|
stmtblock_t block;
|
|
|
|
if (! GFC_DESCRIPTOR_TYPE_P (type)
|
|
|| GFC_TYPE_ARRAY_AKIND (type) != GFC_ARRAY_ALLOCATABLE)
|
|
return build2_v (MODIFY_EXPR, dest, src);
|
|
|
|
/* Handle copying allocatable arrays. */
|
|
gfc_start_block (&block);
|
|
|
|
rank = gfc_rank_cst[GFC_TYPE_ARRAY_RANK (type) - 1];
|
|
size = gfc_conv_descriptor_ubound_get (dest, rank);
|
|
size = fold_build2_loc (input_location, MINUS_EXPR, gfc_array_index_type,
|
|
size, gfc_conv_descriptor_lbound_get (dest, rank));
|
|
size = fold_build2_loc (input_location, PLUS_EXPR, gfc_array_index_type,
|
|
size, gfc_index_one_node);
|
|
if (GFC_TYPE_ARRAY_RANK (type) > 1)
|
|
size = fold_build2_loc (input_location, MULT_EXPR, gfc_array_index_type,
|
|
size, gfc_conv_descriptor_stride_get (dest, rank));
|
|
esize = fold_convert (gfc_array_index_type,
|
|
TYPE_SIZE_UNIT (gfc_get_element_type (type)));
|
|
size = fold_build2_loc (input_location, MULT_EXPR, gfc_array_index_type,
|
|
size, esize);
|
|
size = gfc_evaluate_now (fold_convert (size_type_node, size), &block);
|
|
call = build_call_expr_loc (input_location,
|
|
builtin_decl_explicit (BUILT_IN_MEMCPY), 3,
|
|
fold_convert (pvoid_type_node,
|
|
gfc_conv_descriptor_data_get (dest)),
|
|
fold_convert (pvoid_type_node,
|
|
gfc_conv_descriptor_data_get (src)),
|
|
size);
|
|
gfc_add_expr_to_block (&block, fold_convert (void_type_node, call));
|
|
|
|
return gfc_finish_block (&block);
|
|
}
|
|
|
|
/* Build and return code destructing DECL. Return NULL if nothing
|
|
to be done. */
|
|
|
|
tree
|
|
gfc_omp_clause_dtor (tree clause ATTRIBUTE_UNUSED, tree decl)
|
|
{
|
|
tree type = TREE_TYPE (decl);
|
|
|
|
if (! GFC_DESCRIPTOR_TYPE_P (type)
|
|
|| GFC_TYPE_ARRAY_AKIND (type) != GFC_ARRAY_ALLOCATABLE)
|
|
return NULL;
|
|
|
|
if (OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_REDUCTION)
|
|
return NULL;
|
|
|
|
/* Allocatable arrays in FIRSTPRIVATE/LASTPRIVATE etc. clauses need
|
|
to be deallocated if they were allocated. */
|
|
return gfc_trans_dealloc_allocated (decl, false, NULL);
|
|
}
|
|
|
|
|
|
/* Return true if DECL's DECL_VALUE_EXPR (if any) should be
|
|
disregarded in OpenMP construct, because it is going to be
|
|
remapped during OpenMP lowering. SHARED is true if DECL
|
|
is going to be shared, false if it is going to be privatized. */
|
|
|
|
bool
|
|
gfc_omp_disregard_value_expr (tree decl, bool shared)
|
|
{
|
|
if (GFC_DECL_COMMON_OR_EQUIV (decl)
|
|
&& DECL_HAS_VALUE_EXPR_P (decl))
|
|
{
|
|
tree value = DECL_VALUE_EXPR (decl);
|
|
|
|
if (TREE_CODE (value) == COMPONENT_REF
|
|
&& TREE_CODE (TREE_OPERAND (value, 0)) == VAR_DECL
|
|
&& GFC_DECL_COMMON_OR_EQUIV (TREE_OPERAND (value, 0)))
|
|
{
|
|
/* If variable in COMMON or EQUIVALENCE is privatized, return
|
|
true, as just that variable is supposed to be privatized,
|
|
not the whole COMMON or whole EQUIVALENCE.
|
|
For shared variables in COMMON or EQUIVALENCE, let them be
|
|
gimplified to DECL_VALUE_EXPR, so that for multiple shared vars
|
|
from the same COMMON or EQUIVALENCE just one sharing of the
|
|
whole COMMON or EQUIVALENCE is enough. */
|
|
return ! shared;
|
|
}
|
|
}
|
|
|
|
if (GFC_DECL_RESULT (decl) && DECL_HAS_VALUE_EXPR_P (decl))
|
|
return ! shared;
|
|
|
|
return false;
|
|
}
|
|
|
|
/* Return true if DECL that is shared iff SHARED is true should
|
|
be put into OMP_CLAUSE_PRIVATE with OMP_CLAUSE_PRIVATE_DEBUG
|
|
flag set. */
|
|
|
|
bool
|
|
gfc_omp_private_debug_clause (tree decl, bool shared)
|
|
{
|
|
if (GFC_DECL_CRAY_POINTEE (decl))
|
|
return true;
|
|
|
|
if (GFC_DECL_COMMON_OR_EQUIV (decl)
|
|
&& DECL_HAS_VALUE_EXPR_P (decl))
|
|
{
|
|
tree value = DECL_VALUE_EXPR (decl);
|
|
|
|
if (TREE_CODE (value) == COMPONENT_REF
|
|
&& TREE_CODE (TREE_OPERAND (value, 0)) == VAR_DECL
|
|
&& GFC_DECL_COMMON_OR_EQUIV (TREE_OPERAND (value, 0)))
|
|
return shared;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/* Register language specific type size variables as potentially OpenMP
|
|
firstprivate variables. */
|
|
|
|
void
|
|
gfc_omp_firstprivatize_type_sizes (struct gimplify_omp_ctx *ctx, tree type)
|
|
{
|
|
if (GFC_ARRAY_TYPE_P (type) || GFC_DESCRIPTOR_TYPE_P (type))
|
|
{
|
|
int r;
|
|
|
|
gcc_assert (TYPE_LANG_SPECIFIC (type) != NULL);
|
|
for (r = 0; r < GFC_TYPE_ARRAY_RANK (type); r++)
|
|
{
|
|
omp_firstprivatize_variable (ctx, GFC_TYPE_ARRAY_LBOUND (type, r));
|
|
omp_firstprivatize_variable (ctx, GFC_TYPE_ARRAY_UBOUND (type, r));
|
|
omp_firstprivatize_variable (ctx, GFC_TYPE_ARRAY_STRIDE (type, r));
|
|
}
|
|
omp_firstprivatize_variable (ctx, GFC_TYPE_ARRAY_SIZE (type));
|
|
omp_firstprivatize_variable (ctx, GFC_TYPE_ARRAY_OFFSET (type));
|
|
}
|
|
}
|
|
|
|
|
|
static inline tree
|
|
gfc_trans_add_clause (tree node, tree tail)
|
|
{
|
|
OMP_CLAUSE_CHAIN (node) = tail;
|
|
return node;
|
|
}
|
|
|
|
static tree
|
|
gfc_trans_omp_variable (gfc_symbol *sym)
|
|
{
|
|
tree t = gfc_get_symbol_decl (sym);
|
|
tree parent_decl;
|
|
int parent_flag;
|
|
bool return_value;
|
|
bool alternate_entry;
|
|
bool entry_master;
|
|
|
|
return_value = sym->attr.function && sym->result == sym;
|
|
alternate_entry = sym->attr.function && sym->attr.entry
|
|
&& sym->result == sym;
|
|
entry_master = sym->attr.result
|
|
&& sym->ns->proc_name->attr.entry_master
|
|
&& !gfc_return_by_reference (sym->ns->proc_name);
|
|
parent_decl = DECL_CONTEXT (current_function_decl);
|
|
|
|
if ((t == parent_decl && return_value)
|
|
|| (sym->ns && sym->ns->proc_name
|
|
&& sym->ns->proc_name->backend_decl == parent_decl
|
|
&& (alternate_entry || entry_master)))
|
|
parent_flag = 1;
|
|
else
|
|
parent_flag = 0;
|
|
|
|
/* Special case for assigning the return value of a function.
|
|
Self recursive functions must have an explicit return value. */
|
|
if (return_value && (t == current_function_decl || parent_flag))
|
|
t = gfc_get_fake_result_decl (sym, parent_flag);
|
|
|
|
/* Similarly for alternate entry points. */
|
|
else if (alternate_entry
|
|
&& (sym->ns->proc_name->backend_decl == current_function_decl
|
|
|| parent_flag))
|
|
{
|
|
gfc_entry_list *el = NULL;
|
|
|
|
for (el = sym->ns->entries; el; el = el->next)
|
|
if (sym == el->sym)
|
|
{
|
|
t = gfc_get_fake_result_decl (sym, parent_flag);
|
|
break;
|
|
}
|
|
}
|
|
|
|
else if (entry_master
|
|
&& (sym->ns->proc_name->backend_decl == current_function_decl
|
|
|| parent_flag))
|
|
t = gfc_get_fake_result_decl (sym, parent_flag);
|
|
|
|
return t;
|
|
}
|
|
|
|
static tree
|
|
gfc_trans_omp_variable_list (enum omp_clause_code code, gfc_namelist *namelist,
|
|
tree list)
|
|
{
|
|
for (; namelist != NULL; namelist = namelist->next)
|
|
if (namelist->sym->attr.referenced)
|
|
{
|
|
tree t = gfc_trans_omp_variable (namelist->sym);
|
|
if (t != error_mark_node)
|
|
{
|
|
tree node = build_omp_clause (input_location, code);
|
|
OMP_CLAUSE_DECL (node) = t;
|
|
list = gfc_trans_add_clause (node, list);
|
|
}
|
|
}
|
|
return list;
|
|
}
|
|
|
|
static void
|
|
gfc_trans_omp_array_reduction (tree c, gfc_symbol *sym, locus where)
|
|
{
|
|
gfc_symtree *root1 = NULL, *root2 = NULL, *root3 = NULL, *root4 = NULL;
|
|
gfc_symtree *symtree1, *symtree2, *symtree3, *symtree4 = NULL;
|
|
gfc_symbol init_val_sym, outer_sym, intrinsic_sym;
|
|
gfc_expr *e1, *e2, *e3, *e4;
|
|
gfc_ref *ref;
|
|
tree decl, backend_decl, stmt, type, outer_decl;
|
|
locus old_loc = gfc_current_locus;
|
|
const char *iname;
|
|
bool t;
|
|
|
|
decl = OMP_CLAUSE_DECL (c);
|
|
gfc_current_locus = where;
|
|
type = TREE_TYPE (decl);
|
|
outer_decl = create_tmp_var_raw (type, NULL);
|
|
if (TREE_CODE (decl) == PARM_DECL
|
|
&& TREE_CODE (type) == REFERENCE_TYPE
|
|
&& GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (type))
|
|
&& GFC_TYPE_ARRAY_AKIND (TREE_TYPE (type)) == GFC_ARRAY_ALLOCATABLE)
|
|
{
|
|
decl = build_fold_indirect_ref (decl);
|
|
type = TREE_TYPE (type);
|
|
}
|
|
|
|
/* Create a fake symbol for init value. */
|
|
memset (&init_val_sym, 0, sizeof (init_val_sym));
|
|
init_val_sym.ns = sym->ns;
|
|
init_val_sym.name = sym->name;
|
|
init_val_sym.ts = sym->ts;
|
|
init_val_sym.attr.referenced = 1;
|
|
init_val_sym.declared_at = where;
|
|
init_val_sym.attr.flavor = FL_VARIABLE;
|
|
backend_decl = omp_reduction_init (c, gfc_sym_type (&init_val_sym));
|
|
init_val_sym.backend_decl = backend_decl;
|
|
|
|
/* Create a fake symbol for the outer array reference. */
|
|
outer_sym = *sym;
|
|
outer_sym.as = gfc_copy_array_spec (sym->as);
|
|
outer_sym.attr.dummy = 0;
|
|
outer_sym.attr.result = 0;
|
|
outer_sym.attr.flavor = FL_VARIABLE;
|
|
outer_sym.backend_decl = outer_decl;
|
|
if (decl != OMP_CLAUSE_DECL (c))
|
|
outer_sym.backend_decl = build_fold_indirect_ref (outer_decl);
|
|
|
|
/* Create fake symtrees for it. */
|
|
symtree1 = gfc_new_symtree (&root1, sym->name);
|
|
symtree1->n.sym = sym;
|
|
gcc_assert (symtree1 == root1);
|
|
|
|
symtree2 = gfc_new_symtree (&root2, sym->name);
|
|
symtree2->n.sym = &init_val_sym;
|
|
gcc_assert (symtree2 == root2);
|
|
|
|
symtree3 = gfc_new_symtree (&root3, sym->name);
|
|
symtree3->n.sym = &outer_sym;
|
|
gcc_assert (symtree3 == root3);
|
|
|
|
/* Create expressions. */
|
|
e1 = gfc_get_expr ();
|
|
e1->expr_type = EXPR_VARIABLE;
|
|
e1->where = where;
|
|
e1->symtree = symtree1;
|
|
e1->ts = sym->ts;
|
|
e1->ref = ref = gfc_get_ref ();
|
|
ref->type = REF_ARRAY;
|
|
ref->u.ar.where = where;
|
|
ref->u.ar.as = sym->as;
|
|
ref->u.ar.type = AR_FULL;
|
|
ref->u.ar.dimen = 0;
|
|
t = gfc_resolve_expr (e1);
|
|
gcc_assert (t);
|
|
|
|
e2 = gfc_get_expr ();
|
|
e2->expr_type = EXPR_VARIABLE;
|
|
e2->where = where;
|
|
e2->symtree = symtree2;
|
|
e2->ts = sym->ts;
|
|
t = gfc_resolve_expr (e2);
|
|
gcc_assert (t);
|
|
|
|
e3 = gfc_copy_expr (e1);
|
|
e3->symtree = symtree3;
|
|
t = gfc_resolve_expr (e3);
|
|
gcc_assert (t);
|
|
|
|
iname = NULL;
|
|
switch (OMP_CLAUSE_REDUCTION_CODE (c))
|
|
{
|
|
case PLUS_EXPR:
|
|
case MINUS_EXPR:
|
|
e4 = gfc_add (e3, e1);
|
|
break;
|
|
case MULT_EXPR:
|
|
e4 = gfc_multiply (e3, e1);
|
|
break;
|
|
case TRUTH_ANDIF_EXPR:
|
|
e4 = gfc_and (e3, e1);
|
|
break;
|
|
case TRUTH_ORIF_EXPR:
|
|
e4 = gfc_or (e3, e1);
|
|
break;
|
|
case EQ_EXPR:
|
|
e4 = gfc_eqv (e3, e1);
|
|
break;
|
|
case NE_EXPR:
|
|
e4 = gfc_neqv (e3, e1);
|
|
break;
|
|
case MIN_EXPR:
|
|
iname = "min";
|
|
break;
|
|
case MAX_EXPR:
|
|
iname = "max";
|
|
break;
|
|
case BIT_AND_EXPR:
|
|
iname = "iand";
|
|
break;
|
|
case BIT_IOR_EXPR:
|
|
iname = "ior";
|
|
break;
|
|
case BIT_XOR_EXPR:
|
|
iname = "ieor";
|
|
break;
|
|
default:
|
|
gcc_unreachable ();
|
|
}
|
|
if (iname != NULL)
|
|
{
|
|
memset (&intrinsic_sym, 0, sizeof (intrinsic_sym));
|
|
intrinsic_sym.ns = sym->ns;
|
|
intrinsic_sym.name = iname;
|
|
intrinsic_sym.ts = sym->ts;
|
|
intrinsic_sym.attr.referenced = 1;
|
|
intrinsic_sym.attr.intrinsic = 1;
|
|
intrinsic_sym.attr.function = 1;
|
|
intrinsic_sym.result = &intrinsic_sym;
|
|
intrinsic_sym.declared_at = where;
|
|
|
|
symtree4 = gfc_new_symtree (&root4, iname);
|
|
symtree4->n.sym = &intrinsic_sym;
|
|
gcc_assert (symtree4 == root4);
|
|
|
|
e4 = gfc_get_expr ();
|
|
e4->expr_type = EXPR_FUNCTION;
|
|
e4->where = where;
|
|
e4->symtree = symtree4;
|
|
e4->value.function.isym = gfc_find_function (iname);
|
|
e4->value.function.actual = gfc_get_actual_arglist ();
|
|
e4->value.function.actual->expr = e3;
|
|
e4->value.function.actual->next = gfc_get_actual_arglist ();
|
|
e4->value.function.actual->next->expr = e1;
|
|
}
|
|
/* e1 and e3 have been stored as arguments of e4, avoid sharing. */
|
|
e1 = gfc_copy_expr (e1);
|
|
e3 = gfc_copy_expr (e3);
|
|
t = gfc_resolve_expr (e4);
|
|
gcc_assert (t);
|
|
|
|
/* Create the init statement list. */
|
|
pushlevel ();
|
|
if (GFC_DESCRIPTOR_TYPE_P (type)
|
|
&& GFC_TYPE_ARRAY_AKIND (type) == GFC_ARRAY_ALLOCATABLE)
|
|
{
|
|
/* If decl is an allocatable array, it needs to be allocated
|
|
with the same bounds as the outer var. */
|
|
tree rank, size, esize, ptr;
|
|
stmtblock_t block;
|
|
|
|
gfc_start_block (&block);
|
|
|
|
gfc_add_modify (&block, decl, outer_sym.backend_decl);
|
|
rank = gfc_rank_cst[GFC_TYPE_ARRAY_RANK (type) - 1];
|
|
size = gfc_conv_descriptor_ubound_get (decl, rank);
|
|
size = fold_build2_loc (input_location, MINUS_EXPR,
|
|
gfc_array_index_type, size,
|
|
gfc_conv_descriptor_lbound_get (decl, rank));
|
|
size = fold_build2_loc (input_location, PLUS_EXPR, gfc_array_index_type,
|
|
size, gfc_index_one_node);
|
|
if (GFC_TYPE_ARRAY_RANK (type) > 1)
|
|
size = fold_build2_loc (input_location, MULT_EXPR,
|
|
gfc_array_index_type, size,
|
|
gfc_conv_descriptor_stride_get (decl, rank));
|
|
esize = fold_convert (gfc_array_index_type,
|
|
TYPE_SIZE_UNIT (gfc_get_element_type (type)));
|
|
size = fold_build2_loc (input_location, MULT_EXPR, gfc_array_index_type,
|
|
size, esize);
|
|
size = gfc_evaluate_now (fold_convert (size_type_node, size), &block);
|
|
|
|
ptr = gfc_create_var (pvoid_type_node, NULL);
|
|
gfc_allocate_using_malloc (&block, ptr, size, NULL_TREE);
|
|
gfc_conv_descriptor_data_set (&block, decl, ptr);
|
|
|
|
gfc_add_expr_to_block (&block, gfc_trans_assignment (e1, e2, false,
|
|
false));
|
|
stmt = gfc_finish_block (&block);
|
|
}
|
|
else
|
|
stmt = gfc_trans_assignment (e1, e2, false, false);
|
|
if (TREE_CODE (stmt) != BIND_EXPR)
|
|
stmt = build3_v (BIND_EXPR, NULL, stmt, poplevel (1, 0));
|
|
else
|
|
poplevel (0, 0);
|
|
OMP_CLAUSE_REDUCTION_INIT (c) = stmt;
|
|
|
|
/* Create the merge statement list. */
|
|
pushlevel ();
|
|
if (GFC_DESCRIPTOR_TYPE_P (type)
|
|
&& GFC_TYPE_ARRAY_AKIND (type) == GFC_ARRAY_ALLOCATABLE)
|
|
{
|
|
/* If decl is an allocatable array, it needs to be deallocated
|
|
afterwards. */
|
|
stmtblock_t block;
|
|
|
|
gfc_start_block (&block);
|
|
gfc_add_expr_to_block (&block, gfc_trans_assignment (e3, e4, false,
|
|
true));
|
|
gfc_add_expr_to_block (&block, gfc_trans_dealloc_allocated (decl, false,
|
|
NULL));
|
|
stmt = gfc_finish_block (&block);
|
|
}
|
|
else
|
|
stmt = gfc_trans_assignment (e3, e4, false, true);
|
|
if (TREE_CODE (stmt) != BIND_EXPR)
|
|
stmt = build3_v (BIND_EXPR, NULL, stmt, poplevel (1, 0));
|
|
else
|
|
poplevel (0, 0);
|
|
OMP_CLAUSE_REDUCTION_MERGE (c) = stmt;
|
|
|
|
/* And stick the placeholder VAR_DECL into the clause as well. */
|
|
OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) = outer_decl;
|
|
|
|
gfc_current_locus = old_loc;
|
|
|
|
gfc_free_expr (e1);
|
|
gfc_free_expr (e2);
|
|
gfc_free_expr (e3);
|
|
gfc_free_expr (e4);
|
|
free (symtree1);
|
|
free (symtree2);
|
|
free (symtree3);
|
|
free (symtree4);
|
|
gfc_free_array_spec (outer_sym.as);
|
|
}
|
|
|
|
static tree
|
|
gfc_trans_omp_reduction_list (gfc_namelist *namelist, tree list,
|
|
enum tree_code reduction_code, locus where)
|
|
{
|
|
for (; namelist != NULL; namelist = namelist->next)
|
|
if (namelist->sym->attr.referenced)
|
|
{
|
|
tree t = gfc_trans_omp_variable (namelist->sym);
|
|
if (t != error_mark_node)
|
|
{
|
|
tree node = build_omp_clause (where.lb->location,
|
|
OMP_CLAUSE_REDUCTION);
|
|
OMP_CLAUSE_DECL (node) = t;
|
|
OMP_CLAUSE_REDUCTION_CODE (node) = reduction_code;
|
|
if (namelist->sym->attr.dimension)
|
|
gfc_trans_omp_array_reduction (node, namelist->sym, where);
|
|
list = gfc_trans_add_clause (node, list);
|
|
}
|
|
}
|
|
return list;
|
|
}
|
|
|
|
static tree
|
|
gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
|
|
locus where)
|
|
{
|
|
tree omp_clauses = NULL_TREE, chunk_size, c;
|
|
int list;
|
|
enum omp_clause_code clause_code;
|
|
gfc_se se;
|
|
|
|
if (clauses == NULL)
|
|
return NULL_TREE;
|
|
|
|
for (list = 0; list < OMP_LIST_NUM; list++)
|
|
{
|
|
gfc_namelist *n = clauses->lists[list];
|
|
|
|
if (n == NULL)
|
|
continue;
|
|
if (list >= OMP_LIST_REDUCTION_FIRST
|
|
&& list <= OMP_LIST_REDUCTION_LAST)
|
|
{
|
|
enum tree_code reduction_code;
|
|
switch (list)
|
|
{
|
|
case OMP_LIST_PLUS:
|
|
reduction_code = PLUS_EXPR;
|
|
break;
|
|
case OMP_LIST_MULT:
|
|
reduction_code = MULT_EXPR;
|
|
break;
|
|
case OMP_LIST_SUB:
|
|
reduction_code = MINUS_EXPR;
|
|
break;
|
|
case OMP_LIST_AND:
|
|
reduction_code = TRUTH_ANDIF_EXPR;
|
|
break;
|
|
case OMP_LIST_OR:
|
|
reduction_code = TRUTH_ORIF_EXPR;
|
|
break;
|
|
case OMP_LIST_EQV:
|
|
reduction_code = EQ_EXPR;
|
|
break;
|
|
case OMP_LIST_NEQV:
|
|
reduction_code = NE_EXPR;
|
|
break;
|
|
case OMP_LIST_MAX:
|
|
reduction_code = MAX_EXPR;
|
|
break;
|
|
case OMP_LIST_MIN:
|
|
reduction_code = MIN_EXPR;
|
|
break;
|
|
case OMP_LIST_IAND:
|
|
reduction_code = BIT_AND_EXPR;
|
|
break;
|
|
case OMP_LIST_IOR:
|
|
reduction_code = BIT_IOR_EXPR;
|
|
break;
|
|
case OMP_LIST_IEOR:
|
|
reduction_code = BIT_XOR_EXPR;
|
|
break;
|
|
default:
|
|
gcc_unreachable ();
|
|
}
|
|
omp_clauses
|
|
= gfc_trans_omp_reduction_list (n, omp_clauses, reduction_code,
|
|
where);
|
|
continue;
|
|
}
|
|
switch (list)
|
|
{
|
|
case OMP_LIST_PRIVATE:
|
|
clause_code = OMP_CLAUSE_PRIVATE;
|
|
goto add_clause;
|
|
case OMP_LIST_SHARED:
|
|
clause_code = OMP_CLAUSE_SHARED;
|
|
goto add_clause;
|
|
case OMP_LIST_FIRSTPRIVATE:
|
|
clause_code = OMP_CLAUSE_FIRSTPRIVATE;
|
|
goto add_clause;
|
|
case OMP_LIST_LASTPRIVATE:
|
|
clause_code = OMP_CLAUSE_LASTPRIVATE;
|
|
goto add_clause;
|
|
case OMP_LIST_COPYIN:
|
|
clause_code = OMP_CLAUSE_COPYIN;
|
|
goto add_clause;
|
|
case OMP_LIST_COPYPRIVATE:
|
|
clause_code = OMP_CLAUSE_COPYPRIVATE;
|
|
/* FALLTHROUGH */
|
|
add_clause:
|
|
omp_clauses
|
|
= gfc_trans_omp_variable_list (clause_code, n, omp_clauses);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (clauses->if_expr)
|
|
{
|
|
tree if_var;
|
|
|
|
gfc_init_se (&se, NULL);
|
|
gfc_conv_expr (&se, clauses->if_expr);
|
|
gfc_add_block_to_block (block, &se.pre);
|
|
if_var = gfc_evaluate_now (se.expr, block);
|
|
gfc_add_block_to_block (block, &se.post);
|
|
|
|
c = build_omp_clause (where.lb->location, OMP_CLAUSE_IF);
|
|
OMP_CLAUSE_IF_EXPR (c) = if_var;
|
|
omp_clauses = gfc_trans_add_clause (c, omp_clauses);
|
|
}
|
|
|
|
if (clauses->final_expr)
|
|
{
|
|
tree final_var;
|
|
|
|
gfc_init_se (&se, NULL);
|
|
gfc_conv_expr (&se, clauses->final_expr);
|
|
gfc_add_block_to_block (block, &se.pre);
|
|
final_var = gfc_evaluate_now (se.expr, block);
|
|
gfc_add_block_to_block (block, &se.post);
|
|
|
|
c = build_omp_clause (where.lb->location, OMP_CLAUSE_FINAL);
|
|
OMP_CLAUSE_FINAL_EXPR (c) = final_var;
|
|
omp_clauses = gfc_trans_add_clause (c, omp_clauses);
|
|
}
|
|
|
|
if (clauses->num_threads)
|
|
{
|
|
tree num_threads;
|
|
|
|
gfc_init_se (&se, NULL);
|
|
gfc_conv_expr (&se, clauses->num_threads);
|
|
gfc_add_block_to_block (block, &se.pre);
|
|
num_threads = gfc_evaluate_now (se.expr, block);
|
|
gfc_add_block_to_block (block, &se.post);
|
|
|
|
c = build_omp_clause (where.lb->location, OMP_CLAUSE_NUM_THREADS);
|
|
OMP_CLAUSE_NUM_THREADS_EXPR (c) = num_threads;
|
|
omp_clauses = gfc_trans_add_clause (c, omp_clauses);
|
|
}
|
|
|
|
chunk_size = NULL_TREE;
|
|
if (clauses->chunk_size)
|
|
{
|
|
gfc_init_se (&se, NULL);
|
|
gfc_conv_expr (&se, clauses->chunk_size);
|
|
gfc_add_block_to_block (block, &se.pre);
|
|
chunk_size = gfc_evaluate_now (se.expr, block);
|
|
gfc_add_block_to_block (block, &se.post);
|
|
}
|
|
|
|
if (clauses->sched_kind != OMP_SCHED_NONE)
|
|
{
|
|
c = build_omp_clause (where.lb->location, OMP_CLAUSE_SCHEDULE);
|
|
OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (c) = chunk_size;
|
|
switch (clauses->sched_kind)
|
|
{
|
|
case OMP_SCHED_STATIC:
|
|
OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_STATIC;
|
|
break;
|
|
case OMP_SCHED_DYNAMIC:
|
|
OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_DYNAMIC;
|
|
break;
|
|
case OMP_SCHED_GUIDED:
|
|
OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_GUIDED;
|
|
break;
|
|
case OMP_SCHED_RUNTIME:
|
|
OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_RUNTIME;
|
|
break;
|
|
case OMP_SCHED_AUTO:
|
|
OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_AUTO;
|
|
break;
|
|
default:
|
|
gcc_unreachable ();
|
|
}
|
|
omp_clauses = gfc_trans_add_clause (c, omp_clauses);
|
|
}
|
|
|
|
if (clauses->default_sharing != OMP_DEFAULT_UNKNOWN)
|
|
{
|
|
c = build_omp_clause (where.lb->location, OMP_CLAUSE_DEFAULT);
|
|
switch (clauses->default_sharing)
|
|
{
|
|
case OMP_DEFAULT_NONE:
|
|
OMP_CLAUSE_DEFAULT_KIND (c) = OMP_CLAUSE_DEFAULT_NONE;
|
|
break;
|
|
case OMP_DEFAULT_SHARED:
|
|
OMP_CLAUSE_DEFAULT_KIND (c) = OMP_CLAUSE_DEFAULT_SHARED;
|
|
break;
|
|
case OMP_DEFAULT_PRIVATE:
|
|
OMP_CLAUSE_DEFAULT_KIND (c) = OMP_CLAUSE_DEFAULT_PRIVATE;
|
|
break;
|
|
case OMP_DEFAULT_FIRSTPRIVATE:
|
|
OMP_CLAUSE_DEFAULT_KIND (c) = OMP_CLAUSE_DEFAULT_FIRSTPRIVATE;
|
|
break;
|
|
default:
|
|
gcc_unreachable ();
|
|
}
|
|
omp_clauses = gfc_trans_add_clause (c, omp_clauses);
|
|
}
|
|
|
|
if (clauses->nowait)
|
|
{
|
|
c = build_omp_clause (where.lb->location, OMP_CLAUSE_NOWAIT);
|
|
omp_clauses = gfc_trans_add_clause (c, omp_clauses);
|
|
}
|
|
|
|
if (clauses->ordered)
|
|
{
|
|
c = build_omp_clause (where.lb->location, OMP_CLAUSE_ORDERED);
|
|
omp_clauses = gfc_trans_add_clause (c, omp_clauses);
|
|
}
|
|
|
|
if (clauses->untied)
|
|
{
|
|
c = build_omp_clause (where.lb->location, OMP_CLAUSE_UNTIED);
|
|
omp_clauses = gfc_trans_add_clause (c, omp_clauses);
|
|
}
|
|
|
|
if (clauses->mergeable)
|
|
{
|
|
c = build_omp_clause (where.lb->location, OMP_CLAUSE_MERGEABLE);
|
|
omp_clauses = gfc_trans_add_clause (c, omp_clauses);
|
|
}
|
|
|
|
if (clauses->collapse)
|
|
{
|
|
c = build_omp_clause (where.lb->location, OMP_CLAUSE_COLLAPSE);
|
|
OMP_CLAUSE_COLLAPSE_EXPR (c)
|
|
= build_int_cst (integer_type_node, clauses->collapse);
|
|
omp_clauses = gfc_trans_add_clause (c, omp_clauses);
|
|
}
|
|
|
|
return omp_clauses;
|
|
}
|
|
|
|
/* Like gfc_trans_code, but force creation of a BIND_EXPR around it. */
|
|
|
|
static tree
|
|
gfc_trans_omp_code (gfc_code *code, bool force_empty)
|
|
{
|
|
tree stmt;
|
|
|
|
pushlevel ();
|
|
stmt = gfc_trans_code (code);
|
|
if (TREE_CODE (stmt) != BIND_EXPR)
|
|
{
|
|
if (!IS_EMPTY_STMT (stmt) || force_empty)
|
|
{
|
|
tree block = poplevel (1, 0);
|
|
stmt = build3_v (BIND_EXPR, NULL, stmt, block);
|
|
}
|
|
else
|
|
poplevel (0, 0);
|
|
}
|
|
else
|
|
poplevel (0, 0);
|
|
return stmt;
|
|
}
|
|
|
|
|
|
static tree gfc_trans_omp_sections (gfc_code *, gfc_omp_clauses *);
|
|
static tree gfc_trans_omp_workshare (gfc_code *, gfc_omp_clauses *);
|
|
|
|
static tree
|
|
gfc_trans_omp_atomic (gfc_code *code)
|
|
{
|
|
gfc_code *atomic_code = code;
|
|
gfc_se lse;
|
|
gfc_se rse;
|
|
gfc_se vse;
|
|
gfc_expr *expr2, *e;
|
|
gfc_symbol *var;
|
|
stmtblock_t block;
|
|
tree lhsaddr, type, rhs, x;
|
|
enum tree_code op = ERROR_MARK;
|
|
enum tree_code aop = OMP_ATOMIC;
|
|
bool var_on_left = false;
|
|
|
|
code = code->block->next;
|
|
gcc_assert (code->op == EXEC_ASSIGN);
|
|
var = code->expr1->symtree->n.sym;
|
|
|
|
gfc_init_se (&lse, NULL);
|
|
gfc_init_se (&rse, NULL);
|
|
gfc_init_se (&vse, NULL);
|
|
gfc_start_block (&block);
|
|
|
|
expr2 = code->expr2;
|
|
if (expr2->expr_type == EXPR_FUNCTION
|
|
&& expr2->value.function.isym->id == GFC_ISYM_CONVERSION)
|
|
expr2 = expr2->value.function.actual->expr;
|
|
|
|
switch (atomic_code->ext.omp_atomic)
|
|
{
|
|
case GFC_OMP_ATOMIC_READ:
|
|
gfc_conv_expr (&vse, code->expr1);
|
|
gfc_add_block_to_block (&block, &vse.pre);
|
|
|
|
gfc_conv_expr (&lse, expr2);
|
|
gfc_add_block_to_block (&block, &lse.pre);
|
|
type = TREE_TYPE (lse.expr);
|
|
lhsaddr = gfc_build_addr_expr (NULL, lse.expr);
|
|
|
|
x = build1 (OMP_ATOMIC_READ, type, lhsaddr);
|
|
x = convert (TREE_TYPE (vse.expr), x);
|
|
gfc_add_modify (&block, vse.expr, x);
|
|
|
|
gfc_add_block_to_block (&block, &lse.pre);
|
|
gfc_add_block_to_block (&block, &rse.pre);
|
|
|
|
return gfc_finish_block (&block);
|
|
case GFC_OMP_ATOMIC_CAPTURE:
|
|
aop = OMP_ATOMIC_CAPTURE_NEW;
|
|
if (expr2->expr_type == EXPR_VARIABLE)
|
|
{
|
|
aop = OMP_ATOMIC_CAPTURE_OLD;
|
|
gfc_conv_expr (&vse, code->expr1);
|
|
gfc_add_block_to_block (&block, &vse.pre);
|
|
|
|
gfc_conv_expr (&lse, expr2);
|
|
gfc_add_block_to_block (&block, &lse.pre);
|
|
gfc_init_se (&lse, NULL);
|
|
code = code->next;
|
|
var = code->expr1->symtree->n.sym;
|
|
expr2 = code->expr2;
|
|
if (expr2->expr_type == EXPR_FUNCTION
|
|
&& expr2->value.function.isym->id == GFC_ISYM_CONVERSION)
|
|
expr2 = expr2->value.function.actual->expr;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
gfc_conv_expr (&lse, code->expr1);
|
|
gfc_add_block_to_block (&block, &lse.pre);
|
|
type = TREE_TYPE (lse.expr);
|
|
lhsaddr = gfc_build_addr_expr (NULL, lse.expr);
|
|
|
|
if (atomic_code->ext.omp_atomic == GFC_OMP_ATOMIC_WRITE)
|
|
{
|
|
gfc_conv_expr (&rse, expr2);
|
|
gfc_add_block_to_block (&block, &rse.pre);
|
|
}
|
|
else if (expr2->expr_type == EXPR_OP)
|
|
{
|
|
gfc_expr *e;
|
|
switch (expr2->value.op.op)
|
|
{
|
|
case INTRINSIC_PLUS:
|
|
op = PLUS_EXPR;
|
|
break;
|
|
case INTRINSIC_TIMES:
|
|
op = MULT_EXPR;
|
|
break;
|
|
case INTRINSIC_MINUS:
|
|
op = MINUS_EXPR;
|
|
break;
|
|
case INTRINSIC_DIVIDE:
|
|
if (expr2->ts.type == BT_INTEGER)
|
|
op = TRUNC_DIV_EXPR;
|
|
else
|
|
op = RDIV_EXPR;
|
|
break;
|
|
case INTRINSIC_AND:
|
|
op = TRUTH_ANDIF_EXPR;
|
|
break;
|
|
case INTRINSIC_OR:
|
|
op = TRUTH_ORIF_EXPR;
|
|
break;
|
|
case INTRINSIC_EQV:
|
|
op = EQ_EXPR;
|
|
break;
|
|
case INTRINSIC_NEQV:
|
|
op = NE_EXPR;
|
|
break;
|
|
default:
|
|
gcc_unreachable ();
|
|
}
|
|
e = expr2->value.op.op1;
|
|
if (e->expr_type == EXPR_FUNCTION
|
|
&& e->value.function.isym->id == GFC_ISYM_CONVERSION)
|
|
e = e->value.function.actual->expr;
|
|
if (e->expr_type == EXPR_VARIABLE
|
|
&& e->symtree != NULL
|
|
&& e->symtree->n.sym == var)
|
|
{
|
|
expr2 = expr2->value.op.op2;
|
|
var_on_left = true;
|
|
}
|
|
else
|
|
{
|
|
e = expr2->value.op.op2;
|
|
if (e->expr_type == EXPR_FUNCTION
|
|
&& e->value.function.isym->id == GFC_ISYM_CONVERSION)
|
|
e = e->value.function.actual->expr;
|
|
gcc_assert (e->expr_type == EXPR_VARIABLE
|
|
&& e->symtree != NULL
|
|
&& e->symtree->n.sym == var);
|
|
expr2 = expr2->value.op.op1;
|
|
var_on_left = false;
|
|
}
|
|
gfc_conv_expr (&rse, expr2);
|
|
gfc_add_block_to_block (&block, &rse.pre);
|
|
}
|
|
else
|
|
{
|
|
gcc_assert (expr2->expr_type == EXPR_FUNCTION);
|
|
switch (expr2->value.function.isym->id)
|
|
{
|
|
case GFC_ISYM_MIN:
|
|
op = MIN_EXPR;
|
|
break;
|
|
case GFC_ISYM_MAX:
|
|
op = MAX_EXPR;
|
|
break;
|
|
case GFC_ISYM_IAND:
|
|
op = BIT_AND_EXPR;
|
|
break;
|
|
case GFC_ISYM_IOR:
|
|
op = BIT_IOR_EXPR;
|
|
break;
|
|
case GFC_ISYM_IEOR:
|
|
op = BIT_XOR_EXPR;
|
|
break;
|
|
default:
|
|
gcc_unreachable ();
|
|
}
|
|
e = expr2->value.function.actual->expr;
|
|
gcc_assert (e->expr_type == EXPR_VARIABLE
|
|
&& e->symtree != NULL
|
|
&& e->symtree->n.sym == var);
|
|
|
|
gfc_conv_expr (&rse, expr2->value.function.actual->next->expr);
|
|
gfc_add_block_to_block (&block, &rse.pre);
|
|
if (expr2->value.function.actual->next->next != NULL)
|
|
{
|
|
tree accum = gfc_create_var (TREE_TYPE (rse.expr), NULL);
|
|
gfc_actual_arglist *arg;
|
|
|
|
gfc_add_modify (&block, accum, rse.expr);
|
|
for (arg = expr2->value.function.actual->next->next; arg;
|
|
arg = arg->next)
|
|
{
|
|
gfc_init_block (&rse.pre);
|
|
gfc_conv_expr (&rse, arg->expr);
|
|
gfc_add_block_to_block (&block, &rse.pre);
|
|
x = fold_build2_loc (input_location, op, TREE_TYPE (accum),
|
|
accum, rse.expr);
|
|
gfc_add_modify (&block, accum, x);
|
|
}
|
|
|
|
rse.expr = accum;
|
|
}
|
|
|
|
expr2 = expr2->value.function.actual->next->expr;
|
|
}
|
|
|
|
lhsaddr = save_expr (lhsaddr);
|
|
rhs = gfc_evaluate_now (rse.expr, &block);
|
|
|
|
if (atomic_code->ext.omp_atomic == GFC_OMP_ATOMIC_WRITE)
|
|
x = rhs;
|
|
else
|
|
{
|
|
x = convert (TREE_TYPE (rhs),
|
|
build_fold_indirect_ref_loc (input_location, lhsaddr));
|
|
if (var_on_left)
|
|
x = fold_build2_loc (input_location, op, TREE_TYPE (rhs), x, rhs);
|
|
else
|
|
x = fold_build2_loc (input_location, op, TREE_TYPE (rhs), rhs, x);
|
|
}
|
|
|
|
if (TREE_CODE (TREE_TYPE (rhs)) == COMPLEX_TYPE
|
|
&& TREE_CODE (type) != COMPLEX_TYPE)
|
|
x = fold_build1_loc (input_location, REALPART_EXPR,
|
|
TREE_TYPE (TREE_TYPE (rhs)), x);
|
|
|
|
gfc_add_block_to_block (&block, &lse.pre);
|
|
gfc_add_block_to_block (&block, &rse.pre);
|
|
|
|
if (aop == OMP_ATOMIC)
|
|
{
|
|
x = build2_v (OMP_ATOMIC, lhsaddr, convert (type, x));
|
|
gfc_add_expr_to_block (&block, x);
|
|
}
|
|
else
|
|
{
|
|
if (aop == OMP_ATOMIC_CAPTURE_NEW)
|
|
{
|
|
code = code->next;
|
|
expr2 = code->expr2;
|
|
if (expr2->expr_type == EXPR_FUNCTION
|
|
&& expr2->value.function.isym->id == GFC_ISYM_CONVERSION)
|
|
expr2 = expr2->value.function.actual->expr;
|
|
|
|
gcc_assert (expr2->expr_type == EXPR_VARIABLE);
|
|
gfc_conv_expr (&vse, code->expr1);
|
|
gfc_add_block_to_block (&block, &vse.pre);
|
|
|
|
gfc_init_se (&lse, NULL);
|
|
gfc_conv_expr (&lse, expr2);
|
|
gfc_add_block_to_block (&block, &lse.pre);
|
|
}
|
|
x = build2 (aop, type, lhsaddr, convert (type, x));
|
|
x = convert (TREE_TYPE (vse.expr), x);
|
|
gfc_add_modify (&block, vse.expr, x);
|
|
}
|
|
|
|
return gfc_finish_block (&block);
|
|
}
|
|
|
|
static tree
|
|
gfc_trans_omp_barrier (void)
|
|
{
|
|
tree decl = builtin_decl_explicit (BUILT_IN_GOMP_BARRIER);
|
|
return build_call_expr_loc (input_location, decl, 0);
|
|
}
|
|
|
|
static tree
|
|
gfc_trans_omp_critical (gfc_code *code)
|
|
{
|
|
tree name = NULL_TREE, stmt;
|
|
if (code->ext.omp_name != NULL)
|
|
name = get_identifier (code->ext.omp_name);
|
|
stmt = gfc_trans_code (code->block->next);
|
|
return build2_loc (input_location, OMP_CRITICAL, void_type_node, stmt, name);
|
|
}
|
|
|
|
typedef struct dovar_init_d {
|
|
tree var;
|
|
tree init;
|
|
} dovar_init;
|
|
|
|
|
|
static tree
|
|
gfc_trans_omp_do (gfc_code *code, stmtblock_t *pblock,
|
|
gfc_omp_clauses *do_clauses, tree par_clauses)
|
|
{
|
|
gfc_se se;
|
|
tree dovar, stmt, from, to, step, type, init, cond, incr;
|
|
tree count = NULL_TREE, cycle_label, tmp, omp_clauses;
|
|
stmtblock_t block;
|
|
stmtblock_t body;
|
|
gfc_omp_clauses *clauses = code->ext.omp_clauses;
|
|
int i, collapse = clauses->collapse;
|
|
vec<dovar_init> inits = vNULL;
|
|
dovar_init *di;
|
|
unsigned ix;
|
|
|
|
if (collapse <= 0)
|
|
collapse = 1;
|
|
|
|
code = code->block->next;
|
|
gcc_assert (code->op == EXEC_DO);
|
|
|
|
init = make_tree_vec (collapse);
|
|
cond = make_tree_vec (collapse);
|
|
incr = make_tree_vec (collapse);
|
|
|
|
if (pblock == NULL)
|
|
{
|
|
gfc_start_block (&block);
|
|
pblock = █
|
|
}
|
|
|
|
omp_clauses = gfc_trans_omp_clauses (pblock, do_clauses, code->loc);
|
|
|
|
for (i = 0; i < collapse; i++)
|
|
{
|
|
int simple = 0;
|
|
int dovar_found = 0;
|
|
tree dovar_decl;
|
|
|
|
if (clauses)
|
|
{
|
|
gfc_namelist *n;
|
|
for (n = clauses->lists[OMP_LIST_LASTPRIVATE]; n != NULL;
|
|
n = n->next)
|
|
if (code->ext.iterator->var->symtree->n.sym == n->sym)
|
|
break;
|
|
if (n != NULL)
|
|
dovar_found = 1;
|
|
else if (n == NULL)
|
|
for (n = clauses->lists[OMP_LIST_PRIVATE]; n != NULL; n = n->next)
|
|
if (code->ext.iterator->var->symtree->n.sym == n->sym)
|
|
break;
|
|
if (n != NULL)
|
|
dovar_found++;
|
|
}
|
|
|
|
/* Evaluate all the expressions in the iterator. */
|
|
gfc_init_se (&se, NULL);
|
|
gfc_conv_expr_lhs (&se, code->ext.iterator->var);
|
|
gfc_add_block_to_block (pblock, &se.pre);
|
|
dovar = se.expr;
|
|
type = TREE_TYPE (dovar);
|
|
gcc_assert (TREE_CODE (type) == INTEGER_TYPE);
|
|
|
|
gfc_init_se (&se, NULL);
|
|
gfc_conv_expr_val (&se, code->ext.iterator->start);
|
|
gfc_add_block_to_block (pblock, &se.pre);
|
|
from = gfc_evaluate_now (se.expr, pblock);
|
|
|
|
gfc_init_se (&se, NULL);
|
|
gfc_conv_expr_val (&se, code->ext.iterator->end);
|
|
gfc_add_block_to_block (pblock, &se.pre);
|
|
to = gfc_evaluate_now (se.expr, pblock);
|
|
|
|
gfc_init_se (&se, NULL);
|
|
gfc_conv_expr_val (&se, code->ext.iterator->step);
|
|
gfc_add_block_to_block (pblock, &se.pre);
|
|
step = gfc_evaluate_now (se.expr, pblock);
|
|
dovar_decl = dovar;
|
|
|
|
/* Special case simple loops. */
|
|
if (TREE_CODE (dovar) == VAR_DECL)
|
|
{
|
|
if (integer_onep (step))
|
|
simple = 1;
|
|
else if (tree_int_cst_equal (step, integer_minus_one_node))
|
|
simple = -1;
|
|
}
|
|
else
|
|
dovar_decl
|
|
= gfc_trans_omp_variable (code->ext.iterator->var->symtree->n.sym);
|
|
|
|
/* Loop body. */
|
|
if (simple)
|
|
{
|
|
TREE_VEC_ELT (init, i) = build2_v (MODIFY_EXPR, dovar, from);
|
|
/* The condition should not be folded. */
|
|
TREE_VEC_ELT (cond, i) = build2_loc (input_location, simple > 0
|
|
? LE_EXPR : GE_EXPR,
|
|
boolean_type_node, dovar, to);
|
|
TREE_VEC_ELT (incr, i) = fold_build2_loc (input_location, PLUS_EXPR,
|
|
type, dovar, step);
|
|
TREE_VEC_ELT (incr, i) = fold_build2_loc (input_location,
|
|
MODIFY_EXPR,
|
|
type, dovar,
|
|
TREE_VEC_ELT (incr, i));
|
|
}
|
|
else
|
|
{
|
|
/* STEP is not 1 or -1. Use:
|
|
for (count = 0; count < (to + step - from) / step; count++)
|
|
{
|
|
dovar = from + count * step;
|
|
body;
|
|
cycle_label:;
|
|
} */
|
|
tmp = fold_build2_loc (input_location, MINUS_EXPR, type, step, from);
|
|
tmp = fold_build2_loc (input_location, PLUS_EXPR, type, to, tmp);
|
|
tmp = fold_build2_loc (input_location, TRUNC_DIV_EXPR, type, tmp,
|
|
step);
|
|
tmp = gfc_evaluate_now (tmp, pblock);
|
|
count = gfc_create_var (type, "count");
|
|
TREE_VEC_ELT (init, i) = build2_v (MODIFY_EXPR, count,
|
|
build_int_cst (type, 0));
|
|
/* The condition should not be folded. */
|
|
TREE_VEC_ELT (cond, i) = build2_loc (input_location, LT_EXPR,
|
|
boolean_type_node,
|
|
count, tmp);
|
|
TREE_VEC_ELT (incr, i) = fold_build2_loc (input_location, PLUS_EXPR,
|
|
type, count,
|
|
build_int_cst (type, 1));
|
|
TREE_VEC_ELT (incr, i) = fold_build2_loc (input_location,
|
|
MODIFY_EXPR, type, count,
|
|
TREE_VEC_ELT (incr, i));
|
|
|
|
/* Initialize DOVAR. */
|
|
tmp = fold_build2_loc (input_location, MULT_EXPR, type, count, step);
|
|
tmp = fold_build2_loc (input_location, PLUS_EXPR, type, from, tmp);
|
|
dovar_init e = {dovar, tmp};
|
|
inits.safe_push (e);
|
|
}
|
|
|
|
if (!dovar_found)
|
|
{
|
|
tmp = build_omp_clause (input_location, OMP_CLAUSE_PRIVATE);
|
|
OMP_CLAUSE_DECL (tmp) = dovar_decl;
|
|
omp_clauses = gfc_trans_add_clause (tmp, omp_clauses);
|
|
}
|
|
else if (dovar_found == 2)
|
|
{
|
|
tree c = NULL;
|
|
|
|
tmp = NULL;
|
|
if (!simple)
|
|
{
|
|
/* If dovar is lastprivate, but different counter is used,
|
|
dovar += step needs to be added to
|
|
OMP_CLAUSE_LASTPRIVATE_STMT, otherwise the copied dovar
|
|
will have the value on entry of the last loop, rather
|
|
than value after iterator increment. */
|
|
tmp = gfc_evaluate_now (step, pblock);
|
|
tmp = fold_build2_loc (input_location, PLUS_EXPR, type, dovar,
|
|
tmp);
|
|
tmp = fold_build2_loc (input_location, MODIFY_EXPR, type,
|
|
dovar, tmp);
|
|
for (c = omp_clauses; c ; c = OMP_CLAUSE_CHAIN (c))
|
|
if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE
|
|
&& OMP_CLAUSE_DECL (c) == dovar_decl)
|
|
{
|
|
OMP_CLAUSE_LASTPRIVATE_STMT (c) = tmp;
|
|
break;
|
|
}
|
|
}
|
|
if (c == NULL && par_clauses != NULL)
|
|
{
|
|
for (c = par_clauses; c ; c = OMP_CLAUSE_CHAIN (c))
|
|
if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE
|
|
&& OMP_CLAUSE_DECL (c) == dovar_decl)
|
|
{
|
|
tree l = build_omp_clause (input_location,
|
|
OMP_CLAUSE_LASTPRIVATE);
|
|
OMP_CLAUSE_DECL (l) = dovar_decl;
|
|
OMP_CLAUSE_CHAIN (l) = omp_clauses;
|
|
OMP_CLAUSE_LASTPRIVATE_STMT (l) = tmp;
|
|
omp_clauses = l;
|
|
OMP_CLAUSE_SET_CODE (c, OMP_CLAUSE_SHARED);
|
|
break;
|
|
}
|
|
}
|
|
gcc_assert (simple || c != NULL);
|
|
}
|
|
if (!simple)
|
|
{
|
|
tmp = build_omp_clause (input_location, OMP_CLAUSE_PRIVATE);
|
|
OMP_CLAUSE_DECL (tmp) = count;
|
|
omp_clauses = gfc_trans_add_clause (tmp, omp_clauses);
|
|
}
|
|
|
|
if (i + 1 < collapse)
|
|
code = code->block->next;
|
|
}
|
|
|
|
if (pblock != &block)
|
|
{
|
|
pushlevel ();
|
|
gfc_start_block (&block);
|
|
}
|
|
|
|
gfc_start_block (&body);
|
|
|
|
FOR_EACH_VEC_ELT (inits, ix, di)
|
|
gfc_add_modify (&body, di->var, di->init);
|
|
inits.release ();
|
|
|
|
/* Cycle statement is implemented with a goto. Exit statement must not be
|
|
present for this loop. */
|
|
cycle_label = gfc_build_label_decl (NULL_TREE);
|
|
|
|
/* Put these labels where they can be found later. */
|
|
|
|
code->cycle_label = cycle_label;
|
|
code->exit_label = NULL_TREE;
|
|
|
|
/* Main loop body. */
|
|
tmp = gfc_trans_omp_code (code->block->next, true);
|
|
gfc_add_expr_to_block (&body, tmp);
|
|
|
|
/* Label for cycle statements (if needed). */
|
|
if (TREE_USED (cycle_label))
|
|
{
|
|
tmp = build1_v (LABEL_EXPR, cycle_label);
|
|
gfc_add_expr_to_block (&body, tmp);
|
|
}
|
|
|
|
/* End of loop body. */
|
|
stmt = make_node (OMP_FOR);
|
|
|
|
TREE_TYPE (stmt) = void_type_node;
|
|
OMP_FOR_BODY (stmt) = gfc_finish_block (&body);
|
|
OMP_FOR_CLAUSES (stmt) = omp_clauses;
|
|
OMP_FOR_INIT (stmt) = init;
|
|
OMP_FOR_COND (stmt) = cond;
|
|
OMP_FOR_INCR (stmt) = incr;
|
|
gfc_add_expr_to_block (&block, stmt);
|
|
|
|
return gfc_finish_block (&block);
|
|
}
|
|
|
|
static tree
|
|
gfc_trans_omp_flush (void)
|
|
{
|
|
tree decl = builtin_decl_explicit (BUILT_IN_SYNC_SYNCHRONIZE);
|
|
return build_call_expr_loc (input_location, decl, 0);
|
|
}
|
|
|
|
static tree
|
|
gfc_trans_omp_master (gfc_code *code)
|
|
{
|
|
tree stmt = gfc_trans_code (code->block->next);
|
|
if (IS_EMPTY_STMT (stmt))
|
|
return stmt;
|
|
return build1_v (OMP_MASTER, stmt);
|
|
}
|
|
|
|
static tree
|
|
gfc_trans_omp_ordered (gfc_code *code)
|
|
{
|
|
return build1_v (OMP_ORDERED, gfc_trans_code (code->block->next));
|
|
}
|
|
|
|
static tree
|
|
gfc_trans_omp_parallel (gfc_code *code)
|
|
{
|
|
stmtblock_t block;
|
|
tree stmt, omp_clauses;
|
|
|
|
gfc_start_block (&block);
|
|
omp_clauses = gfc_trans_omp_clauses (&block, code->ext.omp_clauses,
|
|
code->loc);
|
|
stmt = gfc_trans_omp_code (code->block->next, true);
|
|
stmt = build2_loc (input_location, OMP_PARALLEL, void_type_node, stmt,
|
|
omp_clauses);
|
|
gfc_add_expr_to_block (&block, stmt);
|
|
return gfc_finish_block (&block);
|
|
}
|
|
|
|
static tree
|
|
gfc_trans_omp_parallel_do (gfc_code *code)
|
|
{
|
|
stmtblock_t block, *pblock = NULL;
|
|
gfc_omp_clauses parallel_clauses, do_clauses;
|
|
tree stmt, omp_clauses = NULL_TREE;
|
|
|
|
gfc_start_block (&block);
|
|
|
|
memset (&do_clauses, 0, sizeof (do_clauses));
|
|
if (code->ext.omp_clauses != NULL)
|
|
{
|
|
memcpy (¶llel_clauses, code->ext.omp_clauses,
|
|
sizeof (parallel_clauses));
|
|
do_clauses.sched_kind = parallel_clauses.sched_kind;
|
|
do_clauses.chunk_size = parallel_clauses.chunk_size;
|
|
do_clauses.ordered = parallel_clauses.ordered;
|
|
do_clauses.collapse = parallel_clauses.collapse;
|
|
parallel_clauses.sched_kind = OMP_SCHED_NONE;
|
|
parallel_clauses.chunk_size = NULL;
|
|
parallel_clauses.ordered = false;
|
|
parallel_clauses.collapse = 0;
|
|
omp_clauses = gfc_trans_omp_clauses (&block, ¶llel_clauses,
|
|
code->loc);
|
|
}
|
|
do_clauses.nowait = true;
|
|
if (!do_clauses.ordered && do_clauses.sched_kind != OMP_SCHED_STATIC)
|
|
pblock = █
|
|
else
|
|
pushlevel ();
|
|
stmt = gfc_trans_omp_do (code, pblock, &do_clauses, omp_clauses);
|
|
if (TREE_CODE (stmt) != BIND_EXPR)
|
|
stmt = build3_v (BIND_EXPR, NULL, stmt, poplevel (1, 0));
|
|
else
|
|
poplevel (0, 0);
|
|
stmt = build2_loc (input_location, OMP_PARALLEL, void_type_node, stmt,
|
|
omp_clauses);
|
|
OMP_PARALLEL_COMBINED (stmt) = 1;
|
|
gfc_add_expr_to_block (&block, stmt);
|
|
return gfc_finish_block (&block);
|
|
}
|
|
|
|
static tree
|
|
gfc_trans_omp_parallel_sections (gfc_code *code)
|
|
{
|
|
stmtblock_t block;
|
|
gfc_omp_clauses section_clauses;
|
|
tree stmt, omp_clauses;
|
|
|
|
memset (§ion_clauses, 0, sizeof (section_clauses));
|
|
section_clauses.nowait = true;
|
|
|
|
gfc_start_block (&block);
|
|
omp_clauses = gfc_trans_omp_clauses (&block, code->ext.omp_clauses,
|
|
code->loc);
|
|
pushlevel ();
|
|
stmt = gfc_trans_omp_sections (code, §ion_clauses);
|
|
if (TREE_CODE (stmt) != BIND_EXPR)
|
|
stmt = build3_v (BIND_EXPR, NULL, stmt, poplevel (1, 0));
|
|
else
|
|
poplevel (0, 0);
|
|
stmt = build2_loc (input_location, OMP_PARALLEL, void_type_node, stmt,
|
|
omp_clauses);
|
|
OMP_PARALLEL_COMBINED (stmt) = 1;
|
|
gfc_add_expr_to_block (&block, stmt);
|
|
return gfc_finish_block (&block);
|
|
}
|
|
|
|
static tree
|
|
gfc_trans_omp_parallel_workshare (gfc_code *code)
|
|
{
|
|
stmtblock_t block;
|
|
gfc_omp_clauses workshare_clauses;
|
|
tree stmt, omp_clauses;
|
|
|
|
memset (&workshare_clauses, 0, sizeof (workshare_clauses));
|
|
workshare_clauses.nowait = true;
|
|
|
|
gfc_start_block (&block);
|
|
omp_clauses = gfc_trans_omp_clauses (&block, code->ext.omp_clauses,
|
|
code->loc);
|
|
pushlevel ();
|
|
stmt = gfc_trans_omp_workshare (code, &workshare_clauses);
|
|
if (TREE_CODE (stmt) != BIND_EXPR)
|
|
stmt = build3_v (BIND_EXPR, NULL, stmt, poplevel (1, 0));
|
|
else
|
|
poplevel (0, 0);
|
|
stmt = build2_loc (input_location, OMP_PARALLEL, void_type_node, stmt,
|
|
omp_clauses);
|
|
OMP_PARALLEL_COMBINED (stmt) = 1;
|
|
gfc_add_expr_to_block (&block, stmt);
|
|
return gfc_finish_block (&block);
|
|
}
|
|
|
|
static tree
|
|
gfc_trans_omp_sections (gfc_code *code, gfc_omp_clauses *clauses)
|
|
{
|
|
stmtblock_t block, body;
|
|
tree omp_clauses, stmt;
|
|
bool has_lastprivate = clauses->lists[OMP_LIST_LASTPRIVATE] != NULL;
|
|
|
|
gfc_start_block (&block);
|
|
|
|
omp_clauses = gfc_trans_omp_clauses (&block, clauses, code->loc);
|
|
|
|
gfc_init_block (&body);
|
|
for (code = code->block; code; code = code->block)
|
|
{
|
|
/* Last section is special because of lastprivate, so even if it
|
|
is empty, chain it in. */
|
|
stmt = gfc_trans_omp_code (code->next,
|
|
has_lastprivate && code->block == NULL);
|
|
if (! IS_EMPTY_STMT (stmt))
|
|
{
|
|
stmt = build1_v (OMP_SECTION, stmt);
|
|
gfc_add_expr_to_block (&body, stmt);
|
|
}
|
|
}
|
|
stmt = gfc_finish_block (&body);
|
|
|
|
stmt = build2_loc (input_location, OMP_SECTIONS, void_type_node, stmt,
|
|
omp_clauses);
|
|
gfc_add_expr_to_block (&block, stmt);
|
|
|
|
return gfc_finish_block (&block);
|
|
}
|
|
|
|
static tree
|
|
gfc_trans_omp_single (gfc_code *code, gfc_omp_clauses *clauses)
|
|
{
|
|
tree omp_clauses = gfc_trans_omp_clauses (NULL, clauses, code->loc);
|
|
tree stmt = gfc_trans_omp_code (code->block->next, true);
|
|
stmt = build2_loc (input_location, OMP_SINGLE, void_type_node, stmt,
|
|
omp_clauses);
|
|
return stmt;
|
|
}
|
|
|
|
static tree
|
|
gfc_trans_omp_task (gfc_code *code)
|
|
{
|
|
stmtblock_t block;
|
|
tree stmt, omp_clauses;
|
|
|
|
gfc_start_block (&block);
|
|
omp_clauses = gfc_trans_omp_clauses (&block, code->ext.omp_clauses,
|
|
code->loc);
|
|
stmt = gfc_trans_omp_code (code->block->next, true);
|
|
stmt = build2_loc (input_location, OMP_TASK, void_type_node, stmt,
|
|
omp_clauses);
|
|
gfc_add_expr_to_block (&block, stmt);
|
|
return gfc_finish_block (&block);
|
|
}
|
|
|
|
static tree
|
|
gfc_trans_omp_taskwait (void)
|
|
{
|
|
tree decl = builtin_decl_explicit (BUILT_IN_GOMP_TASKWAIT);
|
|
return build_call_expr_loc (input_location, decl, 0);
|
|
}
|
|
|
|
static tree
|
|
gfc_trans_omp_taskyield (void)
|
|
{
|
|
tree decl = builtin_decl_explicit (BUILT_IN_GOMP_TASKYIELD);
|
|
return build_call_expr_loc (input_location, decl, 0);
|
|
}
|
|
|
|
static tree
|
|
gfc_trans_omp_workshare (gfc_code *code, gfc_omp_clauses *clauses)
|
|
{
|
|
tree res, tmp, stmt;
|
|
stmtblock_t block, *pblock = NULL;
|
|
stmtblock_t singleblock;
|
|
int saved_ompws_flags;
|
|
bool singleblock_in_progress = false;
|
|
/* True if previous gfc_code in workshare construct is not workshared. */
|
|
bool prev_singleunit;
|
|
|
|
code = code->block->next;
|
|
|
|
pushlevel ();
|
|
|
|
gfc_start_block (&block);
|
|
pblock = █
|
|
|
|
ompws_flags = OMPWS_WORKSHARE_FLAG;
|
|
prev_singleunit = false;
|
|
|
|
/* Translate statements one by one to trees until we reach
|
|
the end of the workshare construct. Adjacent gfc_codes that
|
|
are a single unit of work are clustered and encapsulated in a
|
|
single OMP_SINGLE construct. */
|
|
for (; code; code = code->next)
|
|
{
|
|
if (code->here != 0)
|
|
{
|
|
res = gfc_trans_label_here (code);
|
|
gfc_add_expr_to_block (pblock, res);
|
|
}
|
|
|
|
/* No dependence analysis, use for clauses with wait.
|
|
If this is the last gfc_code, use default omp_clauses. */
|
|
if (code->next == NULL && clauses->nowait)
|
|
ompws_flags |= OMPWS_NOWAIT;
|
|
|
|
/* By default, every gfc_code is a single unit of work. */
|
|
ompws_flags |= OMPWS_CURR_SINGLEUNIT;
|
|
ompws_flags &= ~OMPWS_SCALARIZER_WS;
|
|
|
|
switch (code->op)
|
|
{
|
|
case EXEC_NOP:
|
|
res = NULL_TREE;
|
|
break;
|
|
|
|
case EXEC_ASSIGN:
|
|
res = gfc_trans_assign (code);
|
|
break;
|
|
|
|
case EXEC_POINTER_ASSIGN:
|
|
res = gfc_trans_pointer_assign (code);
|
|
break;
|
|
|
|
case EXEC_INIT_ASSIGN:
|
|
res = gfc_trans_init_assign (code);
|
|
break;
|
|
|
|
case EXEC_FORALL:
|
|
res = gfc_trans_forall (code);
|
|
break;
|
|
|
|
case EXEC_WHERE:
|
|
res = gfc_trans_where (code);
|
|
break;
|
|
|
|
case EXEC_OMP_ATOMIC:
|
|
res = gfc_trans_omp_directive (code);
|
|
break;
|
|
|
|
case EXEC_OMP_PARALLEL:
|
|
case EXEC_OMP_PARALLEL_DO:
|
|
case EXEC_OMP_PARALLEL_SECTIONS:
|
|
case EXEC_OMP_PARALLEL_WORKSHARE:
|
|
case EXEC_OMP_CRITICAL:
|
|
saved_ompws_flags = ompws_flags;
|
|
ompws_flags = 0;
|
|
res = gfc_trans_omp_directive (code);
|
|
ompws_flags = saved_ompws_flags;
|
|
break;
|
|
|
|
default:
|
|
internal_error ("gfc_trans_omp_workshare(): Bad statement code");
|
|
}
|
|
|
|
gfc_set_backend_locus (&code->loc);
|
|
|
|
if (res != NULL_TREE && ! IS_EMPTY_STMT (res))
|
|
{
|
|
if (prev_singleunit)
|
|
{
|
|
if (ompws_flags & OMPWS_CURR_SINGLEUNIT)
|
|
/* Add current gfc_code to single block. */
|
|
gfc_add_expr_to_block (&singleblock, res);
|
|
else
|
|
{
|
|
/* Finish single block and add it to pblock. */
|
|
tmp = gfc_finish_block (&singleblock);
|
|
tmp = build2_loc (input_location, OMP_SINGLE,
|
|
void_type_node, tmp, NULL_TREE);
|
|
gfc_add_expr_to_block (pblock, tmp);
|
|
/* Add current gfc_code to pblock. */
|
|
gfc_add_expr_to_block (pblock, res);
|
|
singleblock_in_progress = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (ompws_flags & OMPWS_CURR_SINGLEUNIT)
|
|
{
|
|
/* Start single block. */
|
|
gfc_init_block (&singleblock);
|
|
gfc_add_expr_to_block (&singleblock, res);
|
|
singleblock_in_progress = true;
|
|
}
|
|
else
|
|
/* Add the new statement to the block. */
|
|
gfc_add_expr_to_block (pblock, res);
|
|
}
|
|
prev_singleunit = (ompws_flags & OMPWS_CURR_SINGLEUNIT) != 0;
|
|
}
|
|
}
|
|
|
|
/* Finish remaining SINGLE block, if we were in the middle of one. */
|
|
if (singleblock_in_progress)
|
|
{
|
|
/* Finish single block and add it to pblock. */
|
|
tmp = gfc_finish_block (&singleblock);
|
|
tmp = build2_loc (input_location, OMP_SINGLE, void_type_node, tmp,
|
|
clauses->nowait
|
|
? build_omp_clause (input_location, OMP_CLAUSE_NOWAIT)
|
|
: NULL_TREE);
|
|
gfc_add_expr_to_block (pblock, tmp);
|
|
}
|
|
|
|
stmt = gfc_finish_block (pblock);
|
|
if (TREE_CODE (stmt) != BIND_EXPR)
|
|
{
|
|
if (!IS_EMPTY_STMT (stmt))
|
|
{
|
|
tree bindblock = poplevel (1, 0);
|
|
stmt = build3_v (BIND_EXPR, NULL, stmt, bindblock);
|
|
}
|
|
else
|
|
poplevel (0, 0);
|
|
}
|
|
else
|
|
poplevel (0, 0);
|
|
|
|
if (IS_EMPTY_STMT (stmt) && !clauses->nowait)
|
|
stmt = gfc_trans_omp_barrier ();
|
|
|
|
ompws_flags = 0;
|
|
return stmt;
|
|
}
|
|
|
|
tree
|
|
gfc_trans_omp_directive (gfc_code *code)
|
|
{
|
|
switch (code->op)
|
|
{
|
|
case EXEC_OMP_ATOMIC:
|
|
return gfc_trans_omp_atomic (code);
|
|
case EXEC_OMP_BARRIER:
|
|
return gfc_trans_omp_barrier ();
|
|
case EXEC_OMP_CRITICAL:
|
|
return gfc_trans_omp_critical (code);
|
|
case EXEC_OMP_DO:
|
|
return gfc_trans_omp_do (code, NULL, code->ext.omp_clauses, NULL);
|
|
case EXEC_OMP_FLUSH:
|
|
return gfc_trans_omp_flush ();
|
|
case EXEC_OMP_MASTER:
|
|
return gfc_trans_omp_master (code);
|
|
case EXEC_OMP_ORDERED:
|
|
return gfc_trans_omp_ordered (code);
|
|
case EXEC_OMP_PARALLEL:
|
|
return gfc_trans_omp_parallel (code);
|
|
case EXEC_OMP_PARALLEL_DO:
|
|
return gfc_trans_omp_parallel_do (code);
|
|
case EXEC_OMP_PARALLEL_SECTIONS:
|
|
return gfc_trans_omp_parallel_sections (code);
|
|
case EXEC_OMP_PARALLEL_WORKSHARE:
|
|
return gfc_trans_omp_parallel_workshare (code);
|
|
case EXEC_OMP_SECTIONS:
|
|
return gfc_trans_omp_sections (code, code->ext.omp_clauses);
|
|
case EXEC_OMP_SINGLE:
|
|
return gfc_trans_omp_single (code, code->ext.omp_clauses);
|
|
case EXEC_OMP_TASK:
|
|
return gfc_trans_omp_task (code);
|
|
case EXEC_OMP_TASKWAIT:
|
|
return gfc_trans_omp_taskwait ();
|
|
case EXEC_OMP_TASKYIELD:
|
|
return gfc_trans_omp_taskyield ();
|
|
case EXEC_OMP_WORKSHARE:
|
|
return gfc_trans_omp_workshare (code, code->ext.omp_clauses);
|
|
default:
|
|
gcc_unreachable ();
|
|
}
|
|
}
|