diff options
72 files changed, 3093 insertions, 749 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c838fcd..8d412b6 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,141 @@ +2025-04-24 Jakub Jelinek <jakub@redhat.com> + Stefan Schulze Frielinghaus <stefansf@gcc.gnu.org> + + PR target/119873 + * config/s390/s390.cc (s390_call_saved_register_used): Don't return + true if default definition of PARM_DECL SSA_NAME of the same register + is passed in call saved register. + (s390_function_ok_for_sibcall): Adjust comment. + +2025-04-24 Jan Hubicka <hubicka@ucw.cz> + + PR target/119919 + * config/i386/i386.cc (ix86_vector_costs::add_stmt_cost): Account + correctly cond_expr and min/max when one of operands is 0 or -1. + +2025-04-24 Jan Hubicka <hubicka@ucw.cz> + + PR ipa/119924 + * ipa-cp.cc (update_counts_for_self_gen_clones): Use nonzero_p. + (update_profiling_info): Likewise. + (update_specialized_profile): Likewise. + +2025-04-24 Richard Sandiford <richard.sandiford@arm.com> + + PR target/119610 + * config/aarch64/aarch64.cc (aarch64_allocate_and_probe_stack_space): + Add a bytes_below_sp parameter and use it to calculate the CFA + offsets. Attach the first SVE CFA note to the move into the + associated temporary register. + (aarch64_allocate_and_probe_stack_space): Update calls accordingly. + Start out with bytes_per_sp set to the frame size and decrement + it after each allocation. + +2025-04-24 Kyrylo Tkachov <ktkachov@nvidia.com> + + * opts.cc (validate_ipa_reorder_locality_lto_partition): Check opts + instead of opts_set for x_flag_ipa_reorder_for_locality. + (finish_options): Update call site. + +2025-04-24 Kyrylo Tkachov <ktkachov@nvidia.com> + + * common.opt (LTO_PARTITION_DEFAULT): Delete. + (flto-partition=): Change default back to balanced. + * flag-types.h (lto_partition_model): Remove LTO_PARTITION_DEFAULT. + * opts.cc (validate_ipa_reorder_locality_lto_partition): + Check opts_set->x_flag_lto_partition instead of LTO_PARTITION_DEFAULT. + (finish_options): Remove handling of LTO_PARTITION_DEFAULT. + +2025-04-24 Jakub Jelinek <jakub@redhat.com> + + PR debug/119711 + * dwarf2out.h (struct dw_val_node): Add u member. + (struct dw_loc_descr_node): Remove dw_loc_opc, dtprel, + frame_offset_rel and dw_loc_addr members. + (dw_loc_opc, dw_loc_dtprel, dw_loc_frame_offset_rel, dw_loc_addr): + Define. + (struct dw_attr_struct): Remove dw_attr member. + (dw_attr): Define. + * dwarf2out.cc (loc_descr_equal_p_1): Use dw_loc_dtprel instead of + dtprel. + (output_loc_operands, new_addr_loc_descr, loc_checksum, + loc_checksum_ordered): Likewise. + (resolve_args_picking_1): Use dw_loc_frame_offset_rel instead of + frame_offset_rel. + (loc_list_from_tree_1): Likewise. + (resolve_addr_in_expr): Use dw_loc_dtprel instead of dtprel. + (copy_deref_exprloc): Copy val_class, val_entry and v members + instead of whole dw_loc_oprnd1 and dw_loc_oprnd2. + (optimize_string_length): Copy val_class, val_entry and v members + instead of whole dw_attr_val. + (hash_loc_operands): Use dw_loc_dtprel instead of dtprel. + (compare_loc_operands, compare_locs): Likewise. + +2025-04-24 liuhongt <hongtao.liu@intel.com> + + PR target/103750 + * config/i386/sse.md (*<avx512>_cmp<mode>3_and15): New define_insn. + (*<avx512>_ucmp<mode>3_and15): Ditto. + (*<avx512>_cmp<mode>3_and3): Ditto. + (*avx512vl_ucmpv2di3_and3): Ditto. + (*<avx512>_cmp<V48H_AVX512VL:mode>3_zero_extend<SWI248x:mode>): + Change operands[3] predicate to <cmp_imm_predicate>. + (*<avx512>_cmp<V48H_AVX512VL:mode>3_zero_extend<SWI248x:mode>_2): + Ditto. + (*<avx512>_cmp<mode>3): Add GET_MODE_NUNITS (<MODE>mode) >= 8 + to the condition. + (*<avx512>_ucmp<mode>3): Ditto. + (V48_AVX512VL_4): New mode iterator. + (VI48_AVX512VL_4): Ditto. + (V8_AVX512VL_2): Ditto. + +2025-04-23 Jan Hubicka <hubicka@ucw.cz> + + * ipa-cp.cc (base_count): Remove. + (struct caller_statistics): Rename n_hot_calls to n_interesting_calls; + add called_without_ipa_profile. + (init_caller_stats): Update. + (cs_interesting_for_ipcp_p): New function. + (gather_caller_stats): collect n_interesting_calls and + called_without_profile. + (ipcp_cloning_candidate_p): Use n_interesting-calls rather then hot. + (good_cloning_opportunity_p): Rewrite heuristics when IPA profile is + present + (estimate_local_effects): Update. + (value_topo_info::propagate_effects): Update. + (compare_edge_profile_counts): Remove. + (ipcp_propagate_stage): Do not collect base_count. + (get_info_about_necessary_edges): Record whether function is called + without profile. + (decide_about_value): Update. + (ipa_cp_cc_finalize): Do not initialie base_count. + * profile-count.cc (profile_count::operator*): New. + (profile_count::operator*=): New. + * profile-count.h (profile_count::operator*): Declare + (profile_count::operator*=): Declare. + * params.opt: Remove ipa-cp-profile-count-base. + * doc/invoke.texi: Likewise. + +2025-04-23 Jan Hubicka <hubicka@ucw.cz> + + * config/i386/i386.cc (ix86_vector_costs::add_stmt_cost): Cost truth_value + exprs. + +2025-04-23 liuhongt <hongtao.liu@intel.com> + + * config/i386/predicates.md (vector_or_0_or_1s_operand): New predicate. + (nonimm_or_0_or_1s_operand): Ditto. + * config/i386/sse.md (vcond_mask_<mode><sseintvecmodelower>): + Extend the predicate of operands1 to accept 0 or allones + operands. + (vcond_mask_<mode><sseintvecmodelower>): Ditto. + (vcond_mask_v1tiv1ti): Ditto. + (vcond_mask_<mode><sseintvecmodelower>): Ditto. + * config/i386/i386.md (mov<mode>cc): Ditto for operands[2] and + operands[3]. + * config/i386/i386-expand.cc (ix86_expand_sse_fp_minmax): + Force immediate_operand to register. + 2025-04-22 Jan Hubicka <hubicka@ucw.cz> * config/i386/i386.cc (ix86_vector_costs::add_stmt_cost): Add special cases diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 1041049..c872ff4 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20250423 +20250425 diff --git a/gcc/cobol/ChangeLog b/gcc/cobol/ChangeLog index 27c31c1..d7d8596 100644 --- a/gcc/cobol/ChangeLog +++ b/gcc/cobol/ChangeLog @@ -1,3 +1,20 @@ +2025-04-24 Robert Dubner <rdubner@symas.com> + + * genapi.cc: (initialize_variable_internal): Change TRACE1 formatting. + (create_and_call): Repair RETURN-CODE processing. + (mh_source_is_group): Repair run-time IF type comparison. + (psa_FldLiteralA): Change TRACE1 formatting. + (parser_symbol_add): Eliminate unnecessary code. + * genutil.cc: Eliminate SET_EXCEPTION_CODE macro. + (get_data_offset_dest): Repair set_exception_code logic. + (get_data_offset_source): Likewise. + (get_binary_value): Likewise. + (refer_refmod_length): Likewise. + (refer_fill_depends): Likewise. + (refer_offset_dest): Likewise. + (refer_size_dest): Likewise. + (refer_offset_source): Likewise. + 2025-04-16 Bob Dubner <rdubner@symas.com> PR cobol/119759 diff --git a/gcc/cobol/genapi.cc b/gcc/cobol/genapi.cc index c8911f9..e44364a 100644 --- a/gcc/cobol/genapi.cc +++ b/gcc/cobol/genapi.cc @@ -1229,7 +1229,40 @@ initialize_variable_internal( cbl_refer_t refer, } else { - TRACE1_FIELD_VALUE("", parsed_var, "") + // Convert strings of spaces to "<SPACES>" + tree spaces = gg_define_int(0); + if( parsed_var->type == FldGroup + || parsed_var->type == FldAlphanumeric + || parsed_var->type == FldAlphaEdited + || parsed_var->type == FldLiteralA ) + { + gg_assign(spaces, integer_one_node); + tree counter = gg_define_int(parsed_var->data.capacity); + WHILE(counter, gt_op, integer_zero_node) + { + gg_decrement(counter); + IF( gg_indirect(member(parsed_var->var_decl_node, "data"), counter), + ne_op, + build_int_cst_type(UCHAR, ' ') ) + { + gg_assign(spaces, integer_zero_node); + } + ELSE + { + } + ENDIF + } + WEND + } + IF(spaces, eq_op, integer_one_node) + { + TRACE1_TEXT(" <SPACES>") + } + ELSE + { + TRACE1_FIELD_VALUE("", parsed_var, "") + } + ENDIF } TRACE1_END } @@ -12341,7 +12374,7 @@ create_and_call(size_t narg, // Because the CALL had a RETURNING clause, RETURN-CODE doesn't return a // value. So, we make sure it is zero - gg_assign(var_decl_return_code, build_int_cst_type(SHORT, 0)); +//// gg_assign(var_decl_return_code, build_int_cst_type(SHORT, 0)); if( returned_value_type == CHAR_P ) { @@ -12352,7 +12385,7 @@ create_and_call(size_t narg, gg_add( member(returned.field->var_decl_node, "data"), refer_offset_dest(returned))); gg_assign(returned_length, - refer_size_dest(returned)); + gg_cast(TREE_TYPE(returned_length), refer_size_dest(returned))); // The returned value is a string of nbytes, which by specification // has to be at least as long as the returned_length of the target: @@ -12442,28 +12475,9 @@ create_and_call(size_t narg, } else { - // Because no explicit returning value is expected, we switch to - // the IBM default behavior, where the returned INT value is assigned - // to our RETURN-CODE: - returned_value = gg_define_variable(SHORT); - - // Before doing the call, we save the COBOL program_state: - push_program_state(); - gg_assign(returned_value, gg_cast(SHORT, call_expr)); - // And after the call, we restore it: - pop_program_state(); - - // We know that the returned value is a 2-byte little-endian INT: - gg_assign( var_decl_return_code, - returned_value); - TRACE1 - { - TRACE1_HEADER - gg_printf("returned value: %d", - gg_cast(INT, var_decl_return_code), - NULL_TREE); - TRACE1_END - } + // Because no explicit returning value is expected, we just call it. We + // expect COBOL routines to set RETURN-CODE when they think it necessary. + gg_append_statement(call_expr); } for( size_t i=0; i<narg; i++ ) @@ -14810,7 +14824,7 @@ mh_source_is_group( cbl_refer_t &destref, tree dbytes = refer_size_dest(destref); tree sbytes = tsrc.length; - IF( sbytes, ge_op, dbytes ) + IF( sbytes, ge_op, gg_cast(TREE_TYPE(sbytes), dbytes) ) { // There are too many source bytes gg_memcpy(tdest, tsource, dbytes); @@ -16140,12 +16154,12 @@ psa_FldLiteralA(struct cbl_field_t *field ) DECL_PRESERVE_P (field->var_decl_node) = 1; nvar += 1; } - TRACE1 - { - TRACE1_INDENT - TRACE1_TEXT("Finished") - TRACE1_END - } +// TRACE1 +// { +// TRACE1_INDENT +// TRACE1_TEXT("Finished") +// TRACE1_END +// } } #endif @@ -16535,24 +16549,15 @@ parser_symbol_add(struct cbl_field_t *new_var ) size_t our_index = new_var->our_index; - // During the early stages of implementing cbl_field_t::our_index, there - // were execution paths in parse.y and parser.cc that resulted in our_index - // not being set. I hereby try to use field_index() to find the index - // of this field to resolve those. I note that field_index does a linear - // search of the symbols[] table to find that index. That's why I don't - // use it routinely; it results in O(N^squared) computational complexity - // to do a linear search of the symbol table for each symbol - if( !our_index && new_var->type != FldLiteralN && !(new_var->attr & intermediate_e)) { - our_index = field_index(new_var); - if( our_index == (size_t)-1 ) - { - // Hmm. Couldn't find it. Seems odd. - our_index = 0; - } + // During the early stages of implementing cbl_field_t::our_index, there + // were execution paths in parse.y and parser.cc that resulted in + // our_index not being set. Those should be gone. + fprintf(stderr, "our_index is NULL under unanticipated circumstances"); + gcc_assert(false); } // When we create the cblc_field_t structure, we need a data pointer @@ -16561,7 +16566,7 @@ parser_symbol_add(struct cbl_field_t *new_var ) // we calculate data as the pointer to our parent's data plus our // offset. - // declare and define the structure. This code *must* match + // Declare and define the structure. This code *must* match // the C structure declared in libgcobol.c. Towards that end, the // variables are declared in descending order of size in order to // make the packing match up. diff --git a/gcc/cobol/genutil.cc b/gcc/cobol/genutil.cc index d11e464..0322833 100644 --- a/gcc/cobol/genutil.cc +++ b/gcc/cobol/genutil.cc @@ -54,8 +54,6 @@ bool skip_exception_processing = true; bool suppress_dest_depends = false; -#define SET_EXCEPTION_CODE(a) do{set_exception_code((a));}while(0); - std::vector<std::string>current_filename; tree var_decl_exception_code; // int __gg__exception_code; @@ -266,6 +264,20 @@ get_integer_value(tree value, gg_assign(value, gg_cast(TREE_TYPE(value), temp)); } +static +tree +get_any_capacity(cbl_field_t *field) + { + if( field->attr & (any_length_e | intermediate_e) ) + { + return member(field->var_decl_node, "capacity"); + } + else + { + return build_int_cst_type(LONG, field->data.capacity); + } + } + static tree get_data_offset_dest(cbl_refer_t &refer, int *pflags = NULL) @@ -324,45 +336,27 @@ get_data_offset_dest(cbl_refer_t &refer, // Pick up the integer value of the subscript: static tree subscript = gg_define_variable(LONG, "..gdod_subscript", vs_file_static); - if( process_this_exception(ec_bound_subscript_e) ) + get_integer_value(subscript, + refer.subscripts[i].field, + refer_offset_dest(refer.subscripts[i]), + CHECK_FOR_FRACTIONAL_DIGITS); + IF( var_decl_rdigits, + ne_op, + integer_zero_node ) { - get_integer_value(value64, - refer.subscripts[i].field, - refer_offset_dest(refer.subscripts[i]), - CHECK_FOR_FRACTIONAL_DIGITS); - IF( var_decl_rdigits, - ne_op, - integer_zero_node ) - { - if( enabled_exceptions.match(ec_bound_subscript_e) ) - { - // The subscript isn't an integer - SET_EXCEPTION_CODE(ec_bound_subscript_e); - gg_assign(subscript, gg_cast(TREE_TYPE(subscript), integer_zero_node)); - } - else - { - rt_error("error: a table subscript is not an integer"); - } - } - ELSE - { - gg_assign(subscript, gg_cast(TREE_TYPE(subscript), value64)); - } - ENDIF + // The subscript isn't an integer + set_exception_code(ec_bound_subscript_e); } - else + ELSE { - get_integer_value(subscript, - refer.subscripts[i].field, - refer_offset_dest(refer.subscripts[i])); } + ENDIF - // gg_printf("%s(): We have a subscript of %d from %s\n", - // gg_string_literal(__func__), - // subscript, - // gg_string_literal(refer.subscripts[i].field->name), - // NULL_TREE); +// gg_printf("%s(): We have a subscript of %d from %s\n", +// gg_string_literal(__func__), +// subscript, +// gg_string_literal(refer.subscripts[i].field->name), +// NULL_TREE); if( (refer.subscripts[i].field->attr & FIGCONST_MASK) == zero_value_e ) { @@ -381,74 +375,46 @@ get_data_offset_dest(cbl_refer_t &refer, // Make it zero-based: gg_decrement(subscript); - if( process_this_exception(ec_bound_subscript_e) ) + + IF( subscript, lt_op, gg_cast(TREE_TYPE(subscript), integer_zero_node) ) + { + // The subscript is too small + set_exception_code(ec_bound_subscript_e); + gg_assign(subscript, build_int_cst_type(TREE_TYPE(subscript), 0)); + } + ELSE { - // gg_printf("process_this_exception is true\n", NULL_TREE); - IF( subscript, lt_op, gg_cast(TREE_TYPE(subscript), integer_zero_node) ) + // gg_printf("parent->occurs.ntimes() is %d\n", build_int_cst_type(INT, parent->occurs.ntimes()), NULL_TREE); + IF( subscript, + ge_op, + build_int_cst_type(TREE_TYPE(subscript), parent->occurs.ntimes()) ) { - // The subscript is too small - SET_EXCEPTION_CODE(ec_bound_subscript_e); - gg_assign(subscript, gg_cast(TREE_TYPE(subscript), integer_zero_node)); + // The subscript is too large + set_exception_code(ec_bound_subscript_e); + gg_assign(subscript, build_int_cst_type(TREE_TYPE(subscript), 0)); } ELSE { - // gg_printf("parent->occurs.ntimes() is %d\n", build_int_cst_type(INT, parent->occurs.ntimes()), NULL_TREE); - IF( subscript, - ge_op, - build_int_cst_type(TREE_TYPE(subscript), parent->occurs.ntimes()) ) + // We have a good subscript: + // Check for an ODO violation: + if( parent->occurs.depending_on ) { - // The subscript is too large - if( enabled_exceptions.match(ec_bound_subscript_e) ) + cbl_field_t *depending_on = cbl_field_of(symbol_at(parent->occurs.depending_on)); + get_integer_value(value64, depending_on); + IF( subscript, ge_op, value64 ) { - SET_EXCEPTION_CODE(ec_bound_subscript_e); - gg_assign(subscript, gg_cast(TREE_TYPE(subscript), integer_zero_node)); - } - else - { - rt_error("error: table subscript is too large"); + gg_assign(var_decl_odo_violation, integer_one_node); } + ELSE + ENDIF } - ELSE - { - // We have a good subscript: - // Check for an ODO violation: - if( parent->occurs.depending_on ) - { - cbl_field_t *depending_on = cbl_field_of(symbol_at(parent->occurs.depending_on)); - get_integer_value(value64, depending_on); - IF( subscript, ge_op, value64 ) - { - gg_assign(var_decl_odo_violation, integer_one_node); - } - ELSE - ENDIF - } - tree augment = gg_multiply(subscript, build_int_cst_type(INT, parent->data.capacity)); - gg_assign(retval, gg_add(retval, gg_cast(SIZE_T, augment))); - } - ENDIF + tree augment = gg_multiply(subscript, get_any_capacity(parent)); + gg_assign(retval, gg_add(retval, gg_cast(SIZE_T, augment))); } ENDIF } - else - { - // Assume a good subscript: - // Check for an ODO violation: - if( parent->occurs.depending_on ) - { - cbl_field_t *depending_on = cbl_field_of(symbol_at(parent->occurs.depending_on)); - get_integer_value(value64, depending_on); - IF( subscript, ge_op, value64 ) - { - gg_assign(var_decl_odo_violation, integer_one_node); - } - ELSE - ENDIF - } - tree augment = gg_multiply(subscript, build_int_cst_type(INT, parent->data.capacity)); - gg_assign(retval, gg_add(retval, gg_cast(SIZE_T, augment))); - } + ENDIF parent = parent_of(parent); } } @@ -458,76 +424,40 @@ get_data_offset_dest(cbl_refer_t &refer, // We have a refmod to deal with static tree refstart = gg_define_variable(LONG, "..gdos_refstart", vs_file_static); - if( process_this_exception(ec_bound_ref_mod_e) ) - { - get_integer_value(value64, - refer.refmod.from->field, - refer_offset_source(*refer.refmod.from), - CHECK_FOR_FRACTIONAL_DIGITS); - IF( var_decl_rdigits, - ne_op, - integer_zero_node ) - { - // refmod offset is not an integer, and has to be - if( enabled_exceptions.match(ec_bound_ref_mod_e) ) - { - SET_EXCEPTION_CODE(ec_bound_ref_mod_e); - gg_assign(refstart, gg_cast(LONG, integer_one_node)); - } - else - { - rt_error("error: a refmod FROM is not an integer"); - } - } - ELSE - gg_assign(refstart, value64); - ENDIF - } - else + get_integer_value(refstart, + refer.refmod.from->field, + refer_offset_source(*refer.refmod.from), + CHECK_FOR_FRACTIONAL_DIGITS); + IF( var_decl_rdigits, + ne_op, + integer_zero_node ) { - get_integer_value(value64, - refer.refmod.from->field, - refer_offset_source(*refer.refmod.from) - ); - gg_assign(refstart, value64); + // refmod offset is not an integer, and has to be + set_exception_code(ec_bound_ref_mod_e); } + ELSE + ENDIF // Make refstart zero-based: gg_decrement(refstart); - if( process_this_exception(ec_bound_ref_mod_e) ) + IF( refstart, lt_op, gg_cast(LONG, integer_zero_node) ) + { + set_exception_code(ec_bound_ref_mod_e); + gg_assign(refstart, build_int_cst_type(TREE_TYPE(refstart), 0)); + } + ELSE { - IF( refstart, lt_op, gg_cast(LONG, integer_zero_node) ) + tree capacity = get_any_capacity(refer.field); + IF( refstart, gt_op, gg_cast(LONG, capacity) ) { - if( enabled_exceptions.match(ec_bound_ref_mod_e) ) - { - SET_EXCEPTION_CODE(ec_bound_ref_mod_e); - gg_assign(refstart, gg_cast(LONG, integer_zero_node)); - } - else - { - rt_error("error: refmod FROM is less than one"); - } + set_exception_code(ec_bound_ref_mod_e); + gg_assign(refstart, build_int_cst_type(TREE_TYPE(refstart), 0)); } ELSE - { - IF( refstart, gt_op, build_int_cst_type(LONG, refer.field->data.capacity) ) - { - if( enabled_exceptions.match(ec_bound_ref_mod_e) ) - { - SET_EXCEPTION_CODE(ec_bound_ref_mod_e); - gg_assign(refstart, gg_cast(LONG, integer_zero_node)); - } - else - { - rt_error("error: refmod FROM is too large"); - } - } - ELSE - ENDIF - } ENDIF } + ENDIF // We have a good refstart gg_assign(retval, gg_add(retval, gg_cast(SIZE_T, refstart))); @@ -601,42 +531,23 @@ get_data_offset_source(cbl_refer_t &refer, cbl_internal_error("Too many subscripts"); } // Pick up the integer value of the subscript: -// static tree subscript = gg_define_variable(LONG, "..gdos_subscript", vs_file_static); tree subscript = gg_define_variable(LONG); - if( process_this_exception(ec_bound_subscript_e) ) + get_integer_value(subscript, + refer.subscripts[i].field, + refer_offset_source(refer.subscripts[i]), + CHECK_FOR_FRACTIONAL_DIGITS); + IF( var_decl_rdigits, + ne_op, + integer_zero_node ) { - get_integer_value(value64, - refer.subscripts[i].field, - refer_offset_source(refer.subscripts[i]), - CHECK_FOR_FRACTIONAL_DIGITS); - IF( var_decl_rdigits, - ne_op, - integer_zero_node ) - { - if( enabled_exceptions.match(ec_bound_subscript_e) ) - { - // The subscript isn't an integer - SET_EXCEPTION_CODE(ec_bound_subscript_e); - gg_assign(subscript, gg_cast(TREE_TYPE(subscript), integer_zero_node)); - } - else - { - rt_error("error: a table subscript is not an integer"); - } - } - ELSE - { - gg_assign(subscript, gg_cast(TREE_TYPE(subscript), value64)); - } - ENDIF + // The subscript isn't an integer + set_exception_code(ec_bound_subscript_e); } - else + ELSE { - get_integer_value(subscript, - refer.subscripts[i].field, - refer_offset_source(refer.subscripts[i])); } + ENDIF // gg_printf("%s(): We have a subscript of %d from %s\n", // gg_string_literal(__func__), @@ -661,74 +572,46 @@ get_data_offset_source(cbl_refer_t &refer, // Make it zero-based: gg_decrement(subscript); - if( process_this_exception(ec_bound_subscript_e) ) + // gg_printf("process_this_exception is true\n", NULL_TREE); + IF( subscript, lt_op, gg_cast(TREE_TYPE(subscript), integer_zero_node) ) + { + // The subscript is too small + set_exception_code(ec_bound_subscript_e); + gg_assign(subscript, build_int_cst_type(TREE_TYPE(subscript), 0)); + } + ELSE { - // gg_printf("process_this_exception is true\n", NULL_TREE); - IF( subscript, lt_op, gg_cast(TREE_TYPE(subscript), integer_zero_node) ) + // gg_printf("parent->occurs.ntimes() is %d\n", build_int_cst_type(INT, parent->occurs.ntimes()), NULL_TREE); + IF( subscript, + ge_op, + build_int_cst_type(TREE_TYPE(subscript), parent->occurs.ntimes()) ) { - // The subscript is too small - SET_EXCEPTION_CODE(ec_bound_subscript_e); - gg_assign(subscript, gg_cast(TREE_TYPE(subscript), integer_zero_node)); + // The subscript is too large + set_exception_code(ec_bound_subscript_e); + gg_assign(subscript, build_int_cst_type(TREE_TYPE(subscript), 0)); } ELSE { - // gg_printf("parent->occurs.ntimes() is %d\n", build_int_cst_type(INT, parent->occurs.ntimes()), NULL_TREE); - IF( subscript, - ge_op, - build_int_cst_type(TREE_TYPE(subscript), parent->occurs.ntimes()) ) + // We have a good subscript: + // Check for an ODO violation: + if( parent->occurs.depending_on ) { - // The subscript is too large - if( enabled_exceptions.match(ec_bound_subscript_e) ) + cbl_field_t *depending_on = cbl_field_of(symbol_at(parent->occurs.depending_on)); + get_integer_value(value64, depending_on); + IF( subscript, ge_op, value64 ) { - SET_EXCEPTION_CODE(ec_bound_subscript_e); - gg_assign(subscript, gg_cast(TREE_TYPE(subscript), integer_zero_node)); - } - else - { - rt_error("error: table subscript is too large"); + gg_assign(var_decl_odo_violation, integer_one_node); } + ELSE + ENDIF } - ELSE - { - // We have a good subscript: - // Check for an ODO violation: - if( parent->occurs.depending_on ) - { - cbl_field_t *depending_on = cbl_field_of(symbol_at(parent->occurs.depending_on)); - get_integer_value(value64, depending_on); - IF( subscript, ge_op, value64 ) - { - gg_assign(var_decl_odo_violation, integer_one_node); - } - ELSE - ENDIF - } - tree augment = gg_multiply(subscript, build_int_cst_type(INT, parent->data.capacity)); - gg_assign(retval, gg_add(retval, gg_cast(SIZE_T, augment))); - } - ENDIF + tree augment = gg_multiply(subscript, get_any_capacity(parent)); + gg_assign(retval, gg_add(retval, gg_cast(SIZE_T, augment))); } ENDIF } - else - { - // Assume a good subscript: - // Check for an ODO violation: - if( parent->occurs.depending_on ) - { - cbl_field_t *depending_on = cbl_field_of(symbol_at(parent->occurs.depending_on)); - get_integer_value(value64, depending_on); - IF( subscript, ge_op, value64 ) - { - gg_assign(var_decl_odo_violation, integer_one_node); - } - ELSE - ENDIF - } - tree augment = gg_multiply(subscript, build_int_cst_type(INT, parent->data.capacity)); - gg_assign(retval, gg_add(retval, gg_cast(SIZE_T, augment))); - } + ENDIF parent = parent_of(parent); } } @@ -738,76 +621,40 @@ get_data_offset_source(cbl_refer_t &refer, // We have a refmod to deal with static tree refstart = gg_define_variable(LONG, "..gdo_refstart", vs_file_static); - if( process_this_exception(ec_bound_ref_mod_e) ) - { - get_integer_value(value64, - refer.refmod.from->field, - refer_offset_source(*refer.refmod.from), - CHECK_FOR_FRACTIONAL_DIGITS); - IF( var_decl_rdigits, - ne_op, - integer_zero_node ) - { - // refmod offset is not an integer, and has to be - if( enabled_exceptions.match(ec_bound_ref_mod_e) ) - { - SET_EXCEPTION_CODE(ec_bound_ref_mod_e); - gg_assign(refstart, gg_cast(LONG, integer_one_node)); - } - else - { - rt_error("error: a refmod FROM is not an integer"); - } - } - ELSE - gg_assign(refstart, value64); - ENDIF - } - else + get_integer_value(refstart, + refer.refmod.from->field, + refer_offset_source(*refer.refmod.from), + CHECK_FOR_FRACTIONAL_DIGITS); + IF( var_decl_rdigits, + ne_op, + integer_zero_node ) { - get_integer_value(value64, - refer.refmod.from->field, - refer_offset_source(*refer.refmod.from) - ); - gg_assign(refstart, value64); + // refmod offset is not an integer, and has to be + set_exception_code(ec_bound_ref_mod_e); } + ELSE + ENDIF // Make refstart zero-based: gg_decrement(refstart); - if( process_this_exception(ec_bound_ref_mod_e) ) + IF( refstart, lt_op, gg_cast(LONG, integer_zero_node) ) { - IF( refstart, lt_op, gg_cast(LONG, integer_zero_node) ) + set_exception_code(ec_bound_ref_mod_e); + gg_assign(refstart, gg_cast(LONG, integer_zero_node)); + } + ELSE + { + tree capacity = get_any_capacity(refer.field); + IF( refstart, gt_op, gg_cast(LONG, capacity) ) { - if( enabled_exceptions.match(ec_bound_ref_mod_e) ) - { - SET_EXCEPTION_CODE(ec_bound_ref_mod_e); - gg_assign(refstart, gg_cast(LONG, integer_zero_node)); - } - else - { - rt_error("error: refmod FROM is less than one"); - } + set_exception_code(ec_bound_ref_mod_e); + gg_assign(refstart, build_int_cst_type(TREE_TYPE(refstart), 0)); } ELSE - { - IF( refstart, gt_op, build_int_cst_type(LONG, refer.field->data.capacity) ) - { - if( enabled_exceptions.match(ec_bound_ref_mod_e) ) - { - SET_EXCEPTION_CODE(ec_bound_ref_mod_e); - gg_assign(refstart, gg_cast(LONG, integer_zero_node)); - } - else - { - rt_error("error: refmod FROM is too large"); - } - } - ELSE - ENDIF - } ENDIF } + ENDIF // We have a good refstart gg_assign(retval, gg_add(retval, gg_cast(SIZE_T, refstart))); @@ -933,7 +780,7 @@ get_binary_value( tree value, // This is the we-are-done pointer gg_assign(pend, gg_add( pointer, - build_int_cst_type(SIZE_T, field->data.capacity))); + get_any_capacity(field))); static tree signbyte = gg_define_variable(UCHAR, "..gbv_signbyte", vs_file_static); @@ -2123,193 +1970,105 @@ refer_refmod_length(cbl_refer_t &refer) if( refer.refmod.from || refer.refmod.len ) { // First, check for compile-time errors - bool any_length = !!(refer.field->attr & any_length_e); - tree rt_capacity; - static tree value64 = gg_define_variable(LONG, "..rrl_value64", vs_file_static); static tree refstart = gg_define_variable(LONG, "..rrl_refstart", vs_file_static); static tree reflen = gg_define_variable(LONG, "..rrl_reflen", vs_file_static); - if( any_length ) - { - rt_capacity = - gg_cast(LONG, - member(refer.field->var_decl_node, "capacity")); - } - else - { - rt_capacity = - build_int_cst_type(LONG, refer.field->data.capacity); - } + tree rt_capacity = get_any_capacity(refer.field); gg_assign(reflen, gg_cast(TREE_TYPE(reflen), integer_one_node)); - if( process_this_exception(ec_bound_ref_mod_e) ) - { - get_integer_value(value64, - refer.refmod.from->field, - refer_offset_source(*refer.refmod.from), - CHECK_FOR_FRACTIONAL_DIGITS); - IF( var_decl_rdigits, - ne_op, - integer_zero_node ) - { - if( enabled_exceptions.match(ec_bound_ref_mod_e) ) - { - SET_EXCEPTION_CODE(ec_bound_ref_mod_e); - gg_assign(refstart, gg_cast(LONG, integer_one_node)); - } - else - { - rt_error("a refmod FROM value is not an integer"); - } - } - ELSE - gg_assign(refstart, value64); - ENDIF - } - else + get_integer_value(refstart, + refer.refmod.from->field, + refer_offset_source(*refer.refmod.from), + CHECK_FOR_FRACTIONAL_DIGITS); + IF( var_decl_rdigits, + ne_op, + integer_zero_node ) { - get_integer_value(value64, - refer.refmod.from->field, - refer_offset_source(*refer.refmod.from) - ); - gg_assign(refstart, value64); + set_exception_code(ec_bound_ref_mod_e); + gg_assign(refstart, gg_cast(LONG, integer_one_node)); } + ELSE + ENDIF // Make refstart zero-based: gg_decrement(refstart); - if( process_this_exception(ec_bound_ref_mod_e) ) + IF( refstart, lt_op, build_int_cst_type(LONG, 0 ) ) { - IF( refstart, lt_op, build_int_cst_type(LONG, 0 ) ) + set_exception_code(ec_bound_ref_mod_e); + gg_assign(refstart, gg_cast(LONG, integer_zero_node)); + } + ELSE + { + IF( refstart, gt_op, gg_cast(TREE_TYPE(refstart), rt_capacity) ) { - if( enabled_exceptions.match(ec_bound_ref_mod_e) ) - { - SET_EXCEPTION_CODE(ec_bound_ref_mod_e); - gg_assign(refstart, gg_cast(LONG, integer_zero_node)); - } - else - { - rt_error("a refmod FROM value is less than zero"); - } + set_exception_code(ec_bound_ref_mod_e); + gg_assign(refstart, gg_cast(LONG, integer_zero_node)); } ELSE { - IF( refstart, gt_op, rt_capacity ) + if( refer.refmod.len ) { - if( enabled_exceptions.match(ec_bound_ref_mod_e) ) + get_integer_value(reflen, + refer.refmod.len->field, + refer_offset_source(*refer.refmod.len), + CHECK_FOR_FRACTIONAL_DIGITS); + IF( var_decl_rdigits, + ne_op, + integer_zero_node ) { - SET_EXCEPTION_CODE(ec_bound_ref_mod_e); - gg_assign(refstart, gg_cast(LONG, integer_zero_node)); + // length is not an integer + set_exception_code(ec_bound_ref_mod_e); + gg_assign(reflen, gg_cast(LONG, integer_one_node)); } - else + ELSE { - rt_error("a refmod FROM value is too large"); } - } - ELSE - { - if( refer.refmod.len ) - { - get_integer_value(value64, - refer.refmod.len->field, - refer_offset_source(*refer.refmod.len), - CHECK_FOR_FRACTIONAL_DIGITS); - IF( var_decl_rdigits, - ne_op, - integer_zero_node ) - { - // length is not an integer - if( enabled_exceptions.match(ec_bound_ref_mod_e) ) - { - SET_EXCEPTION_CODE(ec_bound_ref_mod_e); - gg_assign(reflen, gg_cast(LONG, integer_one_node)); - } - else - { - rt_error("a refmod LENGTH is not an integer"); - } - } - ELSE - { - gg_assign(reflen, gg_cast(LONG, value64)); - } - ENDIF + ENDIF - IF( reflen, lt_op, gg_cast(LONG, integer_one_node) ) + IF( reflen, lt_op, gg_cast(LONG, integer_one_node) ) + { + // length is too small + set_exception_code(ec_bound_ref_mod_e); + gg_assign(reflen, gg_cast(LONG, integer_one_node)); + } + ELSE + { + IF( gg_add(refstart, reflen), + gt_op, + gg_cast(TREE_TYPE(refstart), rt_capacity) ) { - // length is too small - if( enabled_exceptions.match(ec_bound_ref_mod_e) ) - { - SET_EXCEPTION_CODE(ec_bound_ref_mod_e); - gg_assign(reflen, gg_cast(LONG, integer_one_node)); - } - else - { - rt_error("a refmod LENGTH is less than one"); - } + // Start + Length is too large + set_exception_code(ec_bound_ref_mod_e); + + // Our intentions are honorable. But at this point, where + // we notice that start + length is too long, the + // get_data_offset_source routine has already been run and + // it's too late to actually change the refstart. There are + // theoretical solutions to this -- mainly, + // get_data_offset_source needs to check the start + len for + // validity. But I am not going to do it now. Think of this + // as the TODO item. + gg_assign(refstart, gg_cast(LONG, integer_zero_node)); + gg_assign(reflen, gg_cast(LONG, integer_one_node)); } ELSE - { - IF( gg_add(refstart, reflen), - gt_op, - rt_capacity ) - { - // Start + Length is too large - if( enabled_exceptions.match(ec_bound_ref_mod_e) ) - { - SET_EXCEPTION_CODE(ec_bound_ref_mod_e); - - // Our intentions are honorable. But at this point, where - // we notice that start + length is too long, the - // get_data_offset_source routine has already been run and - // it's too late to actually change the refstart. There are - // theoretical solutions to this -- mainly, - // get_data_offset_source needs to check the start + len for - // validity. But I am not going to do it now. Think of this - // as the TODO item. - gg_assign(refstart, gg_cast(LONG, integer_zero_node)); - gg_assign(reflen, gg_cast(LONG, integer_one_node)); - } - else - { - rt_error("refmod START + LENGTH is too large"); - } - } - ELSE - ENDIF - } ENDIF } - else - { - // There is no refmod length, so we default to the remaining characters - tree subtract_expr = gg_subtract( rt_capacity, - refstart); - gg_assign(reflen, subtract_expr); - } + ENDIF + } + else + { + // There is no refmod length, so we default to the remaining characters + tree subtract_expr = gg_subtract( rt_capacity, + refstart); + gg_assign(reflen, subtract_expr); } - ENDIF } ENDIF } - else - { - if( refer.refmod.len ) - { - get_integer_value(value64, - refer.refmod.len->field, - refer_offset_source(*refer.refmod.len) - ); - gg_assign(reflen, gg_cast(LONG, value64)); - } - else - { - // There is no refmod length, so we default to the remaining characters - gg_assign(reflen, gg_subtract(rt_capacity, - refstart)); - } - } + ENDIF // Arrive here with valid values for refstart and reflen: @@ -2346,73 +2105,42 @@ refer_fill_depends(cbl_refer_t &refer) // depending_on->name); static tree value64 = gg_define_variable(LONG, "..rfd_value64", vs_file_static); - if( process_this_exception(ec_bound_odo_e) ) + get_integer_value(value64, + depending_on, + NULL, + CHECK_FOR_FRACTIONAL_DIGITS); + IF( var_decl_rdigits, ne_op, integer_zero_node ) { - get_integer_value(value64, - depending_on, - NULL, - CHECK_FOR_FRACTIONAL_DIGITS); - IF( var_decl_rdigits, ne_op, integer_zero_node ) - { - // This needs to evaluate to an integer - if( enabled_exceptions.match(ec_bound_odo_e) ) - { - SET_EXCEPTION_CODE(ec_bound_odo_e); - gg_assign(value64, build_int_cst_type(TREE_TYPE(value64), odo->occurs.bounds.upper)); - } - else - { - rt_error("DEPENDING ON is not an integer"); - } - } - ELSE - ENDIF + // This needs to evaluate to an integer + set_exception_code(ec_bound_odo_e); + gg_assign(value64, build_int_cst_type(TREE_TYPE(value64), odo->occurs.bounds.upper)); } - else + ELSE + ENDIF + + IF( value64, gt_op, build_int_cst_type(TREE_TYPE(value64), odo->occurs.bounds.upper) ) { - get_integer_value(value64, depending_on); + set_exception_code(ec_bound_odo_e); + gg_assign(value64, build_int_cst_type(TREE_TYPE(value64), odo->occurs.bounds.upper)); } - - if( process_this_exception(ec_bound_odo_e) ) + ELSE { - IF( value64, gt_op, build_int_cst_type(TREE_TYPE(value64), odo->occurs.bounds.upper) ) + IF( value64, lt_op, build_int_cst_type(TREE_TYPE(value64), odo->occurs.bounds.lower) ) { - SET_EXCEPTION_CODE(ec_bound_odo_e); - gg_assign(value64, build_int_cst_type(TREE_TYPE(value64), odo->occurs.bounds.upper)); + set_exception_code(ec_bound_odo_e); + gg_assign(value64, build_int_cst_type(TREE_TYPE(value64), odo->occurs.bounds.lower)); } ELSE + ENDIF + IF( value64, lt_op, gg_cast(TREE_TYPE(value64), integer_zero_node) ) { - IF( value64, lt_op, build_int_cst_type(TREE_TYPE(value64), odo->occurs.bounds.lower) ) - { - if( enabled_exceptions.match(ec_bound_odo_e) ) - { - SET_EXCEPTION_CODE(ec_bound_odo_e); - gg_assign(value64, build_int_cst_type(TREE_TYPE(value64), odo->occurs.bounds.lower)); - } - else - { - rt_error("DEPENDING ON is less than OCCURS lower limit"); - } - } - ELSE - ENDIF - IF( value64, lt_op, gg_cast(TREE_TYPE(value64), integer_zero_node) ) - { - if( enabled_exceptions.match(ec_bound_odo_e) ) - { - SET_EXCEPTION_CODE(ec_bound_odo_e); - gg_assign(value64, gg_cast(TREE_TYPE(value64), integer_zero_node)); - } - else - { - rt_error("DEPENDING ON is greater than OCCURS upper limit"); - } - } - ELSE - ENDIF + set_exception_code(ec_bound_odo_e); + gg_assign(value64, gg_cast(TREE_TYPE(value64), integer_zero_node)); } + ELSE ENDIF } + ENDIF // value64 is >= zero and < bounds.upper // We multiply the ODO value by the size of the data capacity to get the @@ -2448,22 +2176,12 @@ refer_offset_dest(cbl_refer_t &refer) tree retval = gg_define_variable(SIZE_T); gg_assign(retval, get_data_offset_dest(refer)); - if( process_this_exception(ec_bound_odo_e) ) + IF( var_decl_odo_violation, ne_op, integer_zero_node ) { - IF( var_decl_odo_violation, ne_op, integer_zero_node ) - { - if( enabled_exceptions.match(ec_bound_odo_e) ) - { - SET_EXCEPTION_CODE(ec_bound_odo_e); - } - else - { - rt_error("receiving item subscript not in DEPENDING ON range"); - } - } - ELSE - ENDIF + set_exception_code(ec_bound_odo_e); } + ELSE + ENDIF return retval; } @@ -2482,14 +2200,7 @@ refer_size_dest(cbl_refer_t &refer) { // When the refer has no modifications, we return zero, which is interpreted // as "use the original length" - if( refer.field->attr & (intermediate_e | any_length_e) ) - { - return member(refer.field->var_decl_node, "capacity"); - } - else - { - return build_int_cst_type(SIZE_T, refer.field->data.capacity); - } + return get_any_capacity(refer.field); } // Step the first: Get the actual full length: @@ -2546,22 +2257,12 @@ refer_offset_source(cbl_refer_t &refer, gg_assign(var_decl_odo_violation, integer_zero_node); gg_assign(retval, get_data_offset_source(refer, pflags)); - if( process_this_exception(ec_bound_odo_e) ) + IF( var_decl_odo_violation, ne_op, integer_zero_node ) { - IF( var_decl_odo_violation, ne_op, integer_zero_node ) - { - if( enabled_exceptions.match(ec_bound_odo_e) ) - { - SET_EXCEPTION_CODE(ec_bound_odo_e); - } - else - { - rt_error("sending item subscript not in DEPENDING ON range"); - } - } - ELSE - ENDIF + set_exception_code(ec_bound_odo_e); } + ELSE + ENDIF return retval; } diff --git a/gcc/common.opt b/gcc/common.opt index 88d987e..e3fa0da 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -2279,9 +2279,6 @@ Enum Name(lto_partition_model) Type(enum lto_partition_model) UnknownError(unknown LTO partitioning model %qs) EnumValue -Enum(lto_partition_model) String(default) Value(LTO_PARTITION_DEFAULT) - -EnumValue Enum(lto_partition_model) String(none) Value(LTO_PARTITION_NONE) EnumValue @@ -2300,7 +2297,7 @@ EnumValue Enum(lto_partition_model) String(cache) Value(LTO_PARTITION_CACHE) flto-partition= -Common Joined RejectNegative Enum(lto_partition_model) Var(flag_lto_partition) Init(LTO_PARTITION_DEFAULT) +Common Joined RejectNegative Enum(lto_partition_model) Var(flag_lto_partition) Init(LTO_PARTITION_BALANCED) Specify the algorithm to partition symbols and vars at linktime. ; The initial value of -1 comes from Z_DEFAULT_COMPRESSION in zlib.h. diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc index 38c112c..f7bccf5 100644 --- a/gcc/config/aarch64/aarch64.cc +++ b/gcc/config/aarch64/aarch64.cc @@ -9417,13 +9417,16 @@ aarch64_emit_stack_tie (rtx reg) } /* Allocate POLY_SIZE bytes of stack space using TEMP1 and TEMP2 as scratch - registers. If POLY_SIZE is not large enough to require a probe this function - will only adjust the stack. When allocating the stack space - FRAME_RELATED_P is then used to indicate if the allocation is frame related. - FINAL_ADJUSTMENT_P indicates whether we are allocating the area below - the saved registers. If we are then we ensure that any allocation - larger than the ABI defined buffer needs a probe so that the - invariant of having a 1KB buffer is maintained. + registers, given that the stack pointer is currently BYTES_BELOW_SP bytes + above the bottom of the static frame. + + If POLY_SIZE is not large enough to require a probe this function will only + adjust the stack. When allocating the stack space FRAME_RELATED_P is then + used to indicate if the allocation is frame related. FINAL_ADJUSTMENT_P + indicates whether we are allocating the area below the saved registers. + If we are then we ensure that any allocation larger than the ABI defined + buffer needs a probe so that the invariant of having a 1KB buffer is + maintained. We emit barriers after each stack adjustment to prevent optimizations from breaking the invariant that we never drop the stack more than a page. This @@ -9440,6 +9443,7 @@ aarch64_emit_stack_tie (rtx reg) static void aarch64_allocate_and_probe_stack_space (rtx temp1, rtx temp2, poly_int64 poly_size, + poly_int64 bytes_below_sp, aarch64_isa_mode force_isa_mode, bool frame_related_p, bool final_adjustment_p) @@ -9503,8 +9507,8 @@ aarch64_allocate_and_probe_stack_space (rtx temp1, rtx temp2, poly_size, temp1, temp2, force_isa_mode, false, true); - rtx_insn *insn = get_last_insn (); - + auto initial_cfa_offset = frame.frame_size - bytes_below_sp; + auto final_cfa_offset = initial_cfa_offset + poly_size; if (frame_related_p) { /* This is done to provide unwinding information for the stack @@ -9514,28 +9518,31 @@ aarch64_allocate_and_probe_stack_space (rtx temp1, rtx temp2, The tie will expand to nothing but the optimizers will not touch the instruction. */ rtx stack_ptr_copy = gen_rtx_REG (Pmode, STACK_CLASH_SVE_CFA_REGNUM); - emit_move_insn (stack_ptr_copy, stack_pointer_rtx); + auto *insn = emit_move_insn (stack_ptr_copy, stack_pointer_rtx); aarch64_emit_stack_tie (stack_ptr_copy); /* We want the CFA independent of the stack pointer for the duration of the loop. */ - add_reg_note (insn, REG_CFA_DEF_CFA, stack_ptr_copy); + add_reg_note (insn, REG_CFA_DEF_CFA, + plus_constant (Pmode, stack_ptr_copy, + initial_cfa_offset)); RTX_FRAME_RELATED_P (insn) = 1; } rtx probe_const = gen_int_mode (min_probe_threshold, Pmode); rtx guard_const = gen_int_mode (guard_size, Pmode); - insn = emit_insn (gen_probe_sve_stack_clash (Pmode, stack_pointer_rtx, - stack_pointer_rtx, temp1, - probe_const, guard_const)); + auto *insn + = emit_insn (gen_probe_sve_stack_clash (Pmode, stack_pointer_rtx, + stack_pointer_rtx, temp1, + probe_const, guard_const)); /* Now reset the CFA register if needed. */ if (frame_related_p) { add_reg_note (insn, REG_CFA_DEF_CFA, - gen_rtx_PLUS (Pmode, stack_pointer_rtx, - gen_int_mode (poly_size, Pmode))); + plus_constant (Pmode, stack_pointer_rtx, + final_cfa_offset)); RTX_FRAME_RELATED_P (insn) = 1; } @@ -9581,12 +9588,13 @@ aarch64_allocate_and_probe_stack_space (rtx temp1, rtx temp2, We can determine which allocation we are doing by looking at the value of FRAME_RELATED_P since the final allocations are not frame related. */ + auto cfa_offset = frame.frame_size - (bytes_below_sp - rounded_size); if (frame_related_p) { /* We want the CFA independent of the stack pointer for the duration of the loop. */ add_reg_note (insn, REG_CFA_DEF_CFA, - plus_constant (Pmode, temp1, rounded_size)); + plus_constant (Pmode, temp1, cfa_offset)); RTX_FRAME_RELATED_P (insn) = 1; } @@ -9608,7 +9616,7 @@ aarch64_allocate_and_probe_stack_space (rtx temp1, rtx temp2, if (frame_related_p) { add_reg_note (insn, REG_CFA_DEF_CFA, - plus_constant (Pmode, stack_pointer_rtx, rounded_size)); + plus_constant (Pmode, stack_pointer_rtx, cfa_offset)); RTX_FRAME_RELATED_P (insn) = 1; } @@ -9916,17 +9924,22 @@ aarch64_expand_prologue (void) code below does not handle it for -fstack-clash-protection. */ gcc_assert (known_eq (initial_adjust, 0) || callee_adjust == 0); + /* The offset of the current SP from the bottom of the static frame. */ + poly_int64 bytes_below_sp = frame_size; + /* Will only probe if the initial adjustment is larger than the guard less the amount of the guard reserved for use by the caller's outgoing args. */ aarch64_allocate_and_probe_stack_space (tmp0_rtx, tmp1_rtx, initial_adjust, - force_isa_mode, true, false); + bytes_below_sp, force_isa_mode, + true, false); + bytes_below_sp -= initial_adjust; if (callee_adjust != 0) - aarch64_push_regs (reg1, reg2, callee_adjust); - - /* The offset of the current SP from the bottom of the static frame. */ - poly_int64 bytes_below_sp = frame_size - initial_adjust - callee_adjust; + { + aarch64_push_regs (reg1, reg2, callee_adjust); + bytes_below_sp -= callee_adjust; + } if (emit_frame_chain) { @@ -9994,7 +10007,7 @@ aarch64_expand_prologue (void) || known_eq (frame.reg_offset[VG_REGNUM], bytes_below_sp)); aarch64_allocate_and_probe_stack_space (tmp1_rtx, tmp0_rtx, sve_callee_adjust, - force_isa_mode, + bytes_below_sp, force_isa_mode, !frame_pointer_needed, false); bytes_below_sp -= sve_callee_adjust; } @@ -10005,10 +10018,11 @@ aarch64_expand_prologue (void) /* We may need to probe the final adjustment if it is larger than the guard that is assumed by the called. */ - gcc_assert (known_eq (bytes_below_sp, final_adjust)); aarch64_allocate_and_probe_stack_space (tmp1_rtx, tmp0_rtx, final_adjust, - force_isa_mode, + bytes_below_sp, force_isa_mode, !frame_pointer_needed, true); + bytes_below_sp -= final_adjust; + gcc_assert (known_eq (bytes_below_sp, 0)); if (emit_frame_chain && maybe_ne (final_adjust, 0)) aarch64_emit_stack_tie (hard_frame_pointer_rtx); diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc index 3b4dfd9..78df3d9 100644 --- a/gcc/config/i386/i386.cc +++ b/gcc/config/i386/i386.cc @@ -25375,14 +25375,32 @@ ix86_vector_costs::add_stmt_cost (int count, vect_cost_for_stmt kind, case COND_EXPR: { /* SSE2 conditinal move sequence is: - pcmpgtd %xmm5, %xmm0 + pcmpgtd %xmm5, %xmm0 (accounted separately) pand %xmm0, %xmm2 pandn %xmm1, %xmm0 por %xmm2, %xmm0 while SSE4 uses cmp + blend - and AVX512 masked moves. */ - - int ninsns = TARGET_SSE4_1 ? 2 : 4; + and AVX512 masked moves. + + The condition is accounted separately since we usually have + p = a < b + c = p ? x : y + and we will account first statement as setcc. Exception is when + p is loaded from memory as bool and then we will not acocunt + the compare, but there is no way to check for this. */ + + int ninsns = TARGET_SSE4_1 ? 1 : 3; + + /* If one of parameters is 0 or -1 the sequence will be simplified: + (if_true & mask) | (if_false & ~mask) -> if_true & mask */ + if (ninsns > 1 + && (zerop (gimple_assign_rhs2 (stmt_info->stmt)) + || zerop (gimple_assign_rhs3 (stmt_info->stmt)) + || integer_minus_onep + (gimple_assign_rhs2 (stmt_info->stmt)) + || integer_minus_onep + (gimple_assign_rhs3 (stmt_info->stmt)))) + ninsns = 1; if (SSE_FLOAT_MODE_SSEMATH_OR_HFBF_P (mode)) stmt_cost = ninsns * ix86_cost->sse_op; @@ -25393,8 +25411,8 @@ ix86_vector_costs::add_stmt_cost (int count, vect_cost_for_stmt kind, else if (VECTOR_MODE_P (mode)) stmt_cost = ix86_vec_cost (mode, ninsns * ix86_cost->sse_op); else - /* compare + cmov. */ - stmt_cost = ix86_cost->add * 2; + /* compare (accounted separately) + cmov. */ + stmt_cost = ix86_cost->add; } break; @@ -25416,9 +25434,18 @@ ix86_vector_costs::add_stmt_cost (int count, vect_cost_for_stmt kind, { stmt_cost = ix86_vec_cost (mode, ix86_cost->sse_op); /* vpmin was introduced in SSE3. - SSE2 needs pcmpgtd + pand + pandn + pxor. */ + SSE2 needs pcmpgtd + pand + pandn + pxor. + If one of parameters is 0 or -1 the sequence is simplified + to pcmpgtd + pand. */ if (!TARGET_SSSE3) - stmt_cost *= 4; + { + if (zerop (gimple_assign_rhs2 (stmt_info->stmt)) + || integer_minus_onep + (gimple_assign_rhs2 (stmt_info->stmt))) + stmt_cost *= 2; + else + stmt_cost *= 4; + } } else /* cmp + cmov. */ diff --git a/gcc/config/s390/s390.cc b/gcc/config/s390/s390.cc index d82b16e..0e9140e 100644 --- a/gcc/config/s390/s390.cc +++ b/gcc/config/s390/s390.cc @@ -14496,7 +14496,21 @@ s390_call_saved_register_used (tree call_expr) for (reg = 0; reg < nregs; reg++) if (!call_used_or_fixed_reg_p (reg + REGNO (parm_rtx))) - return true; + { + rtx parm; + /* Allow passing through unmodified value from caller, + see PR119873. */ + if (TREE_CODE (parameter) == SSA_NAME + && SSA_NAME_IS_DEFAULT_DEF (parameter) + && SSA_NAME_VAR (parameter) + && TREE_CODE (SSA_NAME_VAR (parameter)) == PARM_DECL + && (parm = DECL_INCOMING_RTL (SSA_NAME_VAR (parameter))) + && REG_P (parm) + && REGNO (parm) == REGNO (parm_rtx) + && REG_NREGS (parm) == REG_NREGS (parm_rtx)) + break; + return true; + } } else if (GET_CODE (parm_rtx) == PARALLEL) { @@ -14543,8 +14557,9 @@ s390_function_ok_for_sibcall (tree decl, tree exp) return false; /* Register 6 on s390 is available as an argument register but unfortunately - "caller saved". This makes functions needing this register for arguments - not suitable for sibcalls. */ + "caller saved". This makes functions needing this register for arguments + not suitable for sibcalls, unless the same value is passed from the + caller. */ return !s390_call_saved_register_used (exp); } diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index d9f0298..cd128e2 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,9 @@ +2025-04-24 Jason Merrill <jason@redhat.com> + + PR c++/116954 + * contracts.cc (remove_contract_attributes): Return early if + not enabled. + 2025-04-22 Nathaniel Shead <nathanieloshead@gmail.com> * name-lookup.cc (lookup_imported_hidden_friend): Remove diff --git a/gcc/cp/contracts.cc b/gcc/cp/contracts.cc index 3ca2102..d0cfd2e 100644 --- a/gcc/cp/contracts.cc +++ b/gcc/cp/contracts.cc @@ -860,6 +860,9 @@ cp_contract_assertion_p (const_tree attr) void remove_contract_attributes (tree fndecl) { + if (!flag_contracts) + return; + tree list = NULL_TREE; for (tree p = DECL_ATTRIBUTES (fndecl); p; p = TREE_CHAIN (p)) if (!cxx_contract_attribute_p (p)) diff --git a/gcc/dwarf2out.cc b/gcc/dwarf2out.cc index 69e9d77..34ffeed 100644 --- a/gcc/dwarf2out.cc +++ b/gcc/dwarf2out.cc @@ -1536,7 +1536,7 @@ loc_descr_equal_p_1 (dw_loc_descr_ref a, dw_loc_descr_ref b) /* ??? This is only ever set for DW_OP_constNu, for N equal to the address size, but since we always allocate cleared storage it should be zero for other types of locations. */ - if (a->dtprel != b->dtprel) + if (a->dw_loc_dtprel != b->dw_loc_dtprel) return false; return (dw_val_equal_p (&a->dw_loc_oprnd1, &b->dw_loc_oprnd1) @@ -2115,7 +2115,7 @@ output_loc_operands (dw_loc_descr_ref loc, int for_eh_or_skip) dw2_asm_output_data (2, val1->v.val_int, NULL); break; case DW_OP_const4u: - if (loc->dtprel) + if (loc->dw_loc_dtprel) { gcc_assert (targetm.asm_out.output_dwarf_dtprel); targetm.asm_out.output_dwarf_dtprel (asm_out_file, 4, @@ -2128,7 +2128,7 @@ output_loc_operands (dw_loc_descr_ref loc, int for_eh_or_skip) dw2_asm_output_data (4, val1->v.val_int, NULL); break; case DW_OP_const8u: - if (loc->dtprel) + if (loc->dw_loc_dtprel) { gcc_assert (targetm.asm_out.output_dwarf_dtprel); targetm.asm_out.output_dwarf_dtprel (asm_out_file, 8, @@ -2323,7 +2323,7 @@ output_loc_operands (dw_loc_descr_ref loc, int for_eh_or_skip) break; case DW_OP_addr: - if (loc->dtprel) + if (loc->dw_loc_dtprel) { if (targetm.asm_out.output_dwarf_dtprel) { @@ -4028,7 +4028,7 @@ new_addr_loc_descr (rtx addr, enum dtprel_bool dtprel) ref->dw_loc_oprnd1.val_class = dw_val_class_addr; ref->dw_loc_oprnd1.v.val_addr = addr; - ref->dtprel = dtprel; + ref->dw_loc_dtprel = dtprel; if (dwarf_split_debug_info) ref->dw_loc_oprnd1.val_entry = add_addr_table_entry (addr, @@ -7036,7 +7036,7 @@ loc_checksum (dw_loc_descr_ref loc, struct md5_ctx *ctx) inchash::hash hstate; hashval_t hash; - tem = (loc->dtprel << 8) | ((unsigned int) loc->dw_loc_opc); + tem = (loc->dw_loc_dtprel << 8) | ((unsigned int) loc->dw_loc_opc); CHECKSUM (tem); hash_loc_operands (loc, hstate); hash = hstate.end(); @@ -7259,7 +7259,7 @@ loc_checksum_ordered (dw_loc_descr_ref loc, struct md5_ctx *ctx) inchash::hash hstate; hashval_t hash; - CHECKSUM_ULEB128 (loc->dtprel); + CHECKSUM_ULEB128 (loc->dw_loc_dtprel); CHECKSUM_ULEB128 (loc->dw_loc_opc); hash_loc_operands (loc, hstate); hash = hstate.end (); @@ -18310,7 +18310,7 @@ resolve_args_picking_1 (dw_loc_descr_ref loc, unsigned initial_frame_offset, /* If needed, relocate the picking offset with respect to the frame offset. */ - if (l->frame_offset_rel) + if (l->dw_loc_frame_offset_rel) { unsigned HOST_WIDE_INT off; switch (l->dw_loc_opc) @@ -18826,7 +18826,7 @@ loc_list_from_tree_1 (tree loc, int want_address, && want_address == 0) { ret = new_loc_descr (DW_OP_pick, 0, 0); - ret->frame_offset_rel = 1; + ret->dw_loc_frame_offset_rel = 1; context->placeholder_seen = true; break; } @@ -18993,7 +18993,7 @@ loc_list_from_tree_1 (tree loc, int want_address, gcc_assert (cursor != NULL_TREE); ret = new_loc_descr (DW_OP_pick, i, 0); - ret->frame_offset_rel = 1; + ret->dw_loc_frame_offset_rel = 1; break; } /* FALLTHRU */ @@ -31061,7 +31061,7 @@ resolve_addr_in_expr (dw_attr_node *a, dw_loc_descr_ref loc) || loc->dw_loc_opc == DW_OP_addrx) || ((loc->dw_loc_opc == DW_OP_GNU_const_index || loc->dw_loc_opc == DW_OP_constx) - && loc->dtprel)) + && loc->dw_loc_dtprel)) { rtx rtl = loc->dw_loc_oprnd1.val_entry->addr.rtl; if (!resolve_one_addr (&rtl)) @@ -31073,7 +31073,7 @@ resolve_addr_in_expr (dw_attr_node *a, dw_loc_descr_ref loc) break; case DW_OP_const4u: case DW_OP_const8u: - if (loc->dtprel + if (loc->dw_loc_dtprel && !resolve_one_addr (&loc->dw_loc_oprnd1.v.val_addr)) return false; break; @@ -31359,8 +31359,12 @@ copy_deref_exprloc (dw_loc_descr_ref expr) while (expr != l) { *p = new_loc_descr (expr->dw_loc_opc, 0, 0); - (*p)->dw_loc_oprnd1 = expr->dw_loc_oprnd1; - (*p)->dw_loc_oprnd2 = expr->dw_loc_oprnd2; + (*p)->dw_loc_oprnd1.val_class = expr->dw_loc_oprnd1.val_class; + (*p)->dw_loc_oprnd1.val_entry = expr->dw_loc_oprnd1.val_entry; + (*p)->dw_loc_oprnd1.v = expr->dw_loc_oprnd1.v; + (*p)->dw_loc_oprnd2.val_class = expr->dw_loc_oprnd2.val_class; + (*p)->dw_loc_oprnd2.val_entry = expr->dw_loc_oprnd2.val_entry; + (*p)->dw_loc_oprnd2.v = expr->dw_loc_oprnd2.v; p = &(*p)->dw_loc_next; expr = expr->dw_loc_next; } @@ -31451,7 +31455,9 @@ optimize_string_length (dw_attr_node *a) copy over the DW_AT_location attribute from die to a. */ if (l->dw_loc_next != NULL) { - a->dw_attr_val = av->dw_attr_val; + a->dw_attr_val.val_class = av->dw_attr_val.val_class; + a->dw_attr_val.val_entry = av->dw_attr_val.val_entry; + a->dw_attr_val.v = av->dw_attr_val.v; return 1; } @@ -31737,7 +31743,7 @@ hash_loc_operands (dw_loc_descr_ref loc, inchash::hash &hstate) { case DW_OP_const4u: case DW_OP_const8u: - if (loc->dtprel) + if (loc->dw_loc_dtprel) goto hash_addr; /* FALLTHRU */ case DW_OP_const1u: @@ -31839,7 +31845,7 @@ hash_loc_operands (dw_loc_descr_ref loc, inchash::hash &hstate) break; case DW_OP_addr: hash_addr: - if (loc->dtprel) + if (loc->dw_loc_dtprel) { unsigned char dtprel = 0xd1; hstate.add_object (dtprel); @@ -31851,7 +31857,7 @@ hash_loc_operands (dw_loc_descr_ref loc, inchash::hash &hstate) case DW_OP_GNU_const_index: case DW_OP_constx: { - if (loc->dtprel) + if (loc->dw_loc_dtprel) { unsigned char dtprel = 0xd1; hstate.add_object (dtprel); @@ -31998,7 +32004,7 @@ compare_loc_operands (dw_loc_descr_ref x, dw_loc_descr_ref y) { case DW_OP_const4u: case DW_OP_const8u: - if (x->dtprel) + if (x->dw_loc_dtprel) goto hash_addr; /* FALLTHRU */ case DW_OP_const1u: @@ -32162,7 +32168,7 @@ compare_locs (dw_loc_descr_ref x, dw_loc_descr_ref y) { for (; x != NULL && y != NULL; x = x->dw_loc_next, y = y->dw_loc_next) if (x->dw_loc_opc != y->dw_loc_opc - || x->dtprel != y->dtprel + || x->dw_loc_dtprel != y->dw_loc_dtprel || !compare_loc_operands (x, y)) break; return x == NULL && y == NULL; diff --git a/gcc/dwarf2out.h b/gcc/dwarf2out.h index fe50956..a0b0fa4 100644 --- a/gcc/dwarf2out.h +++ b/gcc/dwarf2out.h @@ -276,6 +276,25 @@ typedef struct GTY(()) dw_loc_list_struct { struct GTY(()) dw_val_node { enum dw_val_class val_class; + /* On 64-bit host, there are 4 bytes of padding between val_class + and val_entry. Reuse the padding for other content of + dw_loc_descr_node and dw_attr_struct. */ + union dw_val_node_parent + { + struct dw_val_loc_descr_node + { + ENUM_BITFIELD (dwarf_location_atom) dw_loc_opc_v : 8; + /* Used to distinguish DW_OP_addr with a direct symbol relocation + from DW_OP_addr with a dtp-relative symbol relocation. */ + unsigned int dw_loc_dtprel_v : 1; + /* For DW_OP_pick, DW_OP_dup and DW_OP_over operations: true iff. + it targets a DWARF prodecure argument. In this case, it needs to be + relocated according to the current frame offset. */ + unsigned int dw_loc_frame_offset_rel_v : 1; + } u1; + int u2; + enum dwarf_attribute u3; + } GTY((skip)) u; struct addr_table_entry * GTY(()) val_entry; union dw_val_struct_union { @@ -321,15 +340,15 @@ struct GTY(()) dw_val_node { struct GTY((chain_next ("%h.dw_loc_next"))) dw_loc_descr_node { dw_loc_descr_ref dw_loc_next; - ENUM_BITFIELD (dwarf_location_atom) dw_loc_opc : 8; +#define dw_loc_opc dw_loc_oprnd1.u.u1.dw_loc_opc_v /* Used to distinguish DW_OP_addr with a direct symbol relocation from DW_OP_addr with a dtp-relative symbol relocation. */ - unsigned int dtprel : 1; +#define dw_loc_dtprel dw_loc_oprnd1.u.u1.dw_loc_dtprel_v /* For DW_OP_pick, DW_OP_dup and DW_OP_over operations: true iff. it targets a DWARF prodecure argument. In this case, it needs to be relocated according to the current frame offset. */ - unsigned int frame_offset_rel : 1; - int dw_loc_addr; +#define dw_loc_frame_offset_rel dw_loc_oprnd1.u.u1.dw_loc_frame_offset_rel_v +#define dw_loc_addr dw_loc_oprnd2.u.u2 dw_val_node dw_loc_oprnd1; dw_val_node dw_loc_oprnd2; }; @@ -493,7 +512,7 @@ void dwarf2out_cc_finalize (void); Attributes are typically linked below the DIE they modify. */ typedef struct GTY(()) dw_attr_struct { - enum dwarf_attribute dw_attr; +#define dw_attr dw_attr_val.u.u3 dw_val_node dw_attr_val; } dw_attr_node; diff --git a/gcc/flag-types.h b/gcc/flag-types.h index db57376..9a3cc4a 100644 --- a/gcc/flag-types.h +++ b/gcc/flag-types.h @@ -404,8 +404,7 @@ enum lto_partition_model { LTO_PARTITION_BALANCED = 2, LTO_PARTITION_1TO1 = 3, LTO_PARTITION_MAX = 4, - LTO_PARTITION_CACHE = 5, - LTO_PARTITION_DEFAULT= 6 + LTO_PARTITION_CACHE = 5 }; /* flag_lto_locality_cloning initialization values. */ diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index bda22d1..7c6a415 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,13 @@ +2025-04-23 Andre Vehreschild <vehre@gcc.gnu.org> + + PR fortran/119200 + * check.cc (gfc_check_lcobound): Use locus from intrinsic_where. + (gfc_check_image_index): Same. + (gfc_check_num_images): Same. + (gfc_check_team_number): Same. + (gfc_check_this_image): Same. + (gfc_check_ucobound): Same. + 2025-04-22 Andre Vehreschild <vehre@gcc.gnu.org> * match.cc (match_exit_cycle): Allow to exit team block. diff --git a/gcc/ipa-cp.cc b/gcc/ipa-cp.cc index abde64b..b4b9699 100644 --- a/gcc/ipa-cp.cc +++ b/gcc/ipa-cp.cc @@ -4639,7 +4639,7 @@ update_counts_for_self_gen_clones (cgraph_node *orig_node, const vec<cgraph_node *> &self_gen_clones) { profile_count redist_sum = orig_node->count.ipa (); - if (!(redist_sum > profile_count::zero ())) + if (!redist_sum.nonzero_p ()) return; if (dump_file) @@ -4710,7 +4710,7 @@ update_counts_for_self_gen_clones (cgraph_node *orig_node, it. */ for (cgraph_node *n : self_gen_clones) { - if (!(n->count.ipa () > profile_count::zero ())) + if (!n->count.ipa ().nonzero_p ()) continue; desc_incoming_count_struct desc; @@ -4756,7 +4756,7 @@ update_profiling_info (struct cgraph_node *orig_node, profile_count new_sum; profile_count remainder, orig_node_count = orig_node->count.ipa (); - if (!(orig_node_count > profile_count::zero ())) + if (!orig_node_count.nonzero_p ()) return; if (dump_file) @@ -4920,7 +4920,7 @@ update_specialized_profile (struct cgraph_node *new_node, orig_node_count.dump (dump_file); fprintf (dump_file, "\n"); } - if (!(orig_node_count > profile_count::zero ())) + if (!orig_node_count.nonzero_p ()) return; new_node_count = new_node->count; diff --git a/gcc/m2/ChangeLog b/gcc/m2/ChangeLog index eeb5f66..5290f7c 100644 --- a/gcc/m2/ChangeLog +++ b/gcc/m2/ChangeLog @@ -1,3 +1,39 @@ +2025-04-24 Gaius Mulley <gaiusmod2@gmail.com> + + PR modula2/119915 + * gm2-libs/FormatStrings.mod (PerformFormatString): Handle + the %u and %x format specifiers in a similar way to the %d + specifier. Avoid using Slice and use Copy instead. + +2025-04-24 Gaius Mulley <gaiusmod2@gmail.com> + + PR modula2/119914 + * gm2-compiler/M2Check.mod (checkConstMeta): Add check for + Ztype, Rtype and Ctype and unbounded arrays. + (IsZRCType): New procedure function. + (isZRC): Add comment. + * gm2-compiler/M2Quads.mod: + * gm2-compiler/M2Range.mod (gdbinit): New procedure. + (BreakWhenRangeCreated): Ditto. + (CheckBreak): Ditto. + (InitRange): Call CheckBreak. + (Init): Add gdbhook and initialize interactive watch point. + * gm2-compiler/SymbolTable.def (GetNthParamAnyClosest): New + procedure function. + * gm2-compiler/SymbolTable.mod (BreakSym): Remove constant. + (BreakSym): Add Variable. + (stop): Remove. + (gdbhook): New procedure. + (BreakWhenSymCreated): Ditto. + (CheckBreak): Ditto. + (NewSym): Call CheckBreak. + (Init): Add gdbhook and initialize interactive watch point. + (MakeProcedure): Replace guarded call to stop with CheckBreak. + (GetNthParamChoice): New procedure function. + (GetNthParamOrdered): Ditto. + (GetNthParamAnyClosest): Ditto. + (GetOuterModuleScope): Ditto. + 2025-04-11 Gaius Mulley <gaiusmod2@gmail.com> PR modula2/119735 diff --git a/gcc/m2/gm2-libs/FormatStrings.mod b/gcc/m2/gm2-libs/FormatStrings.mod index ec2985b..aea8da9 100644 --- a/gcc/m2/gm2-libs/FormatStrings.mod +++ b/gcc/m2/gm2-libs/FormatStrings.mod @@ -378,7 +378,7 @@ BEGIN THEN INC (afterperc) ; Cast (u, w) ; - in := ConCat (in, Slice (fmt, startpos, nextperc)) ; + in := Copy (fmt, in, startpos, nextperc) ; in := ConCat (in, CardinalToString (u, width, leader, 16, TRUE)) ; startpos := afterperc ; DSdbExit (NIL) ; @@ -387,7 +387,7 @@ BEGIN THEN INC (afterperc) ; Cast (u, w) ; - in := ConCat (in, Slice (fmt, startpos, nextperc)) ; + in := Copy (fmt, in, startpos, nextperc) ; in := ConCat (in, CardinalToString (u, width, leader, 10, FALSE)) ; startpos := afterperc ; DSdbExit (NIL) ; diff --git a/gcc/opts.cc b/gcc/opts.cc index 5e7b77d..ffcbdfe 100644 --- a/gcc/opts.cc +++ b/gcc/opts.cc @@ -1047,9 +1047,9 @@ validate_ipa_reorder_locality_lto_partition (struct gcc_options *opts, { static bool validated_p = false; - if (opts->x_flag_lto_partition != LTO_PARTITION_DEFAULT) + if (opts_set->x_flag_lto_partition) { - if (opts_set->x_flag_ipa_reorder_for_locality && !validated_p) + if (opts->x_flag_ipa_reorder_for_locality && !validated_p) error ("%<-fipa-reorder-for-locality%> is incompatible with" " an explicit %qs option", "-flto-partition"); } @@ -1269,8 +1269,6 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set, SET_OPTION_IF_UNSET (opts, opts_set, flag_reorder_functions, 1); validate_ipa_reorder_locality_lto_partition (opts, opts_set); - if (opts_set->x_flag_lto_partition != LTO_PARTITION_DEFAULT) - opts_set->x_flag_lto_partition = opts->x_flag_lto_partition = LTO_PARTITION_BALANCED; /* The -gsplit-dwarf option requires -ggnu-pubnames. */ if (opts->x_dwarf_split_debug_info) diff --git a/gcc/po/ChangeLog b/gcc/po/ChangeLog index b1537f7..96da438 100644 --- a/gcc/po/ChangeLog +++ b/gcc/po/ChangeLog @@ -1,3 +1,11 @@ +2025-04-23 Joseph Myers <josmyers@redhat.com> + + * gcc.pot: Regenerate. + +2025-04-23 Joseph Myers <josmyers@redhat.com> + + * sv.po: Update. + 2025-04-09 Joseph Myers <josmyers@redhat.com> * de.po: Update. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index af49263..47666a9 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,97 @@ +2025-04-24 Jakub Jelinek <jakub@redhat.com> + Stefan Schulze Frielinghaus <stefansf@gcc.gnu.org> + + PR target/119873 + * gcc.target/s390/pr119873-1.c: New test. + * gcc.target/s390/pr119873-2.c: New test. + * gcc.target/s390/pr119873-3.c: New test. + * gcc.target/s390/pr119873-4.c: New test. + +2025-04-24 Robert Dubner <rdubner@symas.com> + + * cobol.dg/group1/declarative_1.cob: Adjust for repaired exception logic. + +2025-04-24 Jan Hubicka <hubicka@ucw.cz> + + * gcc.target/i386/pr119919.c: New test. + +2025-04-24 Richard Sandiford <richard.sandiford@arm.com> + + PR target/119610 + * g++.dg/torture/pr119610.C: New test. + * g++.target/aarch64/sve/pr119610-sve.C: Likewise. + +2025-04-24 Jakub Jelinek <jakub@redhat.com> + + PR c++/110343 + * gcc.dg/raw-string-1.c: New test. + +2025-04-24 Kyrylo Tkachov <ktkachov@nvidia.com> + + * gcc.dg/completion-2.c: Remove check for default. + +2025-04-24 Gaius Mulley <gaiusmod2@gmail.com> + + PR modula2/119915 + * gm2/pimlib/run/pass/format2.mod: New test. + +2025-04-24 liuhongt <hongtao.liu@intel.com> + + * gcc.target/i386/avx512vl-pr103750-1.c: New test. + * gcc.target/i386/avx512f-pr96891-3.c: Adjust testcase. + * gcc.target/i386/avx512f-vpcmpgtuq-1.c: Ditto. + * gcc.target/i386/avx512vl-vpcmpeqq-1.c: Ditto. + * gcc.target/i386/avx512vl-vpcmpequq-1.c: Ditto. + * gcc.target/i386/avx512vl-vpcmpgeq-1.c: Ditto. + * gcc.target/i386/avx512vl-vpcmpgeuq-1.c: Ditto. + * gcc.target/i386/avx512vl-vpcmpgtq-1.c: Ditto. + * gcc.target/i386/avx512vl-vpcmpgtuq-1.c: Ditto. + * gcc.target/i386/avx512vl-vpcmpleq-1.c: Ditto. + * gcc.target/i386/avx512vl-vpcmpleuq-1.c: Ditto. + * gcc.target/i386/avx512vl-vpcmpltq-1.c: Ditto. + * gcc.target/i386/avx512vl-vpcmpltuq-1.c: Ditto. + * gcc.target/i386/avx512vl-vpcmpneqq-1.c: Ditto. + * gcc.target/i386/avx512vl-vpcmpnequq-1.c: Ditto. + +2025-04-24 Gaius Mulley <gaiusmod2@gmail.com> + + PR modula2/119914 + * gm2/pim/fail/constintarraybyte.mod: New test. + +2025-04-23 Dimitar Dimitrov <dimitar@dinux.eu> + + * g++.dg/no-stack-protector-attr-3.C: Require effective target + fstack_protector. + +2025-04-23 Jan Hubicka <hubicka@ucw.cz> + + * gcc.dg/ipa/ipa-clone-4.c: New file. + * gcc.dg/tree-prof/ipa-cp-1.c: New file. + +2025-04-23 Christophe Lyon <christophe.lyon@linaro.org> + + PR target/71233 + * gcc.target/aarch64/advsimd-intrinsics/vld1x2.c: Enable on arm. + * gcc.target/aarch64/advsimd-intrinsics/vld1x3.c: Likewise. + * gcc.target/aarch64/advsimd-intrinsics/vld1x4.c: Likewise. + * gcc.target/aarch64/advsimd-intrinsics/vst1x2.c: Likewise. + * gcc.target/aarch64/advsimd-intrinsics/vst1x3.c: Likewise. + * gcc.target/aarch64/advsimd-intrinsics/vst1x4.c: Likewise. + +2025-04-23 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE> + + * g++.dg/eh/pr119507.C: Skip on sparc*-*-solaris2* && !gas. + +2025-04-23 Tamar Christina <tamar.christina@arm.com> + + PR target/119286 + * gcc.dg/vect/vect-early-break_38.c: Force -march=gfx908 for amdgcn. + +2025-04-23 liuhongt <hongtao.liu@intel.com> + + * gcc.target/i386/blendv-to-maxmin.c: New test. + * gcc.target/i386/blendv-to-pand.c: New test. + 2025-04-22 Jan Hubicka <hubicka@ucw.cz> * gcc.target/i386/pr89618-2.c: XFAIL. diff --git a/gcc/testsuite/cobol.dg/group1/declarative_1.cob b/gcc/testsuite/cobol.dg/group1/declarative_1.cob index 744495a..ec68e9c 100644 --- a/gcc/testsuite/cobol.dg/group1/declarative_1.cob +++ b/gcc/testsuite/cobol.dg/group1/declarative_1.cob @@ -1,14 +1,14 @@ *> { dg-do run } *> { dg-output {Turning EC\-ALL CHECKING OFF \-\- Expecting \+00\.00 from ACOS\(\-3\)(\n|\r\n|\r)} } -*> { dg-output { \+00\.00 TABL\(VSIX\) is 6(\n|\r\n|\r)} } +*> { dg-output { \+00\.00 TABL\(VSIX\) is 1(\n|\r\n|\r)} } *> { dg-output {Turning EC\-ARGUMENT\-FUNCTION CHECKING ON(\n|\r\n|\r)} } *> { dg-output { Expecting \+0\.00 and DECLARATIVE FOR EC\-ARGUMENT\-FUNCTION(\n|\r\n|\r)} } *> { dg-output { DECLARATIVE FOR EC\-ARGUMENT\-FUNCTION(\n|\r\n|\r)} } -*> { dg-output { \+00\.00 TABL\(VSIX\) is 6(\n|\r\n|\r)} } +*> { dg-output { \+00\.00 TABL\(VSIX\) is 1(\n|\r\n|\r)} } *> { dg-output {Turning EC\-ARGUMENT CHECKING ON(\n|\r\n|\r)} } *> { dg-output { Expecting \+0\.00 and DECLARATIVE FOR EC\-ARGUMENT\-FUNCTION(\n|\r\n|\r)} } *> { dg-output { DECLARATIVE FOR EC\-ARGUMENT\-FUNCTION(\n|\r\n|\r)} } -*> { dg-output { \+00\.00 TABL\(VSIX\) is 6(\n|\r\n|\r)} } +*> { dg-output { \+00\.00 TABL\(VSIX\) is 1(\n|\r\n|\r)} } *> { dg-output {Turning EC\-ALL CHECKING ON(\n|\r\n|\r)} } *> { dg-output { Expecting \+0\.00 and DECLARATIVE EC\-ARGUMENT\-FUNCTION(\n|\r\n|\r)} } *> { dg-output { Followed by DECLARATIVE EC\-ALL for TABL\(6\) access(\n|\r\n|\r)} } diff --git a/gcc/testsuite/g++.dg/torture/pr119610.C b/gcc/testsuite/g++.dg/torture/pr119610.C new file mode 100644 index 0000000..9998026 --- /dev/null +++ b/gcc/testsuite/g++.dg/torture/pr119610.C @@ -0,0 +1,18 @@ +// { dg-do run } +// { dg-additional-options "-fstack-protector-strong" { target fstack_protector } } +// { dg-additional-options "-fstack-clash-protection" { target supports_stack_clash_protection } } + +int *ptr; +void foo() { + int c[1024*128]; + ptr = c; + throw 1; +} +int main() +{ + try { + foo(); + } catch(int x) { + return 0; + } +} diff --git a/gcc/testsuite/g++.target/aarch64/sve/pr119610-sve.C b/gcc/testsuite/g++.target/aarch64/sve/pr119610-sve.C new file mode 100644 index 0000000..0044e51 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/pr119610-sve.C @@ -0,0 +1,20 @@ +// { dg-do run { target aarch64_sve_hw } } +// { dg-additional-options "-fstack-protector-strong" { target fstack_protector } } +// { dg-additional-options "-fstack-clash-protection" { target supports_stack_clash_protection } } + +void *a_ptr, *b_ptr; +void foo() { + __SVInt32_t a; + int b[1024*128]; + a_ptr = &a; + b_ptr = b; + throw 1; +} +int main() +{ + try { + foo(); + } catch(int x) { + return 0; + } +} diff --git a/gcc/testsuite/gcc.dg/completion-2.c b/gcc/testsuite/gcc.dg/completion-2.c index 46c511c..99e6531 100644 --- a/gcc/testsuite/gcc.dg/completion-2.c +++ b/gcc/testsuite/gcc.dg/completion-2.c @@ -5,7 +5,6 @@ -flto-partition=1to1 -flto-partition=balanced -flto-partition=cache --flto-partition=default -flto-partition=max -flto-partition=none -flto-partition=one diff --git a/gcc/testsuite/gcc.dg/raw-string-1.c b/gcc/testsuite/gcc.dg/raw-string-1.c new file mode 100644 index 0000000..77d6145 --- /dev/null +++ b/gcc/testsuite/gcc.dg/raw-string-1.c @@ -0,0 +1,25 @@ +/* PR c++/110343 */ +/* { dg-do compile } */ +/* { dg-options "-std=gnu23" } */ + +const void *s0 = R"0123456789abcdefg()0123456789abcdefg" 0; + /* { dg-error "raw string delimiter longer" "longer" { target *-*-* } .-1 } */ + /* { dg-error "stray" "stray" { target *-*-* } .-2 } */ +const void *s1 = R" () " 0; + /* { dg-error "invalid character" "invalid" { target *-*-* } .-1 } */ + /* { dg-error "stray" "stray" { target *-*-* } .-2 } */ +const void *s2 = R" () " 0; + /* { dg-error "invalid character" "invalid" { target *-*-* } .-1 } */ + /* { dg-error "stray" "stray" { target *-*-* } .-2 } */ +const void *s3 = R")())" 0; + /* { dg-error "invalid character" "invalid" { target *-*-* } .-1 } */ + /* { dg-error "stray" "stray" { target *-*-* } .-2 } */ +const char *s4 = R"@()@"; +const char *s5 = R"$()$"; +const char *s6 = R"`()`"; +const void *s7 = R"\u0040()\u0040" 0; + /* { dg-error "invalid character" "invalid" { target *-*-* } .-1 } */ + /* { dg-error "stray" "stray" { target *-*-* } .-2 } */ +const char *s8 = R"`@$$@`@`$()`@$$@`@`$"; + +int main () {} diff --git a/gcc/testsuite/gcc.target/i386/pr119919.c b/gcc/testsuite/gcc.target/i386/pr119919.c new file mode 100644 index 0000000..ed64656 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr119919.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -msse2 -fdump-tree-vect-details" } */ +int a[9*9]; +bool b[9]; +void test() +{ + for (int i = 0; i < 9; i++) + { + b[i] = a[i*9] != 0; + } +} + +/* { dg-final { scan-tree-dump "loop vectorized using 8 byte vectors" "vect" } } */ diff --git a/gcc/testsuite/gcc.target/s390/pr119873-1.c b/gcc/testsuite/gcc.target/s390/pr119873-1.c new file mode 100644 index 0000000..7a9a988 --- /dev/null +++ b/gcc/testsuite/gcc.target/s390/pr119873-1.c @@ -0,0 +1,11 @@ +/* PR target/119873 */ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +const char *foo (void *, void *, void *, void *, unsigned long, unsigned long); + +const char * +bar (void *a, void *b, void *c, void *d, unsigned long e, unsigned long f) +{ + [[gnu::musttail]] return foo (a, b, c, d, e, f); +} diff --git a/gcc/testsuite/gcc.target/s390/pr119873-2.c b/gcc/testsuite/gcc.target/s390/pr119873-2.c new file mode 100644 index 0000000..f275253 --- /dev/null +++ b/gcc/testsuite/gcc.target/s390/pr119873-2.c @@ -0,0 +1,17 @@ +/* PR target/119873 */ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +const char *foo (void *, void *, void *, void *, unsigned long, unsigned long); + +const char * +bar (void *a, void *b, void *c, void *d, unsigned long e, unsigned long f) +{ + [[gnu::musttail]] return foo (a, b, c, d, e + 1, f); /* { dg-error "cannot tail-call: target is not able to optimize the call into a sibling call" } */ +} + +const char * +baz (void *a, void *b, void *c, void *d, unsigned long e, unsigned long f) +{ + [[gnu::musttail]] return foo (a, b, c, d, f, e); /* { dg-error "cannot tail-call: target is not able to optimize the call into a sibling call" } */ +} diff --git a/gcc/testsuite/gcc.target/s390/pr119873-3.c b/gcc/testsuite/gcc.target/s390/pr119873-3.c new file mode 100644 index 0000000..048fcaa --- /dev/null +++ b/gcc/testsuite/gcc.target/s390/pr119873-3.c @@ -0,0 +1,27 @@ +/* PR target/119873 */ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +extern int foo (int, int, int, long long, int); + +int +bar (int u, int v, int w, long long x, int y) +{ + [[gnu::musttail]] return foo (u, v, w, x, y); +} + +extern int baz (int, int, int, int, int); + +int +qux (int u, int v, int w, int x, int y) +{ + [[gnu::musttail]] return baz (u, v, w, x, y); +} + +extern int corge (int, int, int, int, unsigned short); + +int +garply (int u, int v, int w, int x, unsigned short y) +{ + [[gnu::musttail]] return corge (u, v, w, x, y); +} diff --git a/gcc/testsuite/gcc.target/s390/pr119873-4.c b/gcc/testsuite/gcc.target/s390/pr119873-4.c new file mode 100644 index 0000000..384170c --- /dev/null +++ b/gcc/testsuite/gcc.target/s390/pr119873-4.c @@ -0,0 +1,27 @@ +/* PR target/119873 */ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +extern int foo (int, int, int, long long, int); + +int +bar (int u, int v, int w, long long x, int y) +{ + [[gnu::musttail]] return foo (u, v, w, x + 1, y - 1); /* { dg-error "cannot tail-call: target is not able to optimize the call into a sibling call" } */ +} + +extern int baz (int, int, int, int, int); + +int +qux (int u, int v, int w, int x, int y) +{ + [[gnu::musttail]] return baz (u, v, w, x, y + 1); /* { dg-error "cannot tail-call: target is not able to optimize the call into a sibling call" } */ +} + +extern int corge (int, int, int, int, unsigned short); + +int +garply (int u, int v, int w, int x, unsigned short y) +{ + [[gnu::musttail]] return corge (u, v, w, x, y + 1); /* { dg-error "cannot tail-call: target is not able to optimize the call into a sibling call" } */ +} diff --git a/gcc/testsuite/gm2/pimlib/run/pass/format2.mod b/gcc/testsuite/gm2/pimlib/run/pass/format2.mod new file mode 100644 index 0000000..2ad6a8c --- /dev/null +++ b/gcc/testsuite/gm2/pimlib/run/pass/format2.mod @@ -0,0 +1,63 @@ +MODULE format2; + +FROM libc IMPORT exit, printf ; +FROM Terminal IMPORT Write, WriteLn; +FROM NumberIO IMPORT WriteCard; +FROM DynamicStrings IMPORT String, Length, char, InitString; +FROM FormatStrings IMPORT Sprintf1; + +PROCEDURE WriteString (s: String); +VAR + l, i: CARDINAL; +BEGIN + l := Length (s) ; + i := 0 ; + WHILE i < l DO + Write (char (s, i)) ; + INC (i) + END +END WriteString; + + +(* + assert - +*) + +PROCEDURE assert (cond: BOOLEAN; line: CARDINAL; file: ARRAY OF CHAR) ; +BEGIN + IF NOT cond + THEN + printf ("%s:%d assertion failed\n", file, line); + exit (1) + END +END assert ; + + +VAR + n: CARDINAL; + r, s: String; +BEGIN + n := 2; + r := InitString("%u pieces of cake") ; + WriteString (r) ; WriteLn ; + assert (Length (r) = 17, __LINE__, __FILE__) ; + s := Sprintf1 (r, n) ; + WriteCard (Length (s), 4) ; WriteLn ; + assert (Length (s) = 16, __LINE__, __FILE__) ; + + r := InitString("%d pieces of cake") ; + WriteString (r) ; WriteLn ; + assert (Length (r) = 17, __LINE__, __FILE__) ; + s := Sprintf1 (r, n) ; + WriteCard (Length (s), 4) ; WriteLn ; + assert (Length (s) = 16, __LINE__, __FILE__) ; + + r := InitString("%x pieces of cake") ; + WriteString (r) ; WriteLn ; + assert (Length (r) = 17, __LINE__, __FILE__) ; + s := Sprintf1 (r, n) ; + WriteCard (Length (s), 4) ; WriteLn ; + assert (Length (s) = 16, __LINE__, __FILE__) ; + + WriteString (InitString ('all tests pass')) ; WriteLn ; +END format2. diff --git a/libcpp/ChangeLog b/libcpp/ChangeLog index 353227a..775b000 100644 --- a/libcpp/ChangeLog +++ b/libcpp/ChangeLog @@ -1,3 +1,9 @@ +2025-04-24 Jakub Jelinek <jakub@redhat.com> + + PR c++/110343 + * lex.cc (lex_raw_string): For C allow $@` in raw string delimiters + if CPP_OPTION (pfile, low_ucns) i.e. for C23 and later. + 2025-04-09 Jakub Jelinek <jakub@redhat.com> PR preprocessor/118674 diff --git a/libcpp/lex.cc b/libcpp/lex.cc index 2d02ce6..e7705a6 100644 --- a/libcpp/lex.cc +++ b/libcpp/lex.cc @@ -2711,8 +2711,9 @@ lex_raw_string (cpp_reader *pfile, cpp_token *token, const uchar *base) || c == '!' || c == '=' || c == ',' || c == '"' || c == '\'' || ((c == '$' || c == '@' || c == '`') - && CPP_OPTION (pfile, cplusplus) - && CPP_OPTION (pfile, lang) > CLK_CXX23))) + && (CPP_OPTION (pfile, cplusplus) + ? CPP_OPTION (pfile, lang) > CLK_CXX23 + : CPP_OPTION (pfile, low_ucns))))) prefix[prefix_len++] = c; else { diff --git a/libgm2/ChangeLog b/libgm2/ChangeLog index fb9920e..51a8e38 100644 --- a/libgm2/ChangeLog +++ b/libgm2/ChangeLog @@ -1,3 +1,44 @@ +2025-04-24 Gaius Mulley <gaiusmod2@gmail.com> + + PR modula2/115276 + * config.h.in: Regenerate. + * configure: Regenerate. + * configure.ac (AC_STRUCT_TIMEZONE): Add. + (AC_CHECK_MEMBER): Test for struct tm.tm_year. + (AC_CHECK_MEMBER): Test for struct tm.tm_mon. + (AC_CHECK_MEMBER): Test for struct tm.tm_mday. + (AC_CHECK_MEMBER): Test for struct tm.tm_hour. + (AC_CHECK_MEMBER): Test for struct tm.tm_min. + (AC_CHECK_MEMBER): Test for struct tm.tm_sec. + (AC_CHECK_MEMBER): Test for struct tm.tm_year. + (AC_CHECK_MEMBER): Test for struct tm.tm_yday. + (AC_CHECK_MEMBER): Test for struct tm.tm_wday. + (AC_CHECK_MEMBER): Test for struct tm.tm_isdst. + (AC_CHECK_MEMBER): Test for struct timeval.tv_sec. + (AC_CHECK_MEMBER): Test for struct timeval.tv_sec. + (AC_CHECK_MEMBER): Test for struct timeval.tv_usec. + * libm2iso/wraptime.cc (InitTimeval): Guard against lack + struct timeval and malloc. + (InitTimezone): Guard against lack of struct tm.tm_zone + and malloc. + (KillTimezone): Ditto. + (InitTimeval): Guard against lack of struct timeval + and malloc. + (KillTimeval): Guard against lack of malloc. + (settimeofday): Guard against lack of struct tm.tm_zone. + (GetFractions): Guard against lack of struct timeval. + (localtime_r): Ditto. + (GetYear): Guard against lack of struct tm. + (GetMonth): Ditto. + (GetDay): Ditto. + (GetHour): Ditto. + (GetMinute): Ditto. + (GetSecond): Ditto. + (GetSummerTime): Ditto. + (GetDST): Guards against lack of struct timezone. + (SetTimezone): Ditto. + (SetTimeval): Guard against lack of struct tm. + 2025-03-28 Gaius Mulley <gaiusmod2@gmail.com> PR modula2/118045 diff --git a/libgm2/config.h.in b/libgm2/config.h.in index 321ef3b..f9710ff 100644 --- a/libgm2/config.h.in +++ b/libgm2/config.h.in @@ -34,6 +34,10 @@ */ #undef HAVE_DECL_GETENV +/* Define to 1 if you have the declaration of `tzname', and to 0 if you don't. + */ +#undef HAVE_DECL_TZNAME + /* Define to 1 if you have the <direct.h> header file. */ #undef HAVE_DIRECT_H @@ -232,6 +236,9 @@ /* Define to 1 if the system has the type `struct tm'. */ #undef HAVE_STRUCT_TM +/* Define to 1 if `tm_zone' is a member of `struct tm'. */ +#undef HAVE_STRUCT_TM_TM_ZONE + /* Define to 1 if you have the <sys/errno.h> header file. */ #undef HAVE_SYS_ERRNO_H @@ -286,6 +293,10 @@ /* Define if struct tm has a tm_gmtoff field. */ #undef HAVE_TM_TM_GMTOFF +/* Define to 1 if your `struct tm' has `tm_zone'. Deprecated, use + `HAVE_STRUCT_TM_TM_ZONE' instead. */ +#undef HAVE_TM_ZONE + /* function tzname exists */ #undef HAVE_TZNAME @@ -338,6 +349,9 @@ /* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */ #undef TIME_WITH_SYS_TIME +/* Define to 1 if your <sys/time.h> declares `struct tm'. */ +#undef TM_IN_SYS_TIME + /* Enable extensions on AIX 3, Interix. */ #ifndef _ALL_SOURCE # undef _ALL_SOURCE @@ -363,6 +377,45 @@ /* Version number of package */ #undef VERSION +/* struct timeval was found */ +#undef WE_HAVE_STRUCT_TIMEVAL + +/* struct timeval.tv_sec was found */ +#undef WE_HAVE_STRUCT_TIMEVAL_TV_SEC + +/* struct timeval.tv_usec was found */ +#undef WE_HAVE_STRUCT_TIMEVAL_TV_USEC + +/* struct tm was found */ +#undef WE_HAVE_STRUCT_TM + +/* struct tm.tm_hour was found */ +#undef WE_HAVE_STRUCT_TM_HOUR + +/* struct tm.tm_isdst was found */ +#undef WE_HAVE_STRUCT_TM_ISDST + +/* struct tm.tm_mday was found */ +#undef WE_HAVE_STRUCT_TM_MDAY + +/* struct tm.tm_min was found */ +#undef WE_HAVE_STRUCT_TM_MIN + +/* struct tm.tm_mon was found */ +#undef WE_HAVE_STRUCT_TM_MON + +/* struct tm.tm_sec was found */ +#undef WE_HAVE_STRUCT_TM_SEC + +/* struct tm.tm_wday was found */ +#undef WE_HAVE_STRUCT_TM_WDAY + +/* struct tm.tm_yday was found */ +#undef WE_HAVE_STRUCT_TM_YDAY + +/* struct tm.tm_year was found */ +#undef WE_HAVE_STRUCT_TM_YEAR + /* Defined if no way to sleep is available. */ #undef _GLIBCXX_NO_SLEEP diff --git a/libgm2/configure b/libgm2/configure index efe3b66..8ffdb31 100755 --- a/libgm2/configure +++ b/libgm2/configure @@ -2100,6 +2100,109 @@ $as_echo "$ac_res" >&6; } } # ac_fn_cxx_check_func +# ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES +# ---------------------------------------------------- +# Tries to find if the field MEMBER exists in type AGGR, after including +# INCLUDES, setting cache variable VAR accordingly. +ac_fn_c_check_member () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5 +$as_echo_n "checking for $2.$3... " >&6; } +if eval \${$4+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$5 +int +main () +{ +static $2 ac_aggr; +if (ac_aggr.$3) +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$4=yes" +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$5 +int +main () +{ +static $2 ac_aggr; +if (sizeof ac_aggr.$3) +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$4=yes" +else + eval "$4=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$4 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_member + +# ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES +# --------------------------------------------- +# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR +# accordingly. +ac_fn_c_check_decl () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + as_decl_name=`echo $2|sed 's/ *(.*//'` + as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 +$as_echo_n "checking whether $as_decl_name is declared... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +#ifndef $as_decl_name +#ifdef __cplusplus + (void) $as_decl_use; +#else + (void) $as_decl_name; +#endif +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_decl + # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. @@ -2269,52 +2372,6 @@ $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_type - -# ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES -# --------------------------------------------- -# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR -# accordingly. -ac_fn_c_check_decl () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - as_decl_name=`echo $2|sed 's/ *(.*//'` - as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 -$as_echo_n "checking whether $as_decl_name is declared... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main () -{ -#ifndef $as_decl_name -#ifdef __cplusplus - (void) $as_decl_use; -#else - (void) $as_decl_name; -#endif -#endif - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - eval "$3=yes" -else - eval "$3=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_check_decl cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. @@ -6872,6 +6929,7 @@ $as_echo "#define TIME_WITH_SYS_TIME 1" >>confdefs.h fi + ac_fn_c_check_header_mongrel "$LINENO" "math.h" "ac_cv_header_math_h" "$ac_includes_default" if test "x$ac_cv_header_math_h" = xyes; then : @@ -6903,6 +6961,223 @@ fi done +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether struct tm is in sys/time.h or time.h" >&5 +$as_echo_n "checking whether struct tm is in sys/time.h or time.h... " >&6; } +if ${ac_cv_struct_tm+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <sys/types.h> +#include <time.h> + +int +main () +{ +struct tm tm; + int *p = &tm.tm_sec; + return !p; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_struct_tm=time.h +else + ac_cv_struct_tm=sys/time.h +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_tm" >&5 +$as_echo "$ac_cv_struct_tm" >&6; } +if test $ac_cv_struct_tm = sys/time.h; then + +$as_echo "#define TM_IN_SYS_TIME 1" >>confdefs.h + +fi + +ac_fn_c_check_member "$LINENO" "struct tm" "tm_zone" "ac_cv_member_struct_tm_tm_zone" "#include <sys/types.h> +#include <$ac_cv_struct_tm> + +" +if test "x$ac_cv_member_struct_tm_tm_zone" = xyes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_TM_TM_ZONE 1 +_ACEOF + + +fi + +if test "$ac_cv_member_struct_tm_tm_zone" = yes; then + +$as_echo "#define HAVE_TM_ZONE 1" >>confdefs.h + +else + ac_fn_c_check_decl "$LINENO" "tzname" "ac_cv_have_decl_tzname" "#include <time.h> +" +if test "x$ac_cv_have_decl_tzname" = xyes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_TZNAME $ac_have_decl +_ACEOF + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tzname" >&5 +$as_echo_n "checking for tzname... " >&6; } +if ${ac_cv_var_tzname+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <time.h> +#if !HAVE_DECL_TZNAME +extern char *tzname[]; +#endif + +int +main () +{ +return tzname[0][0]; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_var_tzname=yes +else + ac_cv_var_tzname=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_var_tzname" >&5 +$as_echo "$ac_cv_var_tzname" >&6; } + if test $ac_cv_var_tzname = yes; then + +$as_echo "#define HAVE_TZNAME 1" >>confdefs.h + + fi +fi + + +ac_fn_c_check_member "$LINENO" "struct tm" "tm_year" "ac_cv_member_struct_tm_tm_year" "#include <time.h> +" +if test "x$ac_cv_member_struct_tm_tm_year" = xyes; then : + +$as_echo "#define WE_HAVE_STRUCT_TM 1" >>confdefs.h + +fi + +ac_fn_c_check_member "$LINENO" "struct tm" "tm_year" "ac_cv_member_struct_tm_tm_year" "#include <time.h> +" +if test "x$ac_cv_member_struct_tm_tm_year" = xyes; then : + +$as_echo "#define WE_HAVE_STRUCT_TM_YEAR 1" >>confdefs.h + +fi + +ac_fn_c_check_member "$LINENO" "struct tm" "tm_mon" "ac_cv_member_struct_tm_tm_mon" "#include <time.h> +" +if test "x$ac_cv_member_struct_tm_tm_mon" = xyes; then : + +$as_echo "#define WE_HAVE_STRUCT_TM_MON 1" >>confdefs.h + +fi + +ac_fn_c_check_member "$LINENO" "struct tm" "tm_mday" "ac_cv_member_struct_tm_tm_mday" "#include <time.h> +" +if test "x$ac_cv_member_struct_tm_tm_mday" = xyes; then : + +$as_echo "#define WE_HAVE_STRUCT_TM_MDAY 1" >>confdefs.h + +fi + +ac_fn_c_check_member "$LINENO" "struct tm" "tm_hour" "ac_cv_member_struct_tm_tm_hour" "#include <time.h> +" +if test "x$ac_cv_member_struct_tm_tm_hour" = xyes; then : + +$as_echo "#define WE_HAVE_STRUCT_TM_HOUR 1" >>confdefs.h + +fi + +ac_fn_c_check_member "$LINENO" "struct tm" "tm_min" "ac_cv_member_struct_tm_tm_min" "#include <time.h> +" +if test "x$ac_cv_member_struct_tm_tm_min" = xyes; then : + +$as_echo "#define WE_HAVE_STRUCT_TM_MIN 1" >>confdefs.h + +fi + +ac_fn_c_check_member "$LINENO" "struct tm" "tm_sec" "ac_cv_member_struct_tm_tm_sec" "#include <time.h> +" +if test "x$ac_cv_member_struct_tm_tm_sec" = xyes; then : + +$as_echo "#define WE_HAVE_STRUCT_TM_SEC 1" >>confdefs.h + +fi + +ac_fn_c_check_member "$LINENO" "struct tm" "tm_year" "ac_cv_member_struct_tm_tm_year" "#include <time.h> +" +if test "x$ac_cv_member_struct_tm_tm_year" = xyes; then : + +$as_echo "#define WE_HAVE_STRUCT_TM_YEAR 1" >>confdefs.h + +fi + +ac_fn_c_check_member "$LINENO" "struct tm" "tm_yday" "ac_cv_member_struct_tm_tm_yday" "#include <time.h> +" +if test "x$ac_cv_member_struct_tm_tm_yday" = xyes; then : + +$as_echo "#define WE_HAVE_STRUCT_TM_YDAY 1" >>confdefs.h + +fi + +ac_fn_c_check_member "$LINENO" "struct tm" "tm_wday" "ac_cv_member_struct_tm_tm_wday" "#include <time.h> +" +if test "x$ac_cv_member_struct_tm_tm_wday" = xyes; then : + +$as_echo "#define WE_HAVE_STRUCT_TM_WDAY 1" >>confdefs.h + +fi + +ac_fn_c_check_member "$LINENO" "struct tm" "tm_isdst" "ac_cv_member_struct_tm_tm_isdst" "#include <time.h> +" +if test "x$ac_cv_member_struct_tm_tm_isdst" = xyes; then : + +$as_echo "#define WE_HAVE_STRUCT_TM_ISDST 1" >>confdefs.h + +fi + + +ac_fn_c_check_member "$LINENO" "struct timeval" "tv_sec" "ac_cv_member_struct_timeval_tv_sec" "$ac_includes_default" +if test "x$ac_cv_member_struct_timeval_tv_sec" = xyes; then : + +$as_echo "#define WE_HAVE_STRUCT_TIMEVAL 1" >>confdefs.h + +fi + +ac_fn_c_check_member "$LINENO" "struct timeval" "tv_sec" "ac_cv_member_struct_timeval_tv_sec" "$ac_includes_default" +if test "x$ac_cv_member_struct_timeval_tv_sec" = xyes; then : + +$as_echo "#define WE_HAVE_STRUCT_TIMEVAL_TV_SEC 1" >>confdefs.h + +fi + +ac_fn_c_check_member "$LINENO" "struct timeval" "tv_usec" "ac_cv_member_struct_timeval_tv_usec" "$ac_includes_default" +if test "x$ac_cv_member_struct_timeval_tv_usec" = xyes; then : + +$as_echo "#define WE_HAVE_STRUCT_TIMEVAL_TV_USEC 1" >>confdefs.h + +fi + + case ${build_alias} in "") build_noncanonical=${build} ;; @@ -14579,7 +14854,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 14582 "configure" +#line 14857 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -14685,7 +14960,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 14688 "configure" +#line 14963 "configure" #include "confdefs.h" #if HAVE_DLFCN_H diff --git a/libgm2/configure.ac b/libgm2/configure.ac index c070491..437485f 100644 --- a/libgm2/configure.ac +++ b/libgm2/configure.ac @@ -89,6 +89,7 @@ AC_ARG_WITH(cross-host, AC_HEADER_STDC AC_HEADER_SYS_WAIT AC_HEADER_TIME + AC_CHECK_HEADER([math.h], [AC_DEFINE([HAVE_MATH_H], [1], [have math.h])]) @@ -102,6 +103,49 @@ AC_CHECK_HEADERS(getopt.h limits.h stddef.h string.h strings.h \ pthread.h stdarg.h stdio.h sys/types.h termios.h \ netinet/in.h netdb.h sys/uio.h sys/stat.h wchar.h) +AC_STRUCT_TIMEZONE + +AC_CHECK_MEMBER([struct tm.tm_year], + [AC_DEFINE(WE_HAVE_STRUCT_TM, [1], [struct tm was found])], + [], [[#include <time.h>]]) +AC_CHECK_MEMBER([struct tm.tm_year], + [AC_DEFINE(WE_HAVE_STRUCT_TM_YEAR, [1], [struct tm.tm_year was found])], + [], [[#include <time.h>]]) +AC_CHECK_MEMBER([struct tm.tm_mon], + [AC_DEFINE(WE_HAVE_STRUCT_TM_MON, [1], [struct tm.tm_mon was found])], + [], [[#include <time.h>]]) +AC_CHECK_MEMBER([struct tm.tm_mday], + [AC_DEFINE(WE_HAVE_STRUCT_TM_MDAY, [1], [struct tm.tm_mday was found])], + [], [[#include <time.h>]]) +AC_CHECK_MEMBER([struct tm.tm_hour], + [AC_DEFINE(WE_HAVE_STRUCT_TM_HOUR, [1], [struct tm.tm_hour was found])], + [], [[#include <time.h>]]) +AC_CHECK_MEMBER([struct tm.tm_min], + [AC_DEFINE(WE_HAVE_STRUCT_TM_MIN, [1], [struct tm.tm_min was found])], + [], [[#include <time.h>]]) +AC_CHECK_MEMBER([struct tm.tm_sec], + [AC_DEFINE(WE_HAVE_STRUCT_TM_SEC, [1], [struct tm.tm_sec was found])], + [], [[#include <time.h>]]) +AC_CHECK_MEMBER([struct tm.tm_year], + [AC_DEFINE(WE_HAVE_STRUCT_TM_YEAR, [1], [struct tm.tm_year was found])], + [], [[#include <time.h>]]) +AC_CHECK_MEMBER([struct tm.tm_yday], + [AC_DEFINE(WE_HAVE_STRUCT_TM_YDAY, [1], [struct tm.tm_yday was found])], + [], [[#include <time.h>]]) +AC_CHECK_MEMBER([struct tm.tm_wday], + [AC_DEFINE(WE_HAVE_STRUCT_TM_WDAY, [1], [struct tm.tm_wday was found])], + [], [[#include <time.h>]]) +AC_CHECK_MEMBER([struct tm.tm_isdst], + [AC_DEFINE(WE_HAVE_STRUCT_TM_ISDST, [1], [struct tm.tm_isdst was found])], + [], [[#include <time.h>]]) + +AC_CHECK_MEMBER([struct timeval.tv_sec], + [AC_DEFINE(WE_HAVE_STRUCT_TIMEVAL, [1], [struct timeval was found])]) +AC_CHECK_MEMBER([struct timeval.tv_sec], + [AC_DEFINE(WE_HAVE_STRUCT_TIMEVAL_TV_SEC, [1], [struct timeval.tv_sec was found])]) +AC_CHECK_MEMBER([struct timeval.tv_usec], + [AC_DEFINE(WE_HAVE_STRUCT_TIMEVAL_TV_USEC, [1], [struct timeval.tv_usec was found])]) + AC_CANONICAL_HOST ACX_NONCANONICAL_HOST ACX_NONCANONICAL_TARGET diff --git a/libgm2/libm2iso/wraptime.cc b/libgm2/libm2iso/wraptime.cc index 4bbd5f9..ed5f05e 100644 --- a/libgm2/libm2iso/wraptime.cc +++ b/libgm2/libm2iso/wraptime.cc @@ -58,7 +58,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see /* InitTimeval returns a newly created opaque type. */ -#if defined(HAVE_STRUCT_TIMEVAL) && defined(HAVE_MALLOC_H) +#if defined(WE_HAVE_STRUCT_TIMEVAL) && defined(HAVE_MALLOC_H) extern "C" struct timeval * EXPORT(InitTimeval) (void) { @@ -85,7 +85,7 @@ EXPORT(KillTimeval) (void *tv) /* InitTimezone returns a newly created opaque type. */ -#if defined(HAVE_STRUCT_TIMEZONE) && defined(HAVE_MALLOC_H) +#if defined(HAVE_STRUCT_TM_TM_ZONE) && defined(HAVE_MALLOC_H) extern "C" struct timezone * EXPORT(InitTimezone) (void) { @@ -102,14 +102,20 @@ EXPORT(InitTimezone) (void) /* KillTimezone - deallocates the memory associated with an opaque type. */ +#if defined(HAVE_STRUCT_TM_TM_ZONE) && defined(HAVE_MALLOC_H) extern "C" struct timezone * EXPORT(KillTimezone) (struct timezone *tv) { -#if defined(HAVE_MALLOC_H) free (tv); -#endif return NULL; } +#else +extern "C" void * +EXPORT(KillTimezone) (void *tv) +{ + return NULL; +} +#endif /* InitTM - returns a newly created opaque type. */ @@ -141,7 +147,7 @@ EXPORT(KillTM) (struct tm *tv) /* gettimeofday - calls gettimeofday(2) with the same parameters, tv, and, tz. It returns 0 on success. */ -#if defined(HAVE_STRUCT_TIMEZONE) && defined(HAVE_GETTIMEOFDAY) +#if defined(HAVE_STRUCT_TM_TM_ZONE) && defined(HAVE_GETTIMEOFDAY) extern "C" int EXPORT(gettimeofday) (void *tv, struct timezone *tz) { @@ -158,7 +164,7 @@ EXPORT(gettimeofday) (void *tv, void *tz) /* settimeofday - calls settimeofday(2) with the same parameters, tv, and, tz. It returns 0 on success. */ -#if defined(HAVE_STRUCT_TIMEZONE) && defined(HAVE_SETTIMEOFDAY) +#if defined(HAVE_STRUCT_TM_TM_ZONE) && defined(HAVE_SETTIMEOFDAY) extern "C" int EXPORT(settimeofday) (void *tv, struct timezone *tz) { @@ -175,7 +181,7 @@ EXPORT(settimeofday) (void *tv, void *tz) /* wraptime_GetFractions - returns the tv_usec field inside the timeval structure. */ -#if defined(HAVE_STRUCT_TIMEVAL) +#if defined(WE_HAVE_STRUCT_TIMEVAL_TV_USEC) extern "C" unsigned int EXPORT(GetFractions) (struct timeval *tv) { @@ -194,7 +200,7 @@ EXPORT(GetFractions) (void *tv) this procedure function expects, timeval, as its first parameter and not a time_t (as expected by the posix equivalent). */ -#if defined(HAVE_STRUCT_TIMEVAL) +#if defined(WE_HAVE_STRUCT_TIMEVAL_TV_SEC) extern "C" struct tm * EXPORT(localtime_r) (struct timeval *tv, struct tm *m) { @@ -210,7 +216,7 @@ EXPORT(localtime_r) (void *tv, struct tm *m) /* wraptime_GetYear - returns the year from the structure, m. */ -#if defined(HAVE_STRUCT_TM) +#if defined(WE_HAVE_STRUCT_TM_YEAR) extern "C" unsigned int EXPORT(GetYear) (struct tm *m) { @@ -226,7 +232,7 @@ EXPORT(GetYear) (void *m) /* wraptime_GetMonth - returns the month from the structure, m. */ -#if defined(HAVE_STRUCT_TM) +#if defined(WE_HAVE_STRUCT_TM_MON) extern "C" unsigned int EXPORT(GetMonth) (struct tm *m) { @@ -243,7 +249,7 @@ EXPORT(GetMonth) (void *m) /* wraptime_GetDay - returns the day of the month from the structure, m. */ -#if defined(HAVE_STRUCT_TM) +#if defined(WE_HAVE_STRUCT_TM_MDAY) extern "C" unsigned int EXPORT(GetDay) (struct tm *m) { @@ -260,7 +266,7 @@ EXPORT(GetDay) (void *m) /* wraptime_GetHour - returns the hour of the day from the structure, m. */ -#if defined(HAVE_STRUCT_TM) +#if defined(WE_HAVE_STRUCT_TM_HOUR) extern "C" unsigned int EXPORT(GetHour) (struct tm *m) { @@ -277,7 +283,7 @@ EXPORT(GetHour) (void *m) /* wraptime_GetMinute - returns the minute within the hour from the structure, m. */ -#if defined(HAVE_STRUCT_TM) +#if defined(WE_HAVE_STRUCT_TM_MIN) extern "C" unsigned int EXPORT(GetMinute) (struct tm *m) { @@ -295,7 +301,7 @@ EXPORT(GetMinute) (void *m) structure, m. The return value will always be in the range 0..59. A leap minute of value 60 will be truncated to 59. */ -#if defined(HAVE_STRUCT_TM) +#if defined(WE_HAVE_STRUCT_TM_SEC) extern "C" unsigned int EXPORT(GetSecond) (struct tm *m) { @@ -314,7 +320,7 @@ EXPORT(GetSecond) (void *m) /* wraptime_GetSummerTime - returns true if summer time is in effect. */ -#if defined(HAVE_STRUCT_TIMEZONE) +#if defined(HAVE_STRUCT_TM_TM_ZONE) extern "C" bool EXPORT(GetSummerTime) (struct timezone *tz) { @@ -330,7 +336,7 @@ EXPORT(GetSummerTime) (void *tz) /* wraptime_GetDST - returns the number of minutes west of GMT. */ -#if defined(HAVE_STRUCT_TIMEZONE) +#if defined(HAVE_STRUCT_TM_TM_ZONE) extern "C" int EXPORT(GetDST) (struct timezone *tz) { @@ -350,7 +356,7 @@ EXPORT(GetDST) (void *tz) /* SetTimezone - set the timezone field inside timeval, tv. */ -#if defined(HAVE_STRUCT_TIMEZONE) +#if defined(HAVE_STRUCT_TM_TM_ZONE) extern "C" void EXPORT(SetTimezone) (struct timezone *tz, int zone, int minuteswest) { @@ -367,22 +373,40 @@ EXPORT(SetTimezone) (void *tz, int zone, int minuteswest) /* SetTimeval - sets the fields in tm, t, with: second, minute, hour, day, month, year, fractions. */ -#if defined(HAVE_STRUCT_TIMEVAL) +#if defined(WE_HAVE_STRUCT_TM) extern "C" void EXPORT(SetTimeval) (struct tm *t, unsigned int second, unsigned int minute, unsigned int hour, unsigned int day, unsigned int month, unsigned int year, unsigned int yday, unsigned int wday, unsigned int isdst) { +#if defined(WE_HAVE_STRUCT_TM_SEC) t->tm_sec = second; +#endif +#if defined(WE_HAVE_STRUCT_TM_MIN) t->tm_min = minute; +#endif +#if defined(WE_HAVE_STRUCT_TM_HOUR) t->tm_hour = hour; +#endif +#if defined(WE_HAVE_STRUCT_TM_MDAY) t->tm_mday = day; +#endif +#if defined(WE_HAVE_STRUCT_TM_MON) t->tm_mon = month; +#endif +#if defined(WE_HAVE_STRUCT_TM_YEAR) t->tm_year = year; +#endif +#if defined(WE_HAVE_STRUCT_TM_YDAY) t->tm_yday = yday; +#endif +#if defined(WE_HAVE_STRUCT_TM_WDAY) t->tm_wday = wday; +#endif +#if defined(WE_HAVE_STRUCT_TM_ISDST) t->tm_isdst = isdst; +#endif } #else extern "C" void diff --git a/libgomp/ChangeLog b/libgomp/ChangeLog index 096e17b..49a62d4 100644 --- a/libgomp/ChangeLog +++ b/libgomp/ChangeLog @@ -1,3 +1,53 @@ +2025-04-24 Tobias Burnus <tburnus@baylibre.com> + + * testsuite/lib/libgomp.exp + (check_effective_target_gomp_hip_header_nvidia): Compile with + "-Wno-deprecated-declarations". + * testsuite/libgomp.c/interop-hip-nvidia-full.c: Likewise. + * testsuite/libgomp.c/interop-hipblas-nvidia-full.c: Likewise. + * testsuite/libgomp.c/interop-hipblas.h: Add workarounds + when using the HIP headers with __HIP_PLATFORM_NVIDIA__. + +2025-04-24 Tobias Burnus <tburnus@baylibre.com> + + * testsuite/lib/libgomp.exp (check_effective_target_openacc_cublas, + check_effective_target_openacc_cudart): Update description as + the check requires more. + (check_effective_target_openacc_libcuda, + check_effective_target_openacc_libcublas, + check_effective_target_openacc_libcudart, + check_effective_target_gomp_hip_header_amd, + check_effective_target_gomp_hip_header_nvidia, + check_effective_target_gomp_hipfort_module, + check_effective_target_gomp_libamdhip64, + check_effective_target_gomp_libhipblas): New. + * testsuite/libgomp.c-c++-common/interop-2.c: New test. + * testsuite/libgomp.c/interop-cublas-full.c: New test. + * testsuite/libgomp.c/interop-cublas-libonly.c: New test. + * testsuite/libgomp.c/interop-cuda-full.c: New test. + * testsuite/libgomp.c/interop-cuda-libonly.c: New test. + * testsuite/libgomp.c/interop-hip-amd-full.c: New test. + * testsuite/libgomp.c/interop-hip-amd-no-hip-header.c: New test. + * testsuite/libgomp.c/interop-hip-nvidia-full.c: New test. + * testsuite/libgomp.c/interop-hip-nvidia-no-headers.c: New test. + * testsuite/libgomp.c/interop-hip-nvidia-no-hip-header.c: New test. + * testsuite/libgomp.c/interop-hip.h: New test. + * testsuite/libgomp.c/interop-hipblas-amd-full.c: New test. + * testsuite/libgomp.c/interop-hipblas-amd-no-hip-header.c: New test. + * testsuite/libgomp.c/interop-hipblas-nvidia-full.c: New test. + * testsuite/libgomp.c/interop-hipblas-nvidia-no-headers.c: New test. + * testsuite/libgomp.c/interop-hipblas-nvidia-no-hip-header.c: New test. + * testsuite/libgomp.c/interop-hipblas.h: New test. + * testsuite/libgomp.fortran/interop-hip-amd-full.F90: New test. + * testsuite/libgomp.fortran/interop-hip-amd-no-module.F90: New test. + * testsuite/libgomp.fortran/interop-hip-nvidia-full.F90: New test. + * testsuite/libgomp.fortran/interop-hip-nvidia-no-module.F90: New test. + * testsuite/libgomp.fortran/interop-hip.h: New test. + +2025-04-23 Tobias Burnus <tburnus@baylibre.com> + + * testsuite/libgomp.fortran/target-enter-data-8.f90: New test. + 2025-04-17 Jakub Jelinek <jakub@redhat.com> PR libgomp/119849 diff --git a/libgomp/testsuite/lib/libgomp.exp b/libgomp/testsuite/lib/libgomp.exp index bc38e3c..54f2f708 100644 --- a/libgomp/testsuite/lib/libgomp.exp +++ b/libgomp/testsuite/lib/libgomp.exp @@ -553,7 +553,23 @@ int main() { } } "-lcuda" ] } -# Return 1 if cublas_v2.h and -lcublas are available. +# Return 1 if -lcuda is available (header not required). + +proc check_effective_target_openacc_libcuda { } { + return [check_no_compiler_messages openacc_libcuda executable { +typedef enum { CUDA_SUCCESS } CUresult; +typedef int CUdevice; +CUresult cuDeviceGet (CUdevice *, int); +int main() { + CUdevice dev; + CUresult r = cuDeviceGet (&dev, 0); + if (r != CUDA_SUCCESS) + return 1; + return 0; +} } "-lcuda" ] +} + +# Return 1 if cublas_v2.h, cuda.h, -lcublas and -lcuda are available. proc check_effective_target_openacc_cublas { } { return [check_no_compiler_messages openacc_cublas executable { @@ -573,7 +589,25 @@ int main() { } } "-lcuda -lcublas" ] } -# Return 1 if cuda_runtime_api.h and -lcudart are available. +# Return 1 if -lcublas is available header not required). + +proc check_effective_target_openacc_libcublas { } { + return [check_no_compiler_messages openacc_libcublas executable { +typedef enum { CUBLAS_STATUS_SUCCESS } cublasStatus_t; +typedef struct cublasContext* cublasHandle_t; +#define cublasCreate cublasCreate_v2 +cublasStatus_t cublasCreate_v2 (cublasHandle_t *); +int main() { + cublasStatus_t s; + cublasHandle_t h; + s = cublasCreate (&h); + if (s != CUBLAS_STATUS_SUCCESS) + return 1; + return 0; +} } "-lcublas" ] +} + +# Return 1 if cuda_runtime_api.h, cuda.h, -lcuda and -lcudart are available. proc check_effective_target_openacc_cudart { } { return [check_no_compiler_messages openacc_cudart executable { @@ -592,3 +626,98 @@ int main() { return 0; } } "-lcuda -lcudart" ] } + +# Return 1 if -lcudart is available (no header required). + +proc check_effective_target_openacc_libcudart { } { + return [check_no_compiler_messages openacc_libcudart executable { +typedef int cudaError_t; +cudaError_t cudaGetDevice(int *); +enum { cudaSuccess }; +int main() { + cudaError_t e; + int devn; + e = cudaGetDevice (&devn); + if (e != cudaSuccess) + return 1; + return 0; +} } "-lcudart" ] +} + +# Return 1 if hip.h is available (no link check; AMD platform). + +proc check_effective_target_gomp_hip_header_amd { } { + return [check_no_compiler_messages gomp_hip_header_amd assembly { +#define __HIP_PLATFORM_AMD__ +#include <hip/hip_runtime_api.h> +int main() { + hipDevice_t dev; + hipError_t r = hipDeviceGet (&dev, 0); + if (r != hipSuccess) + return 1; + return 0; +} }] +} + +# Return 1 if hip.h is available (no link check; Nvidia/CUDA platform). + +proc check_effective_target_gomp_hip_header_nvidia { } { + return [check_no_compiler_messages gomp_hip_header_nvidia assembly { +#define __HIP_PLATFORM_NVIDIA__ +#include <hip/hip_runtime_api.h> +int main() { + hipDevice_t dev; + hipError_t r = hipDeviceGet (&dev, 0); + if (r != hipSuccess) + return 1; + return 0; +} } "-Wno-deprecated-declarations"] +} + +# Return 1 if the Fortran hipfort module is available (no link check) + +proc check_effective_target_gomp_hipfort_module { } { + return [check_no_compiler_messages gomp_hipfort_module assembly { +! Fortran +use hipfort +implicit none +integer(kind(hipSuccess)) :: r +integer(c_int) :: dev +r = hipDeviceGet (dev, 0) +if (r /= hipSuccess) error stop +end +}] +} + +# Return 1 if AMD HIP's -lamdhip64 is available (no header required). + +proc check_effective_target_gomp_libamdhip64 { } { + return [check_no_compiler_messages gomp_libamdhip64 executable { +typedef int hipError_t; +typedef int hipDevice_t; +enum { hipSuccess = 0 }; +hipError_t hipDeviceGet(hipDevice_t*, int); +int main() { + hipDevice_t dev; + hipError_t r = hipDeviceGet (&dev, 0); + if (r != hipSuccess) + return 1; + return 0; +} } "-lamdhip64" ] +} + +# Return 1 if AMD HIP's -lamdhip64 is available (no header required). + +proc check_effective_target_gomp_libhipblas { } { + return [check_no_compiler_messages gomp_libhipblas executable { +typedef enum { HIPBLAS_STATUS_SUCCESS = 0 } hipblasStatus_t; +typedef void* hipblasHandle_t; +hipblasStatus_t hipblasCreate (hipblasHandle_t*); +int main() { + hipblasHandle_t handle; + hipblasStatus_t stat = hipblasCreate (&handle); + if (stat != HIPBLAS_STATUS_SUCCESS) + return 1; + return 0; +} } "-lhipblas" ] +} diff --git a/libgomp/testsuite/libgomp.c-c++-common/interop-2.c b/libgomp/testsuite/libgomp.c-c++-common/interop-2.c new file mode 100644 index 0000000..a7526dc --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/interop-2.c @@ -0,0 +1,129 @@ +/* { dg-do run } */ +/* { dg-additional-options "-lm" } */ + +/* Note: At the time this program was written, Nvptx was not asynchronous + enough to trigger the issue (with a 'nowait' added); however, one + AMD GPUs, it triggered. */ + +/* Test whether nowait / dependency is handled correctly. + Motivated by OpenMP_VV's 5.1/interop/test_interop_target.c + + The code actually only creates a streaming object without actually using it, + except for dependency tracking. + + Note that there is a difference between having a steaming (targetsync) object + and not (= omp_interop_none); at least if one assumes that omp_interop_none + does not include 'targetsync' as (effective) interop type - in that case, + 'nowait' has no effect and the 'depend' is active as included task, otherwise + the code continues with the depend being active only for the about to be + destroyed or used thread. + + The OpenMP spec states (here 6.0): + "If the interop-type set includes 'targetsync', an empty mergeable task is + generated. If the 'nowait' clause is not present on the construct then + the task is also an included task. If the interop-type set does not + include 'targetsync', the 'nowait' clause has no effect. Any depend + clauses that are present on the construct apply to the generated task. */ + +#include <omp.h> + +void +test_async (const int dev) +{ + constexpr int N = 2048; + constexpr int ulp = 4; + constexpr double M_PI = 2.0 * __builtin_acos (0.0); + omp_interop_t obj1, obj2; + double A[N] = { }; + int B[N] = { }; + + /* Create interop object. */ + #pragma omp interop device(dev) init(targetsync : obj1, obj2) + + if (dev == omp_initial_device || dev == omp_get_num_devices ()) + { + if (obj1 != omp_interop_none || obj2 != omp_interop_none) + __builtin_abort (); + } + else + { + if (obj1 == omp_interop_none || obj2 == omp_interop_none) + __builtin_abort (); + } + + /* DOUBLE */ + + /* Now in the background update it, slowly enough that the + code afterwards is reached while still running asynchronously. + As OpenMP_VV's Issue #863 shows, the overhead is high enough to + fail even when only doing an atomic integer increment. */ + + #pragma omp target device(dev) map(A) depend(out: A[:N]) nowait + for (int i = 0; i < N; i++) + #pragma omp atomic update + A[i] += __builtin_sin (2*i*M_PI/N); + + /* DESTROY take care of the dependeny such that ... */ + + if (obj1 == omp_interop_none) + { + // Same as below as 'nowait' is ignored. + #pragma omp interop destroy(obj1) depend(in: A[:N]) nowait + } + else + { + #pragma omp interop destroy(obj1) depend(in: A[:N]) + } + + /* ... this code is only executed once the dependency as been fulfilled. */ + + /* Check the value - part I: quick, avoid A[0] == sin(0) = 0. */ + for (int i = 1; i < N; i++) + if (A[i] == 0.0) + __builtin_abort (); + + /* Check the value - part II: throughly */ + for (int i = 0; i < N; i++) + { + double x = A[i]; + double y = __builtin_sin (2*i*M_PI/N); + if (__builtin_fabs (x - y) > ulp * __builtin_fabs (x+y) * __DBL_EPSILON__) + __builtin_abort (); + } + + /* Integer */ + + #pragma omp target device(dev) map(B) depend(out: B[:N]) nowait + for (int i = 0; i < N; i++) + #pragma omp atomic update + B[i] += 42; + + /* Same - but using USE. */ + if (obj2 == omp_interop_none) + { + // Same as below as 'nowait' is ignored. + #pragma omp interop use(obj2) depend(in: B[:N]) nowait + } + else + { + #pragma omp interop use(obj2) depend(in: B[:N]) + } + + for (int i = 0; i < N; i++) + if (B[i] != 42) + __builtin_abort (); + + #pragma omp interop destroy(obj2) +} + +int +main () +{ + int ndev = omp_get_num_devices (); + + for (int dev = 0; dev <= ndev; dev++) + test_async (dev); + test_async (omp_initial_device); + + return 0; +} diff --git a/libgomp/testsuite/libgomp.c/interop-cublas-full.c b/libgomp/testsuite/libgomp.c/interop-cublas-full.c new file mode 100644 index 0000000..2df5277 --- /dev/null +++ b/libgomp/testsuite/libgomp.c/interop-cublas-full.c @@ -0,0 +1,176 @@ +/* { dg-require-effective-target openacc_cublas } */ +/* { dg-additional-options "-lcublas" } */ + +/* NOTE: This file is also included by libgomp.c-c++-common/interop-cudablas-libonly.c + to test the fallback version. */ + +/* Check whether cuBlas' daxpy works with an interop object. + daxpy(N, DA, DX, INCX, DY, INCY) + calculates (for DX = DY = 1): + DY(1:N) = DY(1:N) + DA * DX(1:N) + and otherwise N array elements, taking every INCX-th or INCY-th one, repectively. + +Based on the interop example in OpenMP's example document */ + +/* Minimal check whether CUDA works - by checking whether the API routines + seem to work. This includes a fallback if the header is not + available. */ + +#include <assert.h> +#include <omp.h> +#include "../libgomp.c-c++-common/on_device_arch.h" + + +#if __has_include(<cuda.h>) && __has_include(<cudaTypedefs.h>) && __has_include(<cuda_runtime.h>) && __has_include(<cublas_v2.h>) && !defined(USE_CUDA_FALLBACK_HEADER) + #include <cuda.h> + #include <cudaTypedefs.h> + #include <cuda_runtime.h> + #include <cublas_v2.h> + +#else + /* Add a poor man's fallback declaration. */ + #if USE_CUDA_FALLBACK_HEADER + // Don't warn. + #elif !__has_include(<cuda.h>) + #warning "Using GCC's cuda.h as fallback for cuda.h" + #elif !__has_include(<cudaTypedefs.h>) + #warning "Using GCC's cuda.h as fallback for cudaTypedefs.h" + #elif !__has_include(<cuda_runtime.h>) + #warning "Using GCC's cuda.h as fallback for cuda_runtime.h" + #else + #warning "Using GCC's cuda.h as fallback for cublas_v2.h" + #endif + #include "../../../include/cuda/cuda.h" + + typedef enum { + CUBLAS_STATUS_SUCCESS = 0, + } cublasStatus_t; + + typedef CUstream cudaStream_t; + typedef struct cublasContext* cublasHandle_t; + + #define cublasCreate cublasCreate_v2 + cublasStatus_t cublasCreate_v2 (cublasHandle_t *); + + #define cublasSetStream cublasSetStream_v2 + cublasStatus_t cublasSetStream_v2 (cublasHandle_t, cudaStream_t); + + #define cublasDaxpy cublasDaxpy_v2 + cublasStatus_t cublasDaxpy_v2(cublasHandle_t, int, const double*, const double*, int, double*, int); +#endif + +static int used_variant = 0; + +void +run_cuBlasdaxpy (int n, double da, const double *dx, int incx, double *dy, int incy, omp_interop_t obj) +{ + used_variant = 1; + + omp_interop_rc_t res; + cublasStatus_t stat; + + omp_intptr_t fr = omp_get_interop_int(obj, omp_ipr_fr_id, &res); + assert (res == omp_irc_success && fr == omp_ifr_cuda); + + cudaStream_t stream = (cudaStream_t) omp_get_interop_ptr (obj, omp_ipr_targetsync, &res); + assert (res == omp_irc_success); + + cublasHandle_t handle; + stat = cublasCreate (&handle); + assert (stat == CUBLAS_STATUS_SUCCESS); + + stat = cublasSetStream (handle, stream); + assert (stat == CUBLAS_STATUS_SUCCESS); + + /* 'da' can be in host or device space, 'dx' and 'dy' must be in device space. */ + stat = cublasDaxpy (handle, n, &da, dx, 1, dy, 1) ; + assert (stat == CUBLAS_STATUS_SUCCESS); +} + + +#pragma omp declare variant(run_cuBlasdaxpy) \ + match(construct={dispatch}, target_device={kind(nohost), arch("nvptx")}) \ + adjust_args(need_device_ptr : dx, dy) \ + append_args(interop(targetsync, prefer_type("cuda"))) + +void +run_daxpy (int n, double da, const double *dx, int incx, double *dy, int incy) +{ + used_variant = 2; + + if (incx == 1 && incy == 1) + #pragma omp simd + for (int i = 0; i < n; i++) + dy[i] += da * dx[i]; + else + { + int ix = 0; + int iy = 0; + for (int i = 0; i < n; i++) + { + dy[iy] += da * dx[ix]; + ix += incx; + iy += incy; + } + } +} + + +void +run_test (int dev) +{ + constexpr int N = 1024; + + // A = {1,2,...,N} + // B = {-1, -2, ..., N} + // B' = daxpy (N, 3, A, incx=1, B, incy=1) + // = B + 3*A + // -> B' = {0, 2, 4, 6, ... } + + double A[N], B[N]; + double factor = 3.0; + for (int i = 0; i < N; i++) + { + A[i] = i; + B[i] = -i; + } + + if (dev != omp_initial_device && dev != omp_get_num_devices ()) + { + #pragma omp target enter data device(dev) map(A, B) + } + + used_variant = 99; + #pragma omp dispatch device(dev) + run_daxpy (N, factor, A, 1, B, 1); + + if (dev != omp_initial_device && dev != omp_get_num_devices ()) + { + #pragma omp target exit data device(dev) map(release: A) map(from: B) + + int tmp = omp_get_default_device (); + omp_set_default_device (dev); + if (on_device_arch_nvptx ()) + assert (used_variant == 1); + else + assert (used_variant == 2); + omp_set_default_device (tmp); + } + else + assert (used_variant == 2); + + for (int i = 0; i < N; i++) + assert (B[i] == 2*i); +} + +int +main () +{ + int ndev = omp_get_num_devices (); + + for (int dev = 0; dev <= ndev; dev++) + run_test (dev); + run_test (omp_initial_device); + + return 0; +} diff --git a/libgomp/testsuite/libgomp.c/interop-cublas-libonly.c b/libgomp/testsuite/libgomp.c/interop-cublas-libonly.c new file mode 100644 index 0000000..89c0652 --- /dev/null +++ b/libgomp/testsuite/libgomp.c/interop-cublas-libonly.c @@ -0,0 +1,7 @@ +/* { dg-require-effective-target openacc_libcublas } */ +/* { dg-additional-options "-lcublas" } */ + +/* Same as interop-cudablas-full.c, but also works if the header is not available. */ + +#define USE_CUDA_FALLBACK_HEADER 1 +#include "interop-cublas-full.c" diff --git a/libgomp/testsuite/libgomp.c/interop-cuda-full.c b/libgomp/testsuite/libgomp.c/interop-cuda-full.c new file mode 100644 index 0000000..38aa6b1 --- /dev/null +++ b/libgomp/testsuite/libgomp.c/interop-cuda-full.c @@ -0,0 +1,159 @@ +/* { dg-require-effective-target openacc_cuda } */ +/* { dg-require-effective-target openacc_cudart } */ +/* { dg-additional-options "-lcuda -lcudart" } */ + +/* NOTE: This file is also included by libgomp.c-c++-common/interop-cuda-libonly.c + to test the fallback version, which defines USE_CUDA_FALLBACK_HEADER. */ + +/* Minimal check whether CUDA works - by checking whether the API routines + seem to work. This includes a fallback if the header is not + available. */ + +#include <assert.h> +#include <omp.h> + +#if __has_include(<cuda.h>) && __has_include(<cudaTypedefs.h>) && __has_include(<cuda_runtime.h>) && !defined(USE_CUDA_FALLBACK_HEADER) + #include <cuda.h> + #include <cudaTypedefs.h> + #include <cuda_runtime.h> + +#else + /* Add a poor man's fallback declaration. */ + #if USE_CUDA_FALLBACK_HEADER + // Don't warn. + #elif !__has_include(<cuda.h>) + #warning "Using GCC's cuda.h as fallback for cuda.h" + #elif !__has_include(<cudaTypedefs.h>) + #warning "Using GCC's cuda.h as fallback for cudaTypedefs.h" + #else + #warning "Using GCC's cuda.h as fallback for cuda_runtime.h" + #endif + #include "../../../include/cuda/cuda.h" + + typedef int cudaError_t; + typedef CUstream cudaStream_t; + enum { + cudaSuccess = 0 + }; + + enum cudaDeviceAttr { + cudaDevAttrClockRate = 13, + cudaDevAttrMaxGridDimX = 5 + }; + + cudaError_t cudaDeviceGetAttribute (int *, enum cudaDeviceAttr, int); + cudaError_t cudaStreamQuery(cudaStream_t); + CUresult cuCtxGetApiVersion(CUcontext, unsigned int *); + CUresult cuStreamGetCtx (CUstream, CUcontext *); +#endif + +int +main () +{ + int ivar; + unsigned uvar; + omp_interop_rc_t res; + omp_interop_t obj_cuda = omp_interop_none; + omp_interop_t obj_cuda_driver = omp_interop_none; + cudaError_t cuda_err; + CUresult cu_err; + + #pragma omp interop init(target, targetsync, prefer_type("cuda") : obj_cuda) \ + init(target, targetsync, prefer_type("cuda_driver") : obj_cuda_driver) \ + + omp_interop_fr_t fr = (omp_interop_fr_t) omp_get_interop_int (obj_cuda, omp_ipr_fr_id, &res); + assert (res == omp_irc_success); + assert (fr == omp_ifr_cuda); + + fr = (omp_interop_fr_t) omp_get_interop_int (obj_cuda_driver, omp_ipr_fr_id, &res); + assert (res == omp_irc_success); + assert (fr == omp_ifr_cuda_driver); + + ivar = (int) omp_get_interop_int (obj_cuda, omp_ipr_vendor, &res); + assert (res == omp_irc_success); + assert (ivar == 11); + + ivar = (int) omp_get_interop_int (obj_cuda_driver, omp_ipr_vendor, &res); + assert (res == omp_irc_success); + assert (ivar == 11); + + + /* Check whether the omp_ipr_device -> cudaDevice_t yields a valid device. */ + + CUdevice cu_dev = (int) omp_get_interop_int (obj_cuda_driver, omp_ipr_device, &res); + assert (res == omp_irc_success); + + /* Assume a clock size is available and > 1 GHz; value is in kHz. */ + cu_err = cuDeviceGetAttribute (&ivar, cudaDevAttrClockRate, cu_dev); + assert (cu_err == CUDA_SUCCESS); + assert (ivar > 1000000 /* kHz */); + + /* Assume that the MaxGridDimX is available and > 1024. */ + cu_err = cuDeviceGetAttribute (&ivar, cudaDevAttrMaxGridDimX, cu_dev); + assert (cu_err == CUDA_SUCCESS); + assert (ivar > 1024); + + int cuda_dev = (int) omp_get_interop_int (obj_cuda, omp_ipr_device, &res); + assert (res == omp_irc_success); + assert (cuda_dev == (CUdevice) cu_dev); // Assume they are the same ... + + /* Assume a clock size is available and > 1 GHz; value is in kHz. */ + cuda_err = cudaDeviceGetAttribute (&ivar, cudaDevAttrClockRate, cuda_dev); + assert (cuda_err == cudaSuccess); + assert (ivar > 1000000 /* kHz */); + + /* Assume that the MaxGridDimX is available and > 1024. */ + cuda_err = cudaDeviceGetAttribute (&ivar, cudaDevAttrMaxGridDimX, cuda_dev); + assert (cuda_err == cudaSuccess); + assert (ivar > 1024); + + + + + /* Check whether the omp_ipr_device_context -> CUcontext yields a context. */ + + CUcontext cu_ctx = (CUcontext) omp_get_interop_ptr (obj_cuda_driver, omp_ipr_device_context, &res); + assert (res == omp_irc_success); + + /* Assume API Version > 0 for Nvidia, cudaErrorNotSupported for AMD. */ + uvar = 99; + cu_err = cuCtxGetApiVersion (cu_ctx, &uvar); + assert (cu_err == CUDA_SUCCESS); + assert (uvar > 0); + + + /* Check whether the omp_ipr_targetsync -> cudaStream_t yields a stream. */ + + cudaStream_t cuda_sm = (cudaStream_t) omp_get_interop_ptr (obj_cuda, omp_ipr_targetsync, &res); + assert (res == omp_irc_success); + + CUstream cu_sm = (cudaStream_t) omp_get_interop_ptr (obj_cuda_driver, omp_ipr_targetsync, &res); + assert (res == omp_irc_success); + + assert ((void*) cu_sm != (void*) cuda_sm); // Type compatible but should have created two streams + + int dev_stream = 99; +#if CUDA_VERSION >= 12080 + cuda_err = cudaStreamGetDevice (cuda_sm, &dev_stream); + assert (cuda_err == cudaSuccess); +#else + cu_err = cuStreamGetCtx (cu_sm, &cu_ctx) != CUDA_SUCCESS; + if (cu_err == CUDA_SUCCESS) + cuda_err = cuCtxPushCurrent (cu_ctx) != CUDA_SUCCESS; + if (cu_err == CUDA_SUCCESS) + cuda_err = cuCtxGetDevice (&dev_stream) != CUDA_SUCCESS; + if (cu_err == CUDA_SUCCESS) + cu_err = cuCtxPopCurrent (&cu_ctx) != CUDA_SUCCESS; + assert (cu_err == CUDA_SUCCESS); +#endif + assert (dev_stream == cuda_dev); + + /* All jobs should have been completed (as there were none none) */ + cuda_err = cudaStreamQuery (cuda_sm); + assert (cuda_err == cudaSuccess); + + cu_err = cuStreamQuery (cu_sm); + assert (cu_err == CUDA_SUCCESS); + + #pragma omp interop destroy(obj_cuda, obj_cuda_driver) +} diff --git a/libgomp/testsuite/libgomp.c/interop-cuda-libonly.c b/libgomp/testsuite/libgomp.c/interop-cuda-libonly.c new file mode 100644 index 0000000..17cbb15 --- /dev/null +++ b/libgomp/testsuite/libgomp.c/interop-cuda-libonly.c @@ -0,0 +1,8 @@ +/* { dg-require-effective-target openacc_libcudart } */ +/* { dg-require-effective-target openacc_libcuda } */ +/* { dg-additional-options "-lcuda -lcudart" } */ + +/* Same as interop-cuda-full.c, but also works if the header is not available. */ + +#define USE_CUDA_FALLBACK_HEADER 1 +#include "interop-cuda-full.c" diff --git a/libgomp/testsuite/libgomp.c/interop-hip-amd-full.c b/libgomp/testsuite/libgomp.c/interop-hip-amd-full.c new file mode 100644 index 0000000..d7725fc --- /dev/null +++ b/libgomp/testsuite/libgomp.c/interop-hip-amd-full.c @@ -0,0 +1,7 @@ +/* { dg-require-effective-target gomp_hip_header_amd } */ +/* { dg-require-effective-target gomp_libamdhip64 } */ +/* { dg-additional-options "-lamdhip64" } */ + +#define __HIP_PLATFORM_AMD__ 1 + +#include "interop-hip.h" diff --git a/libgomp/testsuite/libgomp.c/interop-hip-amd-no-hip-header.c b/libgomp/testsuite/libgomp.c/interop-hip-amd-no-hip-header.c new file mode 100644 index 0000000..2584537 --- /dev/null +++ b/libgomp/testsuite/libgomp.c/interop-hip-amd-no-hip-header.c @@ -0,0 +1,8 @@ +/* { dg-require-effective-target gomp_libamdhip64 } */ +/* { dg-additional-options "-lamdhip64" } */ + +#define __HIP_PLATFORM_AMD__ 1 + +#define USE_HIP_FALLBACK_HEADER 1 + +#include "interop-hip.h" diff --git a/libgomp/testsuite/libgomp.c/interop-hip-nvidia-full.c b/libgomp/testsuite/libgomp.c/interop-hip-nvidia-full.c new file mode 100644 index 0000000..79af47d --- /dev/null +++ b/libgomp/testsuite/libgomp.c/interop-hip-nvidia-full.c @@ -0,0 +1,8 @@ +/* { dg-require-effective-target openacc_cudart } */ +/* { dg-require-effective-target openacc_cuda } */ +/* { dg-require-effective-target gomp_hip_header_nvidia } */ +/* { dg-additional-options "-lcuda -lcudart -Wno-deprecated-declarations" } */ + +#define __HIP_PLATFORM_NVIDIA__ 1 + +#include "interop-hip.h" diff --git a/libgomp/testsuite/libgomp.c/interop-hip-nvidia-no-headers.c b/libgomp/testsuite/libgomp.c/interop-hip-nvidia-no-headers.c new file mode 100644 index 0000000..4586398 --- /dev/null +++ b/libgomp/testsuite/libgomp.c/interop-hip-nvidia-no-headers.c @@ -0,0 +1,10 @@ +/* { dg-require-effective-target openacc_libcudart } */ +/* { dg-require-effective-target openacc_libcuda } */ +/* { dg-additional-options "-lcuda -lcudart" } */ + +#define __HIP_PLATFORM_NVIDIA__ 1 + +#define USE_HIP_FALLBACK_HEADER 1 +#define USE_CUDA_FALLBACK_HEADER 1 + +#include "interop-hip.h" diff --git a/libgomp/testsuite/libgomp.c/interop-hip-nvidia-no-hip-header.c b/libgomp/testsuite/libgomp.c/interop-hip-nvidia-no-hip-header.c new file mode 100644 index 0000000..4186984 --- /dev/null +++ b/libgomp/testsuite/libgomp.c/interop-hip-nvidia-no-hip-header.c @@ -0,0 +1,9 @@ +/* { dg-require-effective-target openacc_cudart } */ +/* { dg-require-effective-target openacc_cuda } */ +/* { dg-additional-options "-lcuda -lcudart" } */ + +#define __HIP_PLATFORM_NVIDIA__ 1 + +#define USE_HIP_FALLBACK_HEADER 1 + +#include "interop-hip.h" diff --git a/libgomp/testsuite/libgomp.c/interop-hip.h b/libgomp/testsuite/libgomp.c/interop-hip.h new file mode 100644 index 0000000..20a1ccb --- /dev/null +++ b/libgomp/testsuite/libgomp.c/interop-hip.h @@ -0,0 +1,234 @@ +/* Minimal check whether HIP works - by checking whether the API routines + seem to work. This includes various fallbacks if the header is not + available. */ + +#include <assert.h> +#include <omp.h> + +#if !defined(__HIP_PLATFORM_AMD__) && !defined(__HIP_PLATFORM_NVIDIA__) + #error "Either __HIP_PLATFORM_AMD__ or __HIP_PLATFORM_NVIDIA__ must be defined" +#endif + +#if defined(__HIP_PLATFORM_AMD__) && defined(__HIP_PLATFORM_NVIDIA__) + #error "Either __HIP_PLATFORM_AMD__ or __HIP_PLATFORM_NVIDIA__ must be defined" +#endif + +#if __has_include(<hip/hip_runtime_api.h>) && !defined(USE_HIP_FALLBACK_HEADER) + #include <hip/hip_runtime_api.h> + +#elif defined(__HIP_PLATFORM_AMD__) + /* Add a poor man's fallback declaration. */ + #if !defined(USE_HIP_FALLBACK_HEADER) + #warning "Using fallback declaration for <hip/hip_runtime_api.h> for __HIP_PLATFORM_AMD__" + #endif + + typedef struct ihipStream_t* hipStream_t; + typedef struct ihipCtx_t* hipCtx_t; + typedef int hipError_t; + typedef int hipDevice_t; + enum { + hipSuccess = 0, + hipErrorNotSupported = 801 + }; + + typedef enum hipDeviceAttribute_t { + hipDeviceAttributeClockRate = 5, + hipDeviceAttributeMaxGridDimX = 29 + } hipDeviceAttribute_t; + + hipError_t hipDeviceGetAttribute (int *, hipDeviceAttribute_t, hipDevice_t); + hipError_t hipCtxGetApiVersion (hipCtx_t, int *); + hipError_t hipStreamGetDevice (hipStream_t, hipDevice_t *); + hipError_t hipStreamQuery (hipStream_t); + +#elif defined(__HIP_PLATFORM_NVIDIA__) + /* Add a poor man's fallback declaration. */ + #if !defined(USE_HIP_FALLBACK_HEADER) + #warning "Using fallback declaration for <hip/hip_runtime_api.h> for __HIP_PLATFORM_NVIDIA__" + #endif + + #if __has_include(<cuda.h>) && __has_include(<cudaTypedefs.h>) && __has_include(<cuda_runtime.h>) && !defined(USE_CUDA_FALLBACK_HEADER) + #include <cuda.h> + #include <cudaTypedefs.h> + #include <cuda_runtime.h> + #else + #if defined(USE_CUDA_FALLBACK_HEADER) + // no warning + #elif !__has_include(<cuda.h>) + #warning "Using GCC's cuda.h as fallback for cuda.h" + #elif !__has_include(<cudaTypedefs.h>) + #warning "Using GCC's cuda.h as fallback for cudaTypedefs.h" + #else + #warning "Using GCC's cuda.h as fallback for cuda_runtime.h" + #endif + + #include "../../../include/cuda/cuda.h" + + typedef int cudaError_t; + enum { + cudaSuccess = 0 + }; + + enum cudaDeviceAttr { + cudaDevAttrClockRate = 13, + cudaDevAttrMaxGridDimX = 5 + }; + + cudaError_t cudaDeviceGetAttribute (int *, enum cudaDeviceAttr, int); + CUresult cuCtxGetApiVersion(CUcontext, unsigned int *); + CUresult cuStreamGetCtx (CUstream, CUcontext *); + #endif + + typedef CUstream hipStream_t; + typedef CUcontext hipCtx_t; + typedef CUdevice hipDevice_t; + + typedef int hipError_t; + typedef int hipDevice_t; + enum { + hipSuccess = 0, + hipErrorNotSupported = 801 + }; + + + typedef enum hipDeviceAttribute_t { + hipDeviceAttributeClockRate = 5, + hipDeviceAttributeMaxGridDimX = 29 + } hipDeviceAttribute_t; + + inline static hipError_t + hipDeviceGetAttribute (int *ival, hipDeviceAttribute_t attr, hipDevice_t dev) + { + enum cudaDeviceAttr cuattr; + switch (attr) + { + case hipDeviceAttributeClockRate: + cuattr = cudaDevAttrClockRate; + break; + case hipDeviceAttributeMaxGridDimX: + cuattr = cudaDevAttrMaxGridDimX; + break; + default: + assert (0); + } + return cudaDeviceGetAttribute (ival, cuattr, dev) != cudaSuccess; + } + + inline static hipError_t + hipCtxGetApiVersion (hipCtx_t ctx, int *ver) + { + unsigned uver; + hipError_t err; + err = cuCtxGetApiVersion (ctx, &uver) != CUDA_SUCCESS; + *ver = (int) uver; + return err; + } + + inline static hipError_t + hipStreamGetDevice (hipStream_t stream, hipDevice_t *dev) + { +#if CUDA_VERSION >= 12080 + return cudaStreamGetDevice (stream, dev); +#else + hipError_t err; + CUcontext ctx; + err = cuStreamGetCtx (stream, &ctx) != CUDA_SUCCESS; + if (err == hipSuccess) + err = cuCtxPushCurrent (ctx) != CUDA_SUCCESS; + if (err == hipSuccess) + err = cuCtxGetDevice (dev) != CUDA_SUCCESS; + if (err == hipSuccess) + err = cuCtxPopCurrent (&ctx) != CUDA_SUCCESS; + return err; +#endif + } + + inline static hipError_t + hipStreamQuery (hipStream_t stream) + { + return cuStreamQuery (stream) != CUDA_SUCCESS; + } + +#else + #error "should be unreachable" +#endif + +int +main () +{ + int ivar; + omp_interop_rc_t res; + omp_interop_t obj = omp_interop_none; + hipError_t hip_err; + + #pragma omp interop init(target, targetsync, prefer_type("hip") : obj) + + omp_interop_fr_t fr = (omp_interop_fr_t) omp_get_interop_int (obj, omp_ipr_fr_id, &res); + assert (res == omp_irc_success); + assert (fr == omp_ifr_hip); + + ivar = (int) omp_get_interop_int (obj, omp_ipr_vendor, &res); + assert (res == omp_irc_success); + int vendor_is_amd = ivar == 1; + #if defined(__HIP_PLATFORM_AMD__) + assert (ivar == 1); + #elif defined(__HIP_PLATFORM_NVIDIA__) + assert (ivar == 11); + #else + assert (0); + #endif + + + /* Check whether the omp_ipr_device -> hipDevice_t yields a valid device. */ + + hipDevice_t hip_dev = (int) omp_get_interop_int (obj, omp_ipr_device, &res); + assert (res == omp_irc_success); + + /* Assume a clock size is available and > 1 GHz; value is in kHz. */ + hip_err = hipDeviceGetAttribute (&ivar, hipDeviceAttributeClockRate, hip_dev); + assert (hip_err == hipSuccess); + assert (ivar > 1000000 /* kHz */); + + /* Assume that the MaxGridDimX is available and > 1024. */ + hip_err = hipDeviceGetAttribute (&ivar, hipDeviceAttributeMaxGridDimX, hip_dev); + assert (hip_err == hipSuccess); + assert (ivar > 1024); + + + /* Check whether the omp_ipr_device_context -> hipCtx_t yields a context. */ + + hipCtx_t hip_ctx = (hipCtx_t) omp_get_interop_ptr (obj, omp_ipr_device_context, &res); + assert (res == omp_irc_success); + + /* Assume API Version > 0 for Nvidia, hipErrorNotSupported for AMD. */ + ivar = -99; + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wdeprecated-declarations" + hip_err = hipCtxGetApiVersion (hip_ctx, &ivar); + #pragma GCC diagnostic pop + + if (vendor_is_amd) + assert (hip_err == hipErrorNotSupported && ivar == -99); + else + { + assert (hip_err == hipSuccess); + assert (ivar > 0); + } + + + /* Check whether the omp_ipr_targetsync -> hipStream_t yields a stream. */ + + hipStream_t hip_sm = (hipStream_t) omp_get_interop_ptr (obj, omp_ipr_targetsync, &res); + assert (res == omp_irc_success); + + hipDevice_t dev_stream = 99; + hip_err = hipStreamGetDevice (hip_sm, &dev_stream); + assert (hip_err == hipSuccess); + assert (dev_stream == hip_dev); + + /* All jobs should have been completed (as there were none none) */ + hip_err = hipStreamQuery (hip_sm); + assert (hip_err == hipSuccess); + + #pragma omp interop destroy(obj) +} diff --git a/libgomp/testsuite/libgomp.c/interop-hipblas-amd-full.c b/libgomp/testsuite/libgomp.c/interop-hipblas-amd-full.c new file mode 100644 index 0000000..53c05bd --- /dev/null +++ b/libgomp/testsuite/libgomp.c/interop-hipblas-amd-full.c @@ -0,0 +1,7 @@ +/* { dg-require-effective-target gomp_hip_header_amd } */ +/* { dg-require-effective-target gomp_libhipblas } */ +/* { dg-additional-options "-lhipblas" } */ + +#define __HIP_PLATFORM_AMD__ 1 + +#include "interop-hipblas.h" diff --git a/libgomp/testsuite/libgomp.c/interop-hipblas-amd-no-hip-header.c b/libgomp/testsuite/libgomp.c/interop-hipblas-amd-no-hip-header.c new file mode 100644 index 0000000..0ea3133 --- /dev/null +++ b/libgomp/testsuite/libgomp.c/interop-hipblas-amd-no-hip-header.c @@ -0,0 +1,8 @@ +/* { dg-require-effective-target gomp_libhipblas } */ +/* { dg-additional-options "-lhipblas" } */ + +#define __HIP_PLATFORM_AMD__ 1 + +#define USE_HIP_FALLBACK_HEADER 1 + +#include "interop-hipblas.h" diff --git a/libgomp/testsuite/libgomp.c/interop-hipblas-nvidia-full.c b/libgomp/testsuite/libgomp.c/interop-hipblas-nvidia-full.c new file mode 100644 index 0000000..ed428c6 --- /dev/null +++ b/libgomp/testsuite/libgomp.c/interop-hipblas-nvidia-full.c @@ -0,0 +1,7 @@ +/* { dg-require-effective-target openacc_cublas } */ +/* { dg-require-effective-target gomp_hip_header_nvidia } */ +/* { dg-additional-options "-lcublas -Wno-deprecated-declarations" } */ + +#define __HIP_PLATFORM_NVIDIA__ 1 + +#include "interop-hipblas.h" diff --git a/libgomp/testsuite/libgomp.c/interop-hipblas-nvidia-no-headers.c b/libgomp/testsuite/libgomp.c/interop-hipblas-nvidia-no-headers.c new file mode 100644 index 0000000..1a31b30 --- /dev/null +++ b/libgomp/testsuite/libgomp.c/interop-hipblas-nvidia-no-headers.c @@ -0,0 +1,9 @@ +/* { dg-require-effective-target openacc_libcublas } */ +/* { dg-additional-options "-lcublas" } */ + +#define __HIP_PLATFORM_NVIDIA__ 1 + +#define USE_HIP_FALLBACK_HEADER 1 +#define USE_CUDA_FALLBACK_HEADER 1 + +#include "interop-hipblas.h" diff --git a/libgomp/testsuite/libgomp.c/interop-hipblas-nvidia-no-hip-header.c b/libgomp/testsuite/libgomp.c/interop-hipblas-nvidia-no-hip-header.c new file mode 100644 index 0000000..f85c13b --- /dev/null +++ b/libgomp/testsuite/libgomp.c/interop-hipblas-nvidia-no-hip-header.c @@ -0,0 +1,8 @@ +/* { dg-require-effective-target openacc_cublas } */ +/* { dg-additional-options "-lcublas" } */ + +#define __HIP_PLATFORM_NVIDIA__ 1 + +#define USE_HIP_FALLBACK_HEADER 1 + +#include "interop-hipblas.h" diff --git a/libgomp/testsuite/libgomp.c/interop-hipblas.h b/libgomp/testsuite/libgomp.c/interop-hipblas.h new file mode 100644 index 0000000..d7cb174 --- /dev/null +++ b/libgomp/testsuite/libgomp.c/interop-hipblas.h @@ -0,0 +1,240 @@ +/* Check whether hipBlas' daxpy works with an interop object. + daxpy(N, DA, DX, INCX, DY, INCY) + calculates (for DX = DY = 1): + DY(1:N) = DY(1:N) + DA * DX(1:N) + and otherwise N array elements, taking every INCX-th or INCY-th one, repectively. + +Based on the interop example in OpenMP's example document */ + +/* Minimal check whether HIP works - by checking whether the API routines + seem to work. This includes a fallback if the header is not + available. */ + +#if !defined(__HIP_PLATFORM_AMD__) && !defined(__HIP_PLATFORM_NVIDIA__) + #error "Either __HIP_PLATFORM_AMD__ or __HIP_PLATFORM_NVIDIA__ must be defined" +#endif + +#if defined(__HIP_PLATFORM_AMD__) && defined(__HIP_PLATFORM_NVIDIA__) + #error "Either __HIP_PLATFORM_AMD__ or __HIP_PLATFORM_NVIDIA__ must be defined" +#endif + + +#include <assert.h> +#include <omp.h> +#include "../libgomp.c-c++-common/on_device_arch.h" + + +#if __has_include(<hipblas/hipblas.h>) && (__has_include(<library_types.h>) || !defined(__HIP_PLATFORM_NVIDIA__)) && !defined(USE_HIP_FALLBACK_HEADER) + #ifdef __HIP_PLATFORM_NVIDIA__ + /* There seems to be an issue with hip/library_types.h including + CUDA's "library_types.h". Include CUDA's one explicitly here. + Could possibly worked around by using -isystem vs. -I. */ + #include <library_types.h> + + /* For some reasons, the following symbols do not seem to get + mapped from HIP to CUDA, causing link errors. */ + #define hipblasSetStream cublasSetStream_v2 + #define hipblasDaxpy cublasDaxpy_v2 + #define hipblasCreate cublasCreate_v2 + #endif + #include <hipblas/hipblas.h> + +#elif defined(__HIP_PLATFORM_AMD__) + /* Add a poor man's fallback declaration. */ + #if !defined(USE_HIP_FALLBACK_HEADER) + #warning "Using fallback declaration for <hipblas/hipblas.h> for __HIP_PLATFORM_AMD__" + #endif + + typedef enum + { + HIPBLAS_STATUS_SUCCESS = 0 + + } hipblasStatus_t; + + typedef struct ihipStream_t* hipStream_t; + typedef void* hipblasHandle_t; + + hipblasStatus_t hipblasCreate (hipblasHandle_t*); + hipblasStatus_t hipblasSetStream (hipblasHandle_t, hipStream_t); + hipblasStatus_t hipblasDaxpy (hipblasHandle_t, int, const double*, const double*, int, double*, int); + +#else + /* Add a poor man's fallback declaration. */ + #if !defined(USE_HIP_FALLBACK_HEADER) + #warning "Using fallback declaration for <hipblas/hipblas.h> for __HIP_PLATFORM_NVIDA__" + #endif + + #if __has_include(<cuda.h>) && __has_include(<cudaTypedefs.h>) && __has_include(<cuda_runtime.h>) && __has_include(<cublas_v2.h>) && !defined(USE_CUDA_FALLBACK_HEADER) + #include <cuda.h> + #include <cudaTypedefs.h> + #include <cuda_runtime.h> + #include <cublas_v2.h> + + #else + /* Add a poor man's fallback declaration. */ + #if defined(USE_CUDA_FALLBACK_HEADER) + // no warning + #elif !__has_include(<cuda.h>) + #warning "Using GCC's cuda.h as fallback for cuda.h" + #elif !__has_include(<cudaTypedefs.h>) + #warning "Using GCC's cuda.h as fallback for cudaTypedefs.h" + #elif !__has_include(<cuda_runtime.h>) + #warning "Using GCC's cuda.h as fallback for cuda_runtime.h" + #else + #warning "Using GCC's cuda.h as fallback for cublas_v2.h" + #endif + #include "../../../include/cuda/cuda.h" + + typedef enum { + CUBLAS_STATUS_SUCCESS = 0, + } cublasStatus_t; + + typedef CUstream cudaStream_t; + typedef struct cublasContext* cublasHandle_t; + + #define cublasCreate cublasCreate_v2 + cublasStatus_t cublasCreate_v2 (cublasHandle_t *); + + #define cublasSetStream cublasSetStream_v2 + cublasStatus_t cublasSetStream_v2 (cublasHandle_t, cudaStream_t); + + #define cublasDaxpy cublasDaxpy_v2 + cublasStatus_t cublasDaxpy_v2(cublasHandle_t, int, const double*, const double*, int, double*, int); + #endif + + #define HIPBLAS_STATUS_SUCCESS CUBLAS_STATUS_SUCCESS + #define hipblasStatus_t cublasStatus_t + #define hipStream_t cudaStream_t + #define hipblasHandle_t cublasHandle_t + #define hipblasCreate cublasCreate + #define hipblasSetStream cublasSetStream + #define hipblasDaxpy cublasDaxpy +#endif + +static int used_variant = 0; + +void +run_hipBlasdaxpy (int n, double da, const double *dx, int incx, double *dy, int incy, omp_interop_t obj) +{ + used_variant = 1; + + omp_interop_rc_t res; + hipblasStatus_t stat; + + omp_intptr_t fr = omp_get_interop_int(obj, omp_ipr_fr_id, &res); + assert (res == omp_irc_success && fr == omp_ifr_hip); + + hipStream_t stream = (hipStream_t) omp_get_interop_ptr (obj, omp_ipr_targetsync, &res); + assert (res == omp_irc_success); + + hipblasHandle_t handle; + stat = hipblasCreate (&handle); + assert (stat == HIPBLAS_STATUS_SUCCESS); + + stat = hipblasSetStream (handle, stream); + assert (stat == HIPBLAS_STATUS_SUCCESS); + + /* 'da' can be in host or device space, 'dx' and 'dy' must be in device space. */ + stat = hipblasDaxpy (handle, n, &da, dx, 1, dy, 1) ; + assert (stat == HIPBLAS_STATUS_SUCCESS); +} + +#if defined(__HIP_PLATFORM_AMD__) +#pragma omp declare variant(run_hipBlasdaxpy) \ + match(construct={dispatch}, target_device={kind(nohost), arch("amdgcn")}) \ + adjust_args(need_device_ptr : dx, dy) \ + append_args(interop(targetsync, prefer_type("hip"))) +#elif defined(__HIP_PLATFORM_NVIDIA__) +#pragma omp declare variant(run_hipBlasdaxpy) \ + match(construct={dispatch}, target_device={kind(nohost), arch("nvptx")}) \ + adjust_args(need_device_ptr : dx, dy) \ + append_args(interop(targetsync, prefer_type("hip"))) +#else + #error "wrong platform" +#endif + +void +run_daxpy (int n, double da, const double *dx, int incx, double *dy, int incy) +{ + used_variant = 2; + + if (incx == 1 && incy == 1) + #pragma omp simd + for (int i = 0; i < n; i++) + dy[i] += da * dx[i]; + else + { + int ix = 0; + int iy = 0; + for (int i = 0; i < n; i++) + { + dy[iy] += da * dx[ix]; + ix += incx; + iy += incy; + } + } +} + + +void +run_test (int dev) +{ + constexpr int N = 1024; + + // A = {1,2,...,N} + // B = {-1, -2, ..., N} + // B' = daxpy (N, 3, A, incx=1, B, incy=1) + // = B + 3*A + // -> B' = {0, 2, 4, 6, ... } + + double A[N], B[N]; + double factor = 3.0; + for (int i = 0; i < N; i++) + { + A[i] = i; + B[i] = -i; + } + + if (dev != omp_initial_device && dev != omp_get_num_devices ()) + { + #pragma omp target enter data device(dev) map(A, B) + } + + used_variant = 99; + #pragma omp dispatch device(dev) + run_daxpy (N, factor, A, 1, B, 1); + + if (dev != omp_initial_device && dev != omp_get_num_devices ()) + { + #pragma omp target exit data device(dev) map(release: A) map(from: B) + + int tmp = omp_get_default_device (); + omp_set_default_device (dev); +#if defined(__HIP_PLATFORM_AMD__) + if (on_device_arch_gcn ()) +#else + if (on_device_arch_nvptx ()) +#endif + assert (used_variant == 1); + else + assert (used_variant == 2); + omp_set_default_device (tmp); + } + else + assert (used_variant == 2); + + for (int i = 0; i < N; i++) + assert (B[i] == 2*i); +} + +int +main () +{ + int ndev = omp_get_num_devices (); + + for (int dev = 0; dev <= ndev; dev++) + run_test (dev); + run_test (omp_initial_device); + + return 0; +} diff --git a/libgomp/testsuite/libgomp.fortran/interop-hip-amd-full.F90 b/libgomp/testsuite/libgomp.fortran/interop-hip-amd-full.F90 new file mode 100644 index 0000000..bbd49dd --- /dev/null +++ b/libgomp/testsuite/libgomp.fortran/interop-hip-amd-full.F90 @@ -0,0 +1,7 @@ +! { dg-require-effective-target gomp_hipfort_module } +! { dg-require-effective-target gomp_libamdhip64 } +! { dg-additional-options "-lamdhip64" } + +#define HAVE_HIPFORT 1 + +#include "interop-hip.h" diff --git a/libgomp/testsuite/libgomp.fortran/interop-hip-amd-no-module.F90 b/libgomp/testsuite/libgomp.fortran/interop-hip-amd-no-module.F90 new file mode 100644 index 0000000..0afec83 --- /dev/null +++ b/libgomp/testsuite/libgomp.fortran/interop-hip-amd-no-module.F90 @@ -0,0 +1,6 @@ +! { dg-require-effective-target gomp_libamdhip64 } +! { dg-additional-options "-lamdhip64" } + +#define USE_HIP_FALLBACK_MODULE 1 + +#include "interop-hip.h" diff --git a/libgomp/testsuite/libgomp.fortran/interop-hip-nvidia-full.F90 b/libgomp/testsuite/libgomp.fortran/interop-hip-nvidia-full.F90 new file mode 100644 index 0000000..cef592f --- /dev/null +++ b/libgomp/testsuite/libgomp.fortran/interop-hip-nvidia-full.F90 @@ -0,0 +1,9 @@ +! { dg-require-effective-target gomp_hipfort_module } +! { dg-require-effective-target openacc_cudart } +! { dg-require-effective-target openacc_cuda } +! { dg-additional-options "-lcuda -lcudart" } + +#define HAVE_HIPFORT 1 +#define USE_CUDA_NAMES 1 + +#include "interop-hip.h" diff --git a/libgomp/testsuite/libgomp.fortran/interop-hip-nvidia-no-module.F90 b/libgomp/testsuite/libgomp.fortran/interop-hip-nvidia-no-module.F90 new file mode 100644 index 0000000..c1ef29d --- /dev/null +++ b/libgomp/testsuite/libgomp.fortran/interop-hip-nvidia-no-module.F90 @@ -0,0 +1,8 @@ +! { dg-require-effective-target openacc_libcudart } +! { dg-require-effective-target openacc_libcuda } +! { dg-additional-options "-lcuda -lcudart" } + +#define USE_CUDA_NAMES 1 +#define USE_HIP_FALLBACK_MODULE 1 + +#include "interop-hip.h" diff --git a/libgomp/testsuite/libgomp.fortran/interop-hip.h b/libgomp/testsuite/libgomp.fortran/interop-hip.h new file mode 100644 index 0000000..753ccce --- /dev/null +++ b/libgomp/testsuite/libgomp.fortran/interop-hip.h @@ -0,0 +1,214 @@ +! Minimal check whether HIP works - by checking whether the API routines +! seem to work. This includes a fallback if hipfort is not available + +#ifndef HAVE_HIPFORT +#ifndef USE_HIP_FALLBACK_MODULE +#if USE_CUDA_NAMES +#warning "Using fallback implementation for module hipfort as HAVE_HIPFORT is undefined (for NVIDA/CUDA)" +#else +#warning "Using fallback implementation for module hipfort as HAVE_HIPFORT is undefined - assume AMD as USE_CUDA_NAMES is unset" +#endif +#endif +module hipfort ! Minimal implementation for the testsuite + implicit none + + enum, bind(c) + enumerator :: hipSuccess = 0 + enumerator :: hipErrorNotSupported = 801 + end enum + + enum, bind(c) + enumerator :: hipDeviceAttributeClockRate = 5 + enumerator :: hipDeviceAttributeMaxGridDimX = 29 + end enum + + interface + integer(kind(hipSuccess)) function hipDeviceGetAttribute (ip, attr, dev) & +#if USE_CUDA_NAMES + bind(c, name="cudaDeviceGetAttribute") +#else + bind(c, name="hipDeviceGetAttribute") +#endif + use iso_c_binding, only: c_ptr, c_int + import + implicit none + type(c_ptr), value :: ip + integer(kind(hipDeviceAttributeClockRate)), value :: attr + integer(c_int), value :: dev + end + + integer(kind(hipSuccess)) function hipCtxGetApiVersion (ctx, ip) & +#if USE_CUDA_NAMES + bind(c, name="cudaCtxGetApiVersion") +#else + bind(c, name="hipCtxGetApiVersion") +#endif + use iso_c_binding, only: c_ptr + import + implicit none + type(c_ptr), value :: ctx, ip + end + + integer(kind(hipSuccess)) function hipStreamQuery (stream) & +#if USE_CUDA_NAMES + bind(c, name="cudaStreamQuery") +#else + bind(c, name="hipStreamQuery") +#endif + use iso_c_binding, only: c_ptr + import + implicit none + type(c_ptr), value :: stream + end + + integer(kind(hipSuccess)) function hipStreamGetFlags (stream, flags) & +#if USE_CUDA_NAMES + bind(c, name="cudaStreamGetFlags") +#else + bind(c, name="hipStreamGetFlags") +#endif + use iso_c_binding, only: c_ptr + import + implicit none + type(c_ptr), value :: stream + type(c_ptr), value :: flags + end + end interface +end module +#endif + +program main + use iso_c_binding, only: c_ptr, c_int, c_loc + use omp_lib + use hipfort + implicit none (type, external) + +! Only supported since CUDA 12.8 - skip for better compatibility +! ! Manally implement hipStreamGetDevice as hipfort misses it +! ! -> https://github.com/ROCm/hipfort/issues/238 +! interface +! integer(kind(hipSuccess)) function my_hipStreamGetDevice(stream, dev) & +!#if USE_CUDA_NAMES +! bind(c, name="cudaStreamGetDevice") +!#else +! bind(c, name="hipStreamGetDevice") +!#endif +! use iso_c_binding, only: c_ptr, c_int +! import +! implicit none +! type(c_ptr), value :: stream +! integer(c_int) :: dev +! end +! end interface + + integer(c_int), target :: ivar + integer(omp_interop_rc_kind) :: res + integer(omp_interop_kind) :: obj + integer(omp_interop_fr_kind) :: fr + integer(kind(hipSuccess)) :: hip_err + integer(c_int) :: hip_dev, dev_stream + type(c_ptr) :: hip_ctx, hip_sm + + logical :: vendor_is_amd + + obj = omp_interop_none + + !$omp interop init(target, targetsync, prefer_type("hip") : obj) + + fr = omp_get_interop_int (obj, omp_ipr_fr_id, res) + if (res /= omp_irc_success) error stop 1 + if (fr /= omp_ifr_hip) error stop 1 + + ivar = omp_get_interop_int (obj, omp_ipr_vendor, res) + if (ivar == 1) then ! AMD + vendor_is_amd = .true. + else if (ivar == 11) then ! Nvidia + vendor_is_amd = .false. + else + error stop 1 ! Unknown + endif +#if USE_CUDA_NAMES + if (vendor_is_amd) error stop 1 +#else + if (.not. vendor_is_amd) error stop 1 +#endif + + ! Check whether the omp_ipr_device -> hipDevice_t yields a valid device. + + hip_dev = omp_get_interop_int (obj, omp_ipr_device, res) + if (res /= omp_irc_success) error stop 1 + +! AMD messed up in Fortran with the attribute handling, missing the +! translation table it has for C. +block + enum, bind(c) + enumerator :: cudaDevAttrClockRate = 13 + enumerator :: cudaDevAttrMaxGridDimX = 5 + end enum + + ! Assume a clock size is available and > 1 GHz; value is in kHz. + ! c_loc is completely bogus, but as AMD messed up the interface ... + ! Cf. https://github.com/ROCm/hipfort/issues/239 +if (vendor_is_amd) then + hip_err = hipDeviceGetAttribute (c_loc(ivar), hipDeviceAttributeClockRate, hip_dev) +else + hip_err = hipDeviceGetAttribute (c_loc(ivar), cudaDevAttrClockRate, hip_dev) +endif + if (hip_err /= hipSuccess) error stop 1 + if (ivar <= 1000000) error stop 1 ! in kHz + + ! Assume that the MaxGridDimX is available and > 1024 + ! c_loc is completely bogus, but as AMD messed up the interface ... + ! Cf. https://github.com/ROCm/hipfort/issues/239 +if (vendor_is_amd) then + hip_err = hipDeviceGetAttribute (c_loc(ivar), hipDeviceAttributeMaxGridDimX, hip_dev) +else + hip_err = hipDeviceGetAttribute (c_loc(ivar), cudaDevAttrMaxGridDimX, hip_dev) +endif + if (hip_err /= hipSuccess) error stop 1 + if (ivar <= 1024) error stop 1 +end block + + + ! Check whether the omp_ipr_device_context -> hipCtx_t yields a context. + + hip_ctx = omp_get_interop_ptr (obj, omp_ipr_device_context, res) + if (res /= omp_irc_success) error stop 1 + +! ! Assume API Version > 0 for Nvidia, hipErrorNotSupported for AMD. */ +! ivar = -99 +! ! AMD deprectated hipCtxGetApiVersion (in C/C++) +! hip_err = hipCtxGetApiVersion (hip_ctx, c_loc(ivar)) +! +! if (vendor_is_amd) then +! if (hip_err /= hipErrorNotSupported .or. ivar /= -99) error stop 1 +! else +! if (hip_err /= hipSuccess) error stop 1 +! if (ivar <= 0) error stop 1 +! end if + + + ! Check whether the omp_ipr_targetsync -> hipStream_t yields a stream. + + hip_sm = omp_get_interop_ptr (obj, omp_ipr_targetsync, res) + if (res /= omp_irc_success) error stop 1 + +! Skip as this is only in CUDA 12.8 +! dev_stream = 99 +! ! Not (yet) implemented: https://github.com/ROCm/hipfort/issues/238 +! ! hip_err = hipStreamGetDevice (hip_sm, dev_stream) +! hip_err = my_hipStreamGetDevice (hip_sm, dev_stream) +! if (hip_err /= hipSuccess) error stop 1 +! if (dev_stream /= hip_dev) error stop 1 + + ! Get flags of the stream + hip_err = hipStreamGetFlags (hip_sm, c_loc (ivar)) + if (hip_err /= hipSuccess) error stop 1 + ! Accept any value + + ! All jobs should have been completed (as there were none none) + hip_err = hipStreamQuery (hip_sm) + if (hip_err /= hipSuccess) error stop 1 + + !$omp interop destroy(obj) +end diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 4615d0f..6433d3f 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,36 @@ +2025-04-24 Jonathan Wakely <jwakely@redhat.com> + + * testsuite/23_containers/forward_list/48101_neg.cc: Remove + dg-prune-output that doesn't match anything. + * testsuite/23_containers/list/48101_neg.cc: Likewise. + * testsuite/23_containers/multiset/48101_neg.cc: Likewise. + * testsuite/23_containers/set/48101_neg.cc: Likewise. + +2025-04-24 Jonathan Wakely <jwakely@redhat.com> + + * include/std/generator (generator::yield_value): Add overload + taking lvalue element_of view, as per LWG 3899. + * testsuite/24_iterators/range_generators/lwg3899.cc: New test. + +2025-04-24 François Dumont <frs.dumont@gmail.com> + + * testsuite/util/replacement_memory_operators.h: Adapt for -fno-exceptions + context. + * testsuite/23_containers/deque/capacity/shrink_to_fit.cc: Adapt test + to check std::deque shrink_to_fit method. + +2025-04-23 Andreas Schwab <schwab@linux-m68k.org> + + * config/abi/post/powerpc-linux-gnu/baseline_symbols.txt: Update. + * config/abi/post/powerpc64-linux-gnu/32/baseline_symbols.txt: Update. + * config/abi/post/powerpc64-linux-gnu/baseline_symbols.txt: Update. + +2025-04-23 ZENG Hao <c@cyano.cn> + + * src/c++23/std.cc.in (atomic_signed_lock_free): Guard with + preprocessor check for __cpp_lib_atomic_lock_free_type_aliases. + (atomic_unsigned_lock_free): Likewise. + 2025-04-22 Patrick Palka <ppalka@redhat.com> Revert: diff --git a/libstdc++-v3/include/std/generator b/libstdc++-v3/include/std/generator index 3f781f1..7ab2c9e 100644 --- a/libstdc++-v3/include/std/generator +++ b/libstdc++-v3/include/std/generator @@ -153,6 +153,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION noexcept { return _Recursive_awaiter { std::move(__r.range) }; } + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 3899. co_yielding elements of an lvalue generator is + // unnecessarily inefficient + template<typename _R2, typename _V2, typename _A2, typename _U2> + requires std::same_as<_Yield2_t<_R2, _V2>, _Yielded> + auto + yield_value(ranges::elements_of<generator<_R2, _V2, _A2>&, _U2> __r) + noexcept + { return _Recursive_awaiter { std::move(__r.range) }; } + template<ranges::input_range _R, typename _Alloc> requires convertible_to<ranges::range_reference_t<_R>, _Yielded> auto diff --git a/libstdc++-v3/testsuite/23_containers/deque/capacity/shrink_to_fit.cc b/libstdc++-v3/testsuite/23_containers/deque/capacity/shrink_to_fit.cc index 7cb6707..4dbf405 100644 --- a/libstdc++-v3/testsuite/23_containers/deque/capacity/shrink_to_fit.cc +++ b/libstdc++-v3/testsuite/23_containers/deque/capacity/shrink_to_fit.cc @@ -1,4 +1,6 @@ // { dg-do run { target c++11 } } +// { dg-require-effective-target std_allocator_new } +// { dg-xfail-run-if "AIX operator new" { powerpc-ibm-aix* } } // 2010-01-08 Paolo Carlini <paolo.carlini@oracle.com> @@ -19,18 +21,42 @@ // with this library; see the file COPYING3. If not see // <http://www.gnu.org/licenses/>. -#include <vector> +#include <deque> #include <testsuite_hooks.h> +#include <replacement_memory_operators.h> // libstdc++/42573 void test01() { - std::vector<int> d(100); - d.push_back(1); - d.push_back(1); - // VERIFY( d.size() < d.capacity() ); + using namespace std; + __gnu_test::counter::reset(); + + const size_t buf_size = _GLIBCXX_STD_C::__deque_buf_size(sizeof(size_t)); + deque<size_t> d; + for (size_t i = 0; i != buf_size; ++i) + d.push_back(i); + + // No shrink if 1st buffer is full, create some front capacity. + d.pop_front(); + + // 1 node array allocation + 2 node allocation = 3. + VERIFY( __gnu_test::counter::count() == 3 ); + VERIFY( __gnu_test::counter::get()._M_increments == 3 ); + d.shrink_to_fit(); - // VERIFY( d.size() == d.capacity() ); + + // No reallocation if no exception support, shrink_to_fit is then a + // no-op. +#if __cpp_exceptions + // 1 node array allocation + 1 node allocation = 2. + const int expected_count = 2; + const int expected_increments = 2; +#else + const int expected_count = 3; + const int expected_increments = 0; +#endif + VERIFY( __gnu_test::counter::count() == expected_count ); + VERIFY( __gnu_test::counter::get()._M_increments == 3 + expected_increments ); } int main() diff --git a/libstdc++-v3/testsuite/23_containers/forward_list/48101_neg.cc b/libstdc++-v3/testsuite/23_containers/forward_list/48101_neg.cc index 2f2ea2a..d18195e 100644 --- a/libstdc++-v3/testsuite/23_containers/forward_list/48101_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/forward_list/48101_neg.cc @@ -26,6 +26,5 @@ test01() } // { dg-error "non-const, non-volatile value_type" "" { target *-*-* } 0 } -// { dg-prune-output "std::allocator<.* has no member named " } // { dg-prune-output "must have the same value_type as its allocator" } // { dg-prune-output "rebind_alloc" } diff --git a/libstdc++-v3/testsuite/23_containers/list/48101_neg.cc b/libstdc++-v3/testsuite/23_containers/list/48101_neg.cc index 8b2e075..cc51705 100644 --- a/libstdc++-v3/testsuite/23_containers/list/48101_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/list/48101_neg.cc @@ -26,5 +26,4 @@ test01() } // { dg-error "non-const, non-volatile value_type" "" { target *-*-* } 0 } -// { dg-prune-output "std::allocator<.* has no member named " } // { dg-prune-output "must have the same value_type as its allocator" } diff --git a/libstdc++-v3/testsuite/23_containers/multiset/48101_neg.cc b/libstdc++-v3/testsuite/23_containers/multiset/48101_neg.cc index f0786cf..3cc0658 100644 --- a/libstdc++-v3/testsuite/23_containers/multiset/48101_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/multiset/48101_neg.cc @@ -29,7 +29,6 @@ test01() // { dg-error "non-const, non-volatile value_type" "" { target *-*-* } 0 } // { dg-error "comparison object must be invocable" "" { target *-*-* } 0 } -// { dg-prune-output "std::allocator<.* has no member named " } // { dg-prune-output "must have the same value_type as its allocator" } // { dg-prune-output "no match for call" } // { dg-prune-output "invalid conversion" } diff --git a/libstdc++-v3/testsuite/23_containers/set/48101_neg.cc b/libstdc++-v3/testsuite/23_containers/set/48101_neg.cc index e8dec72..fe38d1a 100644 --- a/libstdc++-v3/testsuite/23_containers/set/48101_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/set/48101_neg.cc @@ -29,7 +29,6 @@ test01() // { dg-error "non-const, non-volatile value_type" "" { target *-*-* } 0 } // { dg-error "comparison object must be invocable" "" { target *-*-* } 0 } -// { dg-prune-output "std::allocator<.* has no member named " } // { dg-prune-output "must have the same value_type as its allocator" } // { dg-prune-output "no match for call" } // { dg-prune-output "invalid conversion" } diff --git a/libstdc++-v3/testsuite/24_iterators/range_generators/lwg3899.cc b/libstdc++-v3/testsuite/24_iterators/range_generators/lwg3899.cc new file mode 100644 index 0000000..5a812ec --- /dev/null +++ b/libstdc++-v3/testsuite/24_iterators/range_generators/lwg3899.cc @@ -0,0 +1,57 @@ +// { dg-do run { target c++23 } } + +// LWG 3899. +// co_yielding elements of an lvalue generator is unnecessarily inefficient + +#include <generator> +#include <memory_resource> +#include <testsuite_hooks.h> + +struct memory_resource : std::pmr::memory_resource +{ + std::size_t count = 0; + + void* do_allocate(std::size_t n, std::size_t a) override + { + count += n; + return std::pmr::new_delete_resource()->allocate(n, a); + } + + void do_deallocate(void* p, std::size_t n, std::size_t a) override + { + return std::pmr::new_delete_resource()->deallocate(p, n, a); + } + + bool do_is_equal(const std::pmr::memory_resource& mr) const noexcept override + { return this == &mr; } +}; + +std::pmr::generator<int> +f(std::allocator_arg_t, std::pmr::polymorphic_allocator<>, int init) +{ + co_yield init + 0; + co_yield init + 1; +} + +std::pmr::generator<int> +g(std::allocator_arg_t, std::pmr::polymorphic_allocator<> alloc) +{ + auto gen = f(std::allocator_arg, alloc, 0); + auto gen2 = f(std::allocator_arg, alloc, 2); + co_yield std::ranges::elements_of(std::move(gen), alloc); + co_yield std::ranges::elements_of(gen2, alloc); +} + +int +main() +{ + std::size_t counts[4]; + memory_resource mr; + for (auto d : g(std::allocator_arg , &mr)) + counts[d] = mr.count; + VERIFY(counts[0] != 0); + // No allocations after the first one: + VERIFY(counts[1] == counts[0]); + VERIFY(counts[2] == counts[0]); + VERIFY(counts[3] == counts[0]); +} diff --git a/libstdc++-v3/testsuite/util/replacement_memory_operators.h b/libstdc++-v3/testsuite/util/replacement_memory_operators.h index 2516cd2..69afa77 100644 --- a/libstdc++-v3/testsuite/util/replacement_memory_operators.h +++ b/libstdc++-v3/testsuite/util/replacement_memory_operators.h @@ -36,8 +36,12 @@ namespace __gnu_test ~counter() THROW (counter_error) { +#if __cpp_exceptions if (_M_throw && _M_count != 0) throw counter_error(); +#else + VERIFY( !_M_throw || _M_count == 0 ); +#endif } static void @@ -133,8 +137,12 @@ void* operator new(std::size_t size) THROW(std::bad_alloc) { std::printf("operator new is called \n"); void* p = std::malloc(size); +#if __cpp_exceptions if (!p) throw std::bad_alloc(); +#else + VERIFY( p ); +#endif __gnu_test::counter::increment(); return p; } |