diff options
240 files changed, 6492 insertions, 634 deletions
diff --git a/c++tools/ChangeLog b/c++tools/ChangeLog index ff35cac..d5a345b 100644 --- a/c++tools/ChangeLog +++ b/c++tools/ChangeLog @@ -1,3 +1,8 @@ +2025-06-02 Kito Cheng <kito.cheng@sifive.com> + + * configure.ac: Don't check `--enable-default-pie`. + * configure: Regen. + 2024-05-07 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE> * configure.ac (ax_lib_socket_nsl.m4): Don't sinclude. diff --git a/c++tools/configure b/c++tools/configure index 1353479..6df4a2f 100755 --- a/c++tools/configure +++ b/c++tools/configure @@ -700,7 +700,6 @@ enable_option_checking enable_c___tools enable_maintainer_mode enable_checking -enable_default_pie enable_host_pie enable_host_bind_now with_gcc_major_version_only @@ -1335,7 +1334,6 @@ Optional Features: enable expensive run-time checks. With LIST, enable only specific categories of checks. Categories are: yes,no,all,none,release. - --enable-default-pie enable Position Independent Executable as default --enable-host-pie build host code as PIE --enable-host-bind-now link host code as BIND_NOW @@ -2946,15 +2944,6 @@ $as_echo "#define ENABLE_ASSERT_CHECKING 1" >>confdefs.h fi -# Check whether --enable-default-pie was given. -# Check whether --enable-default-pie was given. -if test "${enable_default_pie+set}" = set; then : - enableval=$enable_default_pie; PICFLAG=-fPIE -else - PICFLAG= -fi - - # Enable --enable-host-pie # Check whether --enable-host-pie was given. if test "${enable_host_pie+set}" = set; then : diff --git a/c++tools/configure.ac b/c++tools/configure.ac index db34ee6..8c4b72a 100644 --- a/c++tools/configure.ac +++ b/c++tools/configure.ac @@ -97,12 +97,6 @@ if test x$ac_assert_checking != x ; then [Define if you want assertions enabled. This is a cheap check.]) fi -# Check whether --enable-default-pie was given. -AC_ARG_ENABLE(default-pie, -[AS_HELP_STRING([--enable-default-pie], - [enable Position Independent Executable as default])], -[PICFLAG=-fPIE], [PICFLAG=]) - # Enable --enable-host-pie AC_ARG_ENABLE(host-pie, [AS_HELP_STRING([--enable-host-pie], diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 3c37d27..74490c4 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,120 @@ +2025-06-02 Alexandre Oliva <oliva@adacore.com> + + PR rtl-optimization/120424 + PR middle-end/118939 + * lra-spills.cc (spill_pseudos): Update insn regno info. + * lra-eliminations.cc (update_reg_eliminate): Recognize + disabling of active elimination regardless of + prev_can_eliminate. + +2025-06-02 Dongyan Chen <chendongyan@isrc.iscas.ac.cn> + + * config/riscv/riscv-ext.def: New extension defs. + * config/riscv/riscv-ext.opt: Ditto. + * doc/riscv-ext.texi: Ditto. + +2025-06-02 Stafford Horne <shorne@gmail.com> + + * config/or1k/predicates.md (call_insn_operand): Add condition + to not allow symbol_ref operands with TARGET_CMODEL_LARGE. + * config/or1k/or1k.opt: Document new -mcmodel=large + implications. + * doc/invoke.texi: Likewise. + +2025-06-02 Christophe Lyon <christophe.lyon@linaro.org> + + * doc/sourcebuild.texi (tls_link): Add documentation. + +2025-06-02 Kito Cheng <kito.cheng@sifive.com> + + * config/riscv/t-riscv: Adjust build rule for gen-riscv-ext-opt + and gen-riscv-ext-texi. + +2025-06-02 Kito Cheng <kito.cheng@sifive.com> + + * config/riscv/riscv-c.cc (riscv_cpu_cpp_builtins): Use + range-based-for-loop. + * config/riscv/riscv-subset.h (riscv_subset_list::iterator): + New. + (riscv_subset_list::const_iterator): New. + +2025-06-01 H.J. Lu <hjl.tools@gmail.com> + + PR other/120493 + * final.cc (call_from_call_insn): Change the argument type to + const rtx_call_insn *. + (get_call_rtx_from): New. + * rtl.h (is_a_helper <const rtx_call_insn *>::test): New. + (get_call_rtx_from): Moved to the final.cc section. + * rtlanal.cc (get_call_rtx_from): Removed. + +2025-06-01 Andrew Pinski <quic_apinski@quicinc.com> + + * tree-ssa-forwprop.cc (optimize_vector_load): Set the vuse manually + on the new load statements. Also remove forward declaration since + the definition is before the first use. + (pass_forwprop::execute): Likewise for complex loads. + (pass_data_forwprop): Remove TODO_update_ssa. + +2025-06-01 Pan Li <pan2.li@intel.com> + + * config/riscv/autovec.md: Fix line too long for sorts + of pattern. + +2025-06-01 Takayuki 'January June' Suwa <jjsuwa_sys3175@yahoo.co.jp> + + * config/xtensa/xtensa.cc: Remove include of reload.h. + +2025-06-01 Takayuki 'January June' Suwa <jjsuwa_sys3175@yahoo.co.jp> + + * config/xtensa/xtensa.md (movsf_internal): + Remove destination side constraint modifier '^' in the third + alternative. + +2025-06-01 Takayuki 'January June' Suwa <jjsuwa_sys3175@yahoo.co.jp> + + * config/xtensa/xtensa.cc + (xtensa_ira_change_pseudo_allocno_class): + New prototype and function. + (TARGET_IRA_CHANGE_PSEUDO_ALLOCNO_CLASS): Define macro. + (xtensa_register_move_cost): + Change between integer and FP register move cost to a value + based on actual behavior, i.e. 2, the default and the same as + the move cost between integer registers. + +2025-05-31 Andrew Pinski <quic_apinski@quicinc.com> + + * function.h (struct function): Remove last_verified. + * gimple-harden-conditionals.cc (pass_data_harden_compares): Remove + TODO_verify_il. + (pass_data_harden_conditional_branches): Likewise. + * gimple-harden-control-flow.cc (pass_harden_control_flow_redundancy::execute): + Don't return TODO_verify_il. + * ipa-strub.cc (pass_data_ipa_strub): Remove TODO_verify_il. + * passes.cc (TODO_verify_il): Define. + (execute_function_todo): Don't use or set last_verified. + (clear_last_verified): Remove. + (execute_one_ipa_transform_pass): Update comment before execute_todo. + Assert that none of the todos have TODO_verify_il set on it. + (execute_one_pass): Don't call clear_last_verified on all functions. + Assert that none of the todos have TODO_verify_il set on it. + * tree-inline.cc (initialize_cfun): Don't copy last_verified. + * tree-pass.h (TODO_verify_all): Remove. + * tree-vrp.cc (pass_data_early_vrp): Remove TODO_verify_all. + (pass_data_fast_vrp): Likewise. + +2025-05-31 Richard Biener <rguenther@suse.de> + + PR tree-optimization/120357 + * tree-vect-loop.cc (vect_create_epilog_for_reduction): Create + the conditional reduction induction IV increment before the + main IV exit. + +2025-05-31 Gaius Mulley <gaiusmod2@gmail.com> + + PR modula2/120389 + * doc/gm2.texi (-fm2-strict-type-reason): Document new flag. + 2025-05-30 David Malcolm <dmalcolm@redhat.com> PR other/116792 diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index e844ed6..42c5479 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20250531 +20250603 diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index 75b6531..50ba856 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -938,7 +938,7 @@ C ObjC C++ ObjC++ CPP(cpp_warn_invalid_utf8) CppReason(CPP_W_INVALID_UTF8) Var(w Warn about invalid UTF-8 characters. Wjump-misses-init -C ObjC Var(warn_jump_misses_init) Warning LangEnabledby(C ObjC,Wc++-compat) +C ObjC Var(warn_jump_misses_init) Warning LangEnabledBy(C ObjC,Wc++-compat) Warn when a jump misses a variable initialization. Enum diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index f36431b..53ad780 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,14 @@ +2025-06-02 Sandra Loosemore <sloosemore@baylibre.com> + + * c-parser.cc (c_parser_omp_context_selector): Call + convert_lvalue_to_rvalue and c_objc_common_truthvalue_conversion + on the expression for OMP_TRAIT_PROPERTY_BOOL_EXPR. + +2025-06-01 Martin Uecker <uecker@tugraz.at> + + PR c/120380 + * c-objc-common.cc (get_aka_type): Ignore attributes for tagged types. + 2025-05-30 Qing Zhao <qing.zhao@oracle.com> PR c/120354 diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index 1008bca..2b0bd66 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -10293,6 +10293,7 @@ finish_enum (tree enumtype, tree values, tree attributes) TYPE_UNSIGNED (tem) = TYPE_UNSIGNED (enumtype); TYPE_LANG_SPECIFIC (tem) = TYPE_LANG_SPECIFIC (enumtype); ENUM_UNDERLYING_TYPE (tem) = ENUM_UNDERLYING_TYPE (enumtype); + TYPE_PACKED (tem) = TYPE_PACKED (enumtype); } /* Finish debugging output for this type. */ diff --git a/gcc/c/c-objc-common.cc b/gcc/c/c-objc-common.cc index 2016eae..d574bc7 100644 --- a/gcc/c/c-objc-common.cc +++ b/gcc/c/c-objc-common.cc @@ -216,6 +216,11 @@ get_aka_type (tree type) return canonical ? canonical : type; } } + /* For tagged types ignore attributes because they will otherwise + be ignored later causing a warning inside diagnostics which leads + to an ICE. */ + if (RECORD_OR_UNION_TYPE_P (type) || TREE_CODE (type) == ENUMERAL_TYPE) + return build_qualified_type (result, TYPE_QUALS (type)); return build_type_attribute_qual_variant (result, TYPE_ATTRIBUTES (type), TYPE_QUALS (type)); } diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc index cc0ab12..85580c5 100644 --- a/gcc/c/c-parser.cc +++ b/gcc/c/c-parser.cc @@ -26966,17 +26966,30 @@ c_parser_omp_context_selector (c_parser *parser, enum omp_tss_code set, break; case OMP_TRAIT_PROPERTY_DEV_NUM_EXPR: case OMP_TRAIT_PROPERTY_BOOL_EXPR: - t = c_parser_expr_no_commas (parser, NULL).value; + { + c_expr texpr = c_parser_expr_no_commas (parser, NULL); + texpr = convert_lvalue_to_rvalue (token->location, texpr, + true, true); + t = texpr.value; + } if (t == error_mark_node) return error_mark_node; mark_exp_read (t); - t = c_fully_fold (t, false, NULL); - if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) + if (property_kind == OMP_TRAIT_PROPERTY_BOOL_EXPR) + { + t = c_objc_common_truthvalue_conversion (token->location, + t, + boolean_type_node); + if (t == error_mark_node) + return error_mark_node; + } + else if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) { error_at (token->location, "property must be integer expression"); return error_mark_node; } + t = c_fully_fold (t, false, NULL); properties = make_trait_property (NULL_TREE, t, properties); break; case OMP_TRAIT_PROPERTY_CLAUSE_LIST: diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 2f243ca..b59b5c8a 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -846,12 +846,7 @@ composite_type_internal (tree t1, tree t2, struct composite_cache* cache) n = finish_struct (input_location, n, fields, attributes, NULL, &expr); - n = qualify_type (n, t1); - - gcc_checking_assert (!TYPE_NAME (n) || comptypes (n, t1)); - gcc_checking_assert (!TYPE_NAME (n) || comptypes (n, t2)); - - return n; + return qualify_type (n, t1); } /* FALLTHRU */ case ENUMERAL_TYPE: @@ -1004,7 +999,15 @@ tree composite_type (tree t1, tree t2) { struct composite_cache cache = { }; - return composite_type_internal (t1, t2, &cache); + tree n = composite_type_internal (t1, t2, &cache); + /* For function and arrays there are some cases where qualifiers do + not match. See PR120510. */ + if (FUNCTION_TYPE != TREE_CODE (n) && ARRAY_TYPE != TREE_CODE (n)) + { + gcc_checking_assert (comptypes (n, t1)); + gcc_checking_assert (comptypes (n, t2)); + } + return n; } /* Return the type of a conditional expression between pointers to diff --git a/gcc/cobol/ChangeLog b/gcc/cobol/ChangeLog index 44bf89f..03243e9 100644 --- a/gcc/cobol/ChangeLog +++ b/gcc/cobol/ChangeLog @@ -1,3 +1,16 @@ +2025-06-02 Robert Dubner <rdubner@symas.com> + + PR cobol/119975 + * genapi.cc (parser_intrinsic_call_0): Use get_time_64() function. + * genutil.cc (get_time_64): Definition created. + * genutil.h (get_time_64): Declaration created. + +2025-06-01 Robert Dubner <rdubner@symas.com> + + PR cobol/119524 + * gengen.cc (gg_printf): Use the new __gg__fprintf_stderr() function + instead of generating a call to fprintf(). + 2025-05-20 Robert Dubner <rdubner@symas.com> James K. Lowden <jklowden@cobolworx.com> diff --git a/gcc/cobol/genapi.cc b/gcc/cobol/genapi.cc index 2ce9cad..5e983ab 100644 --- a/gcc/cobol/genapi.cc +++ b/gcc/cobol/genapi.cc @@ -10491,7 +10491,9 @@ parser_intrinsic_call_0(cbl_field_t *tgt, { // Pass __gg__when_compiled() the time from right now. struct timespec tp; - clock_gettime(CLOCK_REALTIME, &tp); // time_t tv_sec; long tv_nsec + uint64_t now = get_time_64(); + tp.tv_sec = now / 1000000000; + tp.tv_nsec = now % 1000000000; store_location_stuff(function_name); gg_call(VOID, diff --git a/gcc/cobol/gengen.cc b/gcc/cobol/gengen.cc index 91f67d5..a5f143c 100644 --- a/gcc/cobol/gengen.cc +++ b/gcc/cobol/gengen.cc @@ -2152,18 +2152,6 @@ gg_printf(const char *format_string, ...) int nargs = 0; tree args[ARG_LIMIT]; - // Because this routine is intended for debugging, we are sending the - // text to STDERR - - // Because we don't actually use stderr ourselves, we just pick it up as a - // VOID_P and pass it along to fprintf() - tree t_stderr = gg_declare_variable(VOID_P, "stderr", - NULL_TREE, - vs_external_reference); - - gg_push_context(); - - args[nargs++] = t_stderr; args[nargs++] = build_string_literal(strlen(format_string)+1, format_string); va_list ap; @@ -2197,7 +2185,7 @@ gg_printf(const char *format_string, ...) static tree function = NULL_TREE; if( !function ) { - function = gg_get_function_address(INT, "fprintf"); + function = gg_get_function_address(INT, "__gg__fprintf_stderr"); } tree stmt = build_call_array_loc (location_from_lineno(), @@ -2206,8 +2194,6 @@ gg_printf(const char *format_string, ...) nargs, args); gg_append_statement(stmt); - - gg_pop_context(); } tree diff --git a/gcc/cobol/genutil.cc b/gcc/cobol/genutil.cc index d0aaf2b3..e971043 100644 --- a/gcc/cobol/genutil.cc +++ b/gcc/cobol/genutil.cc @@ -2119,3 +2119,26 @@ qualified_data_location(cbl_refer_t &refer) return gg_add(member(refer.field->var_decl_node, "data"), refer_offset(refer)); } + +uint64_t +get_time_64() +{ + // This code was unabashedly stolen from gcc/timevar.cc. + // It returns the Unix epoch with nine decimal places. + + uint64_t retval = 0; + +#ifdef HAVE_CLOCK_GETTIME + struct timespec ts; + clock_gettime (CLOCK_REALTIME, &ts); + retval = ts.tv_sec * 1000000000 + ts.tv_nsec; + return retval; +#endif +#ifdef HAVE_GETTIMEOFDAY + struct timeval tv; + gettimeofday (&tv, NULL); + retval = tv.tv_sec * 1000000000 + tv.tv_usec * 1000; + return retval; +#endif + return retval; +}
\ No newline at end of file diff --git a/gcc/cobol/genutil.h b/gcc/cobol/genutil.h index 2f4bc36..43102d7 100644 --- a/gcc/cobol/genutil.h +++ b/gcc/cobol/genutil.h @@ -155,4 +155,7 @@ void build_array_of_fourplets( int ngroup, size_t N, cbl_refer_t *refers); void get_depending_on_value_from_odo(tree retval, cbl_field_t *odo); +uint64_t get_time_64(); + + #endif diff --git a/gcc/config/or1k/or1k.opt b/gcc/config/or1k/or1k.opt index 00c5560..d252de0 100644 --- a/gcc/config/or1k/or1k.opt +++ b/gcc/config/or1k/or1k.opt @@ -69,8 +69,8 @@ are used to perform unordered floating point compare and set flag operations. mcmodel= Target RejectNegative Joined Enum(or1k_cmodel_type) Var(or1k_code_model) Init(CMODEL_SMALL) Specify the code model used for accessing memory addresses. Specifying large -enables generating binaries with large global offset tables. By default the -value is small. +enables generating binaries with large global offset tables and calling +functions anywhere in an executable. By default the value is small. Enum Name(or1k_cmodel_type) Type(enum or1k_cmodel_type) diff --git a/gcc/config/or1k/predicates.md b/gcc/config/or1k/predicates.md index 11bb518..144f4d7 100644 --- a/gcc/config/or1k/predicates.md +++ b/gcc/config/or1k/predicates.md @@ -61,7 +61,8 @@ (match_test "TARGET_ROR")))) (define_predicate "call_insn_operand" - (ior (match_code "symbol_ref") + (ior (and (match_code "symbol_ref") + (match_test "!TARGET_CMODEL_LARGE")) (match_operand 0 "register_operand"))) (define_predicate "high_operand" diff --git a/gcc/config/riscv/autovec-opt.md b/gcc/config/riscv/autovec-opt.md index a972eda..19eb16c 100644 --- a/gcc/config/riscv/autovec-opt.md +++ b/gcc/config/riscv/autovec-opt.md @@ -1713,3 +1713,55 @@ <MODE>mode); } [(set_attr "type" "vialu")]) + +;; ============================================================================= +;; Combine vec_duplicate + op.vv to op.vf +;; Include +;; - vfmadd.vf +;; - vfmsub.vf +;; ============================================================================= + + +(define_insn_and_split "*<optab>_vf_<mode>" + [(set (match_operand:V_VLSF 0 "register_operand" "=vd") + (plus_minus:V_VLSF + (mult:V_VLSF + (vec_duplicate:V_VLSF + (match_operand:<VEL> 1 "register_operand" " f")) + (match_operand:V_VLSF 2 "register_operand" " 0")) + (match_operand:V_VLSF 3 "register_operand" " vr")))] + "TARGET_VECTOR && can_create_pseudo_p ()" + "#" + "&& 1" + [(const_int 0)] + { + rtx ops[] = {operands[0], operands[1], operands[2], operands[3], + operands[2]}; + riscv_vector::emit_vlmax_insn (code_for_pred_mul_scalar (<CODE>, <MODE>mode), + riscv_vector::TERNARY_OP_FRM_DYN, ops); + DONE; + } + [(set_attr "type" "vfmuladd")] +) + +(define_insn_and_split "*<optab>_vf_<mode>" + [(set (match_operand:V_VLSF 0 "register_operand" "=vd") + (plus_minus:V_VLSF + (match_operand:V_VLSF 3 "register_operand" " vr") + (mult:V_VLSF + (vec_duplicate:V_VLSF + (match_operand:<VEL> 1 "register_operand" " f")) + (match_operand:V_VLSF 2 "register_operand" " 0"))))] + "TARGET_VECTOR && can_create_pseudo_p ()" + "#" + "&& 1" + [(const_int 0)] + { + rtx ops[] = {operands[0], operands[1], operands[2], operands[3], + operands[2]}; + riscv_vector::emit_vlmax_insn (code_for_pred_mul_scalar (<CODE>, <MODE>mode), + riscv_vector::TERNARY_OP_FRM_DYN, ops); + DONE; + } + [(set_attr "type" "vfmuladd")] +) diff --git a/gcc/config/riscv/autovec.md b/gcc/config/riscv/autovec.md index 60c881b..c678eef 100644 --- a/gcc/config/riscv/autovec.md +++ b/gcc/config/riscv/autovec.md @@ -2493,7 +2493,8 @@ "TARGET_VECTOR" { insn_code icode = code_for_pred (UNSPEC_VAADD, <V_DOUBLE_TRUNC>mode); - riscv_vector::emit_vlmax_insn (icode, riscv_vector::BINARY_OP_VXRM_RDN, operands); + riscv_vector::emit_vlmax_insn (icode, riscv_vector::BINARY_OP_VXRM_RDN, + operands); DONE; } ) @@ -2527,7 +2528,8 @@ "TARGET_VECTOR" { insn_code icode = code_for_pred (UNSPEC_VAADDU, <MODE>mode); - riscv_vector::emit_vlmax_insn (icode, riscv_vector::BINARY_OP_VXRM_RDN, operands); + riscv_vector::emit_vlmax_insn (icode, riscv_vector::BINARY_OP_VXRM_RDN, + operands); DONE; }) @@ -2540,7 +2542,8 @@ "TARGET_VECTOR" { insn_code icode = code_for_pred (UNSPEC_VAADDU, <MODE>mode); - riscv_vector::emit_vlmax_insn (icode, riscv_vector::BINARY_OP_VXRM_RNU, operands); + riscv_vector::emit_vlmax_insn (icode, riscv_vector::BINARY_OP_VXRM_RNU, + operands); DONE; }) @@ -2565,7 +2568,8 @@ (match_operand:V_VLSF 1 "register_operand")] "TARGET_VECTOR && !flag_trapping_math && !flag_rounding_math" { - riscv_vector::expand_vec_ceil (operands[0], operands[1], <MODE>mode, <VCONVERT>mode); + riscv_vector::expand_vec_ceil (operands[0], operands[1], <MODE>mode, + <VCONVERT>mode); DONE; } ) @@ -2575,7 +2579,8 @@ (match_operand:V_VLSF 1 "register_operand")] "TARGET_VECTOR && !flag_trapping_math && !flag_rounding_math" { - riscv_vector::expand_vec_floor (operands[0], operands[1], <MODE>mode, <VCONVERT>mode); + riscv_vector::expand_vec_floor (operands[0], operands[1], <MODE>mode, + <VCONVERT>mode); DONE; } ) @@ -2585,7 +2590,8 @@ (match_operand:V_VLSF 1 "register_operand")] "TARGET_VECTOR && !flag_trapping_math && !flag_rounding_math" { - riscv_vector::expand_vec_nearbyint (operands[0], operands[1], <MODE>mode, <VCONVERT>mode); + riscv_vector::expand_vec_nearbyint (operands[0], operands[1], <MODE>mode, + <VCONVERT>mode); DONE; } ) @@ -2595,7 +2601,8 @@ (match_operand:V_VLSF 1 "register_operand")] "TARGET_VECTOR && !flag_trapping_math && !flag_rounding_math" { - riscv_vector::expand_vec_rint (operands[0], operands[1], <MODE>mode, <VCONVERT>mode); + riscv_vector::expand_vec_rint (operands[0], operands[1], <MODE>mode, + <VCONVERT>mode); DONE; } ) @@ -2605,7 +2612,8 @@ (match_operand:V_VLSF 1 "register_operand")] "TARGET_VECTOR && !flag_trapping_math && !flag_rounding_math" { - riscv_vector::expand_vec_round (operands[0], operands[1], <MODE>mode, <VCONVERT>mode); + riscv_vector::expand_vec_round (operands[0], operands[1], <MODE>mode, + <VCONVERT>mode); DONE; } ) @@ -2615,7 +2623,8 @@ (match_operand:V_VLSF 1 "register_operand")] "TARGET_VECTOR && !flag_trapping_math && !flag_rounding_math" { - riscv_vector::expand_vec_trunc (operands[0], operands[1], <MODE>mode, <VCONVERT>mode); + riscv_vector::expand_vec_trunc (operands[0], operands[1], <MODE>mode, + <VCONVERT>mode); DONE; } ) @@ -2625,7 +2634,8 @@ (match_operand:V_VLSF 1 "register_operand")] "TARGET_VECTOR && !flag_trapping_math && !flag_rounding_math" { - riscv_vector::expand_vec_roundeven (operands[0], operands[1], <MODE>mode, <VCONVERT>mode); + riscv_vector::expand_vec_roundeven (operands[0], operands[1], <MODE>mode, + <VCONVERT>mode); DONE; } ) @@ -2682,7 +2692,8 @@ (match_operand:V_VLS_F_CONVERT_SI 1 "register_operand")] "TARGET_VECTOR && !flag_trapping_math && !flag_rounding_math" { - riscv_vector::expand_vec_lceil (operands[0], operands[1], <MODE>mode, <V_F2SI_CONVERT>mode); + riscv_vector::expand_vec_lceil (operands[0], operands[1], <MODE>mode, + <V_F2SI_CONVERT>mode); DONE; } ) @@ -2692,7 +2703,8 @@ (match_operand:V_VLS_F_CONVERT_DI 1 "register_operand")] "TARGET_VECTOR && !flag_trapping_math && !flag_rounding_math" { - riscv_vector::expand_vec_lceil (operands[0], operands[1], <MODE>mode, <V_F2DI_CONVERT>mode); + riscv_vector::expand_vec_lceil (operands[0], operands[1], <MODE>mode, + <V_F2DI_CONVERT>mode); DONE; } ) @@ -2702,7 +2714,8 @@ (match_operand:V_VLS_F_CONVERT_SI 1 "register_operand")] "TARGET_VECTOR && !flag_trapping_math && !flag_rounding_math" { - riscv_vector::expand_vec_lfloor (operands[0], operands[1], <MODE>mode, <V_F2SI_CONVERT>mode); + riscv_vector::expand_vec_lfloor (operands[0], operands[1], <MODE>mode, + <V_F2SI_CONVERT>mode); DONE; } ) @@ -2712,7 +2725,8 @@ (match_operand:V_VLS_F_CONVERT_DI 1 "register_operand")] "TARGET_VECTOR && !flag_trapping_math && !flag_rounding_math" { - riscv_vector::expand_vec_lfloor (operands[0], operands[1], <MODE>mode, <V_F2DI_CONVERT>mode); + riscv_vector::expand_vec_lfloor (operands[0], operands[1], <MODE>mode, + <V_F2DI_CONVERT>mode); DONE; } ) @@ -2744,7 +2758,8 @@ (match_operand:V_VLSI 2 "register_operand")] "TARGET_VECTOR" { - riscv_vector::expand_vec_usadd (operands[0], operands[1], operands[2], <MODE>mode); + riscv_vector::expand_vec_usadd (operands[0], operands[1], operands[2], + <MODE>mode); DONE; } ) @@ -2755,7 +2770,8 @@ (match_operand:V_VLSI 2 "register_operand")] "TARGET_VECTOR" { - riscv_vector::expand_vec_ssadd (operands[0], operands[1], operands[2], <MODE>mode); + riscv_vector::expand_vec_ssadd (operands[0], operands[1], operands[2], + <MODE>mode); DONE; } ) @@ -2766,7 +2782,8 @@ (match_operand:V_VLSI 2 "register_operand")] "TARGET_VECTOR" { - riscv_vector::expand_vec_ussub (operands[0], operands[1], operands[2], <MODE>mode); + riscv_vector::expand_vec_ussub (operands[0], operands[1], operands[2], + <MODE>mode); DONE; } ) @@ -2777,7 +2794,8 @@ (match_operand:V_VLSI 2 "register_operand")] "TARGET_VECTOR" { - riscv_vector::expand_vec_sssub (operands[0], operands[1], operands[2], <MODE>mode); + riscv_vector::expand_vec_sssub (operands[0], operands[1], operands[2], + <MODE>mode); DONE; } ) diff --git a/gcc/config/riscv/riscv-c.cc b/gcc/config/riscv/riscv-c.cc index 1ff1968..d2c0af3 100644 --- a/gcc/config/riscv/riscv-c.cc +++ b/gcc/config/riscv/riscv-c.cc @@ -239,26 +239,22 @@ riscv_cpu_cpp_builtins (cpp_reader *pfile) size_t max_ext_len = 0; /* Figure out the max length of extension name for reserving buffer. */ - for (const riscv_subset_t *subset = subset_list->begin (); - subset != subset_list->end (); - subset = subset->next) - max_ext_len = MAX (max_ext_len, subset->name.length ()); + for (auto &subset : *subset_list) + max_ext_len = MAX (max_ext_len, subset.name.length ()); char *buf = (char *)alloca (max_ext_len + 10 /* For __riscv_ and '\0'. */); - for (const riscv_subset_t *subset = subset_list->begin (); - subset != subset_list->end (); - subset = subset->next) + for (auto &subset : *subset_list) { - int version_value = riscv_ext_version_value (subset->major_version, - subset->minor_version); + int version_value = riscv_ext_version_value (subset.major_version, + subset.minor_version); /* Special rule for zicsr and zifencei, it's used for ISA spec 2.2 or earlier. */ - if ((subset->name == "zicsr" || subset->name == "zifencei") + if ((subset.name == "zicsr" || subset.name == "zifencei") && version_value == 0) version_value = riscv_ext_version_value (2, 0); - sprintf (buf, "__riscv_%s", subset->name.c_str ()); + sprintf (buf, "__riscv_%s", subset.name.c_str ()); builtin_define_with_int_value (buf, version_value); } } diff --git a/gcc/config/riscv/riscv-ext.def b/gcc/config/riscv/riscv-ext.def index dbda8de..d0adc2b 100644 --- a/gcc/config/riscv/riscv-ext.def +++ b/gcc/config/riscv/riscv-ext.def @@ -1676,6 +1676,19 @@ DEFINE_RISCV_EXT( /* EXTRA_EXTENSION_FLAGS */ 0) DEFINE_RISCV_EXT( + /* NAME */ smcntrpmf, + /* UPPERCAE_NAME */ SMCNTRPMF, + /* FULL_NAME */ "Cycle and instret privilege mode filtering", + /* DESC */ "", + /* URL */ , + /* DEP_EXTS */ ({"zicsr"}), + /* SUPPORTED_VERSIONS */ ({{1, 0}}), + /* FLAG_GROUP */ sm, + /* BITMASK_GROUP_ID */ BITMASK_NOT_YET_ALLOCATED, + /* BITMASK_BIT_POSITION*/ BITMASK_NOT_YET_ALLOCATED, + /* EXTRA_EXTENSION_FLAGS */ 0) + +DEFINE_RISCV_EXT( /* NAME */ smepmp, /* UPPERCAE_NAME */ SMEPMP, /* FULL_NAME */ "PMP Enhancements for memory access and execution prevention on Machine mode", diff --git a/gcc/config/riscv/riscv-ext.opt b/gcc/config/riscv/riscv-ext.opt index 5e9c5f5..c0dcde6 100644 --- a/gcc/config/riscv/riscv-ext.opt +++ b/gcc/config/riscv/riscv-ext.opt @@ -335,6 +335,8 @@ Mask(SHVSATPA) Var(riscv_sh_subext) Mask(SMAIA) Var(riscv_sm_subext) +Mask(SMCNTRPMF) Var(riscv_sm_subext) + Mask(SMEPMP) Var(riscv_sm_subext) Mask(SMMPM) Var(riscv_sm_subext) diff --git a/gcc/config/riscv/riscv-opts.h b/gcc/config/riscv/riscv-opts.h index c02c599..e1a820b 100644 --- a/gcc/config/riscv/riscv-opts.h +++ b/gcc/config/riscv/riscv-opts.h @@ -164,6 +164,7 @@ enum riscv_tls_type { (TARGET_VECTOR && riscv_mautovec_segment) #define GPR2VR_COST_UNPROVIDED -1 +#define FPR2VR_COST_UNPROVIDED -1 /* Extra extension flags, used for carry extra info for a RISC-V extension. */ enum diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h index d8c8f6b..a033120 100644 --- a/gcc/config/riscv/riscv-protos.h +++ b/gcc/config/riscv/riscv-protos.h @@ -841,6 +841,7 @@ const struct riscv_tune_info * riscv_parse_tune (const char *, bool); const cpu_vector_cost *get_vector_costs (); int get_gr2vr_cost (); +int get_fr2vr_cost (); enum { diff --git a/gcc/config/riscv/riscv-subset.h b/gcc/config/riscv/riscv-subset.h index c5d9fab..a35537d 100644 --- a/gcc/config/riscv/riscv-subset.h +++ b/gcc/config/riscv/riscv-subset.h @@ -109,9 +109,6 @@ public: static riscv_subset_list *parse (const char *, location_t); const char *parse_single_ext (const char *, bool exact_single_p = true); - const riscv_subset_t *begin () const {return m_head;}; - const riscv_subset_t *end () const {return NULL;}; - int match_score (riscv_subset_list *) const; void set_loc (location_t); @@ -119,6 +116,65 @@ public: void set_allow_adding_dup (bool v) { m_allow_adding_dup = v; } void finalize (); + + class iterator + { + public: + explicit iterator(riscv_subset_t *node) : m_node(node) {} + + riscv_subset_t &operator*() const { return *m_node; } + riscv_subset_t *operator->() const { return m_node; } + + iterator &operator++() + { + if (m_node) + m_node = m_node->next; + return *this; + } + + bool operator!=(const iterator &other) const + { + return m_node != other.m_node; + } + + bool operator==(const iterator &other) const + { + return m_node == other.m_node; + } + + private: + riscv_subset_t *m_node; + }; + + iterator begin() { return iterator(m_head); } + iterator end() { return iterator(nullptr); } + + class const_iterator + { + public: + explicit const_iterator(const riscv_subset_t *node) : m_node(node) {} + + const riscv_subset_t &operator*() const { return *m_node; } + const riscv_subset_t *operator->() const { return m_node; } + + const_iterator &operator++() + { + if (m_node) + m_node = m_node->next; + return *this; + } + + bool operator!=(const const_iterator &other) const + { + return m_node != other.m_node; + } + + private: + const riscv_subset_t *m_node; + }; + + const_iterator begin() const { return const_iterator(m_head); } + const_iterator end() const { return const_iterator(nullptr); } }; extern const riscv_subset_list *riscv_cmdline_subset_list (void); diff --git a/gcc/config/riscv/riscv-v.cc b/gcc/config/riscv/riscv-v.cc index 6162797..a41317f 100644 --- a/gcc/config/riscv/riscv-v.cc +++ b/gcc/config/riscv/riscv-v.cc @@ -5567,6 +5567,7 @@ expand_vx_binary_vec_vec_dup (rtx op_0, rtx op_1, rtx op_2, case IOR: case XOR: case MULT: + case DIV: icode = code_for_pred_scalar (code, mode); break; default: diff --git a/gcc/config/riscv/riscv-vector-costs.cc b/gcc/config/riscv/riscv-vector-costs.cc index a39b611..4d8170d 100644 --- a/gcc/config/riscv/riscv-vector-costs.cc +++ b/gcc/config/riscv/riscv-vector-costs.cc @@ -1099,8 +1099,8 @@ costs::adjust_stmt_cost (enum vect_cost_for_stmt kind, loop_vec_info loop, switch (kind) { case scalar_to_vec: - stmt_cost += (FLOAT_TYPE_P (vectype) ? costs->regmove->FR2VR - : get_gr2vr_cost ()); + stmt_cost + += (FLOAT_TYPE_P (vectype) ? get_fr2vr_cost () : get_gr2vr_cost ()); break; case vec_to_scalar: stmt_cost += (FLOAT_TYPE_P (vectype) ? costs->regmove->VR2FR diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index d3cee96..b168a64 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -3891,6 +3891,25 @@ riscv_extend_cost (rtx op, bool unsigned_p) return COSTS_N_INSNS (2); } +/* Return the cost of the vector binary rtx like add, minus, mult. + The cost of gr2vr will be appended if there one of the op comes + from the VEC_DUPLICATE. */ + +static int +get_vector_binary_rtx_cost (rtx x, int gr2vr_cost) +{ + gcc_assert (riscv_v_ext_mode_p (GET_MODE (x))); + + rtx op_0 = XEXP (x, 0); + rtx op_1 = XEXP (x, 1); + + if (GET_CODE (op_0) == VEC_DUPLICATE + || GET_CODE (op_1) == VEC_DUPLICATE) + return (gr2vr_cost + 1) * COSTS_N_INSNS (1); + else + return COSTS_N_INSNS (1); +} + /* Implement TARGET_RTX_COSTS. */ #define SINGLE_SHIFT_COST 1 @@ -3904,6 +3923,7 @@ riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN if (riscv_v_ext_mode_p (mode)) { int gr2vr_cost = get_gr2vr_cost (); + int fr2vr_cost = get_fr2vr_cost (); switch (outer_code) { @@ -3914,6 +3934,21 @@ riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN case VEC_DUPLICATE: *total = gr2vr_cost * COSTS_N_INSNS (1); break; + case IF_THEN_ELSE: + { + rtx op_1 = XEXP (x, 1); + + switch (GET_CODE (op_1)) + { + case DIV: + *total = get_vector_binary_rtx_cost (op_1, gr2vr_cost); + break; + default: + *total = COSTS_N_INSNS (1); + break; + } + } + break; case PLUS: case MINUS: case AND: @@ -3923,14 +3958,29 @@ riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN { rtx op_0 = XEXP (x, 0); rtx op_1 = XEXP (x, 1); + rtx op; if (GET_CODE (op_0) == VEC_DUPLICATE || GET_CODE (op_1) == VEC_DUPLICATE) - *total = (gr2vr_cost + 1) * COSTS_N_INSNS (1); - else - *total = COSTS_N_INSNS (1); + { + *total = (gr2vr_cost + 1) * COSTS_N_INSNS (1); + break; + } + else if (GET_CODE (op = op_0) == MULT + || GET_CODE (op = op_1) == MULT) + { + rtx mult_op0 = XEXP (op, 0); + if (GET_CODE (mult_op0) == VEC_DUPLICATE) + { + if (FLOAT_MODE_P (mode)) + *total = (fr2vr_cost + 1) * COSTS_N_INSNS (1); + else + *total = (gr2vr_cost + 1) * COSTS_N_INSNS (1); + break; + } + } } - break; + /* Fall through. */ default: *total = COSTS_N_INSNS (1); break; @@ -9781,7 +9831,7 @@ riscv_register_move_cost (machine_mode mode, if (from_is_gpr) return get_gr2vr_cost (); else if (from_is_fpr) - return get_vector_costs ()->regmove->FR2VR; + return get_fr2vr_cost (); } return riscv_secondary_memory_needed (mode, from, to) ? 8 : 2; @@ -12647,6 +12697,21 @@ get_gr2vr_cost () return cost; } +/* Return the cost of moving data from floating-point to vector register. + It will take the value of --param=fpr2vr-cost if it is provided. + Otherwise the default regmove->FR2VR will be returned. */ + +int +get_fr2vr_cost () +{ + int cost = get_vector_costs ()->regmove->FR2VR; + + if (fpr2vr_cost != FPR2VR_COST_UNPROVIDED) + cost = fpr2vr_cost; + + return cost; +} + /* Implement targetm.vectorize.builtin_vectorization_cost. */ static int @@ -12712,8 +12777,7 @@ riscv_builtin_vectorization_cost (enum vect_cost_for_stmt type_of_cost, case vec_construct: { /* TODO: This is too pessimistic in case we can splat. */ - int regmove_cost = fp ? costs->regmove->FR2VR - : get_gr2vr_cost (); + int regmove_cost = fp ? get_fr2vr_cost () : get_gr2vr_cost (); return (regmove_cost + common_costs->scalar_to_vec_cost) * estimated_poly_value (TYPE_VECTOR_SUBPARTS (vectype)); } diff --git a/gcc/config/riscv/riscv.opt b/gcc/config/riscv/riscv.opt index b2b9d33..6543fd1 100644 --- a/gcc/config/riscv/riscv.opt +++ b/gcc/config/riscv/riscv.opt @@ -286,6 +286,10 @@ Max number of bytes to compare as part of inlined strcmp/strncmp routines (defau Target RejectNegative Joined UInteger Var(gpr2vr_cost) Init(GPR2VR_COST_UNPROVIDED) Set the cost value of the rvv instruction when operate from GPR to VR. +-param=fpr2vr-cost= +Target RejectNegative Joined UInteger Var(fpr2vr_cost) Init(FPR2VR_COST_UNPROVIDED) +Set the cost value of the rvv instruction when operate from FPR to VR. + -param=riscv-autovec-mode= Target Undocumented RejectNegative Joined Var(riscv_autovec_mode) Save Set the only autovec mode to try. diff --git a/gcc/config/riscv/t-riscv b/gcc/config/riscv/t-riscv index 854daa9..32092d8 100644 --- a/gcc/config/riscv/t-riscv +++ b/gcc/config/riscv/t-riscv @@ -198,19 +198,24 @@ RISCV_EXT_DEFS = \ $(srcdir)/config/riscv/riscv-ext.opt: $(RISCV_EXT_DEFS) -build/gen-riscv-ext-opt$(build_exeext): $(srcdir)/config/riscv/gen-riscv-ext-opt.cc \ +build/gen-riscv-ext-opt.o: $(srcdir)/config/riscv/gen-riscv-ext-opt.cc \ $(RISCV_EXT_DEFS) - $(CXX_FOR_BUILD) $(CXXFLAGS_FOR_BUILD) $< -o $@ + $(CXX_FOR_BUILD) $(CXXFLAGS_FOR_BUILD) -c $< -o $@ + +build/gen-riscv-ext-opt$(build_exeext): build/gen-riscv-ext-opt.o + $(LINKER_FOR_BUILD) $(BUILD_LINKERFLAGS) $(BUILD_LDFLAGS) -o $@ $< s-riscv-ext.opt: build/gen-riscv-ext-opt$(build_exeext) $(RUN_GEN) build/gen-riscv-ext-opt$(build_exeext) > tmp-riscv-ext.opt $(SHELL) $(srcdir)/../move-if-change tmp-riscv-ext.opt $(srcdir)/config/riscv/riscv-ext.opt $(STAMP) s-riscv-ext.opt -build/gen-riscv-ext-texi$(build_exeext): $(srcdir)/config/riscv/gen-riscv-ext-texi.cc \ +build/gen-riscv-ext-texi.o: $(srcdir)/config/riscv/gen-riscv-ext-texi.cc \ $(RISCV_EXT_DEFS) - $(CXX_FOR_BUILD) $(CXXFLAGS_FOR_BUILD) $< -o $@ + $(CXX_FOR_BUILD) $(CXXFLAGS_FOR_BUILD) -c $< -o $@ +build/gen-riscv-ext-texi$(build_exeext): build/gen-riscv-ext-texi.o + $(LINKER_FOR_BUILD) $(BUILD_LINKERFLAGS) $(BUILD_LDFLAGS) -o $@ $< $(srcdir)/doc/riscv-ext.texi: $(RISCV_EXT_DEFS) $(srcdir)/doc/riscv-ext.texi: s-riscv-ext.texi ; @true diff --git a/gcc/config/riscv/vector-iterators.md b/gcc/config/riscv/vector-iterators.md index 2bd99ee..62fd1c0 100644 --- a/gcc/config/riscv/vector-iterators.md +++ b/gcc/config/riscv/vector-iterators.md @@ -4042,7 +4042,7 @@ ]) (define_code_iterator any_int_binop_no_shift_vx [ - plus minus and ior xor mult + plus minus and ior xor mult div ]) (define_code_iterator any_int_unop [neg not]) diff --git a/gcc/config/xtensa/xtensa.cc b/gcc/config/xtensa/xtensa.cc index e03dee3..a9d67a5 100644 --- a/gcc/config/xtensa/xtensa.cc +++ b/gcc/config/xtensa/xtensa.cc @@ -48,7 +48,6 @@ along with GCC; see the file COPYING3. If not see #include "alias.h" #include "explow.h" #include "expr.h" -#include "reload.h" #include "langhooks.h" #include "gimplify.h" #include "builtins.h" @@ -197,6 +196,8 @@ static void xtensa_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED, tree function); static rtx xtensa_delegitimize_address (rtx); +static reg_class_t xtensa_ira_change_pseudo_allocno_class (int, reg_class_t, + reg_class_t); @@ -366,6 +367,9 @@ static rtx xtensa_delegitimize_address (rtx); #undef TARGET_DIFFERENT_ADDR_DISPLACEMENT_P #define TARGET_DIFFERENT_ADDR_DISPLACEMENT_P hook_bool_void_true +#undef TARGET_IRA_CHANGE_PSEUDO_ALLOCNO_CLASS +#define TARGET_IRA_CHANGE_PSEUDO_ALLOCNO_CLASS xtensa_ira_change_pseudo_allocno_class + struct gcc_target targetm = TARGET_INITIALIZER; @@ -4432,12 +4436,10 @@ xtensa_register_move_cost (machine_mode mode ATTRIBUTE_UNUSED, && reg_class_subset_p (to, AR_REGS))) return 2; - /* The cost between AR_REGS and FR_REGS must be <= 8 (2x the default - MEMORY_MOVE_COST) to avoid unwanted spills, and > 4 (2x the above - case) to avoid excessive register-to-register moves. */ + /* The cost between AR_REGS and FR_REGS is 2 (the default value). */ if ((reg_class_subset_p (from, AR_REGS) && to == FP_REGS) || (from == FP_REGS && reg_class_subset_p (to, AR_REGS))) - return 5; + return 2; if ((reg_class_subset_p (from, AR_REGS) && to == ACC_REG) || (from == ACC_REG && reg_class_subset_p (to, AR_REGS))) @@ -5433,4 +5435,20 @@ xtensa_delegitimize_address (rtx op) return op; } +/* Implement TARGET_IRA_CHANGE_PSEUDO_ALLOCNO_CLASS, in order to tell + the register allocator to avoid using ALL_REGS rclass. */ + +static reg_class_t +xtensa_ira_change_pseudo_allocno_class (int regno, reg_class_t allocno_class, + reg_class_t best_class) +{ + if (allocno_class != ALL_REGS) + return allocno_class; + + if (best_class != ALL_REGS) + return best_class; + + return FLOAT_MODE_P (PSEUDO_REGNO_MODE (regno)) ? FP_REGS : AR_REGS; +} + #include "gt-xtensa.h" diff --git a/gcc/config/xtensa/xtensa.md b/gcc/config/xtensa/xtensa.md index 88f011c..c7ac456 100644 --- a/gcc/config/xtensa/xtensa.md +++ b/gcc/config/xtensa/xtensa.md @@ -1453,7 +1453,7 @@ }) (define_insn "movsf_internal" - [(set (match_operand:SF 0 "nonimmed_operand" "=f,f,^U,D,a,D,R,a,f,a,a,W,a,U") + [(set (match_operand:SF 0 "nonimmed_operand" "=f,f,U,D,a,D,R,a,f,a,a,W,a,U") (match_operand:SF 1 "move_operand" "f,^U,f,d,T,R,d,r,r,f,Y,iF,U,r"))] "((register_operand (operands[0], SFmode) || register_operand (operands[1], SFmode)) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 3f05db3..a8f2b4e 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,54 @@ +2025-06-02 Jason Merrill <jason@redhat.com> + + PR c++/107600 + * method.cc (destructible_expr): Fix refs and arrays of unknown + bound. + +2025-06-02 Jason Merrill <jason@redhat.com> + + PR c++/120506 + * constexpr.cc (cxx_eval_outermost_constant_expr): Always check + CONSTRUCTOR_NO_CLEARING. + +2025-06-02 Iain Sandoe <iain@sandoe.co.uk> + + * coroutines.cc (build_actor_fn): Remove an unused + label, guard the frame deallocation correctly, use + simpler APIs to build if and return statements. + +2025-06-02 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/118903 + * constexpr.cc (potential_constant_expression_1): Emit + an error when co_await et. al. are used in constexpr + contexts. + +2025-06-02 Iain Sandoe <iain@sandoe.co.uk> + + * error.cc (dump_expr): Add co_await, co_yield and co_return. + +2025-06-02 Jason Merrill <jason@redhat.com> + + PR c++/107600 + * method.cc (destructible_expr): Handle non-classes. + (constructible_expr): Check for abstract class here... + (is_xible_helper): ...not here. + +2025-06-02 Jason Merrill <jason@redhat.com> + + PR c++/107600 + * semantics.cc (trait_expr_value) [CPTK_HAS_TRIVIAL_DESTRUCTOR]: + Add cp_unevaluated. + +2025-06-02 Sandra Loosemore <sloosemore@baylibre.com> + + * cp-tree.h (maybe_convert_cond): Declare. + * parser.cc (cp_parser_omp_context_selector): Call + maybe_convert_cond and fold_build_cleanup_point_expr on the + expression for OMP_TRAIT_PROPERTY_BOOL_EXPR. + * pt.cc (tsubst_omp_context_selector): Likewise. + * semantics.cc (maybe_convert_cond): Remove static declaration. + 2025-05-30 Jason Merrill <jason@redhat.com> PR c++/113563 diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc index 61481c6..b9fdc94 100644 --- a/gcc/cp/constexpr.cc +++ b/gcc/cp/constexpr.cc @@ -9278,8 +9278,7 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, /* After verify_constant because reduced_constant_expression_p can unset CONSTRUCTOR_NO_CLEARING. */ - if (!non_constant_p - && TREE_CODE (r) == CONSTRUCTOR && CONSTRUCTOR_NO_CLEARING (r)) + if (TREE_CODE (r) == CONSTRUCTOR && CONSTRUCTOR_NO_CLEARING (r)) { if (!allow_non_constant) error ("%qE is not a constant expression because it refers to " @@ -11024,6 +11023,9 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, case CO_AWAIT_EXPR: case CO_YIELD_EXPR: case CO_RETURN_EXPR: + if (flags & tf_error) + constexpr_error (cp_expr_loc_or_loc (t, input_location), fundef_p, + "%qE is not a constant expression", t); return false; /* Assume a TU-local entity is not constant, we'll error later when diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index 5815a8c..7f5d30c 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -2543,8 +2543,8 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody, /* Finish the resume dispatcher. */ finish_switch_stmt (dispatcher); - finish_else_clause (lsb_if); + finish_else_clause (lsb_if); finish_if_stmt (lsb_if); /* If we reach here then we've hit UB. */ @@ -2583,69 +2583,53 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody, /* Add in our function body with the co_returns rewritten to final form. */ add_stmt (fnbody); - /* now do the tail of the function. */ + /* Now do the tail of the function; first cleanups. */ r = build_stmt (loc, LABEL_EXPR, del_promise_label); add_stmt (r); - /* Destructors for the things we built explicitly. */ + /* Destructors for the things we built explicitly. + promise... */ if (tree c = cxx_maybe_build_cleanup (promise_proxy, tf_warning_or_error)) - add_stmt (c); - - tree del_frame_label - = create_named_label_with_ctx (loc, "coro.delete.frame", actor); - r = build_stmt (loc, LABEL_EXPR, del_frame_label); - add_stmt (r); - - /* Here deallocate the frame (if we allocated it), which we will have at - present. */ - tree fnf2_x - = coro_build_frame_access_expr (actor_frame, coro_frame_needs_free_id, - false, tf_warning_or_error); + finish_expr_stmt (c); - tree need_free_if = begin_if_stmt (); - fnf2_x = build1 (CONVERT_EXPR, integer_type_node, fnf2_x); - tree cmp = build2 (NE_EXPR, integer_type_node, fnf2_x, integer_zero_node); - finish_if_stmt_cond (cmp, need_free_if); + /* Argument copies ... */ while (!param_dtor_list->is_empty ()) { tree parm_id = param_dtor_list->pop (); tree a = coro_build_frame_access_expr (actor_frame, parm_id, false, tf_warning_or_error); if (tree dtor = cxx_maybe_build_cleanup (a, tf_warning_or_error)) - add_stmt (dtor); + finish_expr_stmt (dtor); } + /* Here deallocate the frame (if we allocated it), which we will have at + present. */ + tree fnf2_x + = coro_build_frame_access_expr (actor_frame, coro_frame_needs_free_id, + false, tf_warning_or_error); + tree need_free_if = begin_if_stmt (); + finish_if_stmt_cond (fnf2_x, need_free_if); + /* Build the frame DTOR. */ tree del_coro_fr = build_coroutine_frame_delete_expr (actor_fp, frame_size, promise_type, loc); finish_expr_stmt (del_coro_fr); finish_then_clause (need_free_if); - tree scope = IF_SCOPE (need_free_if); - IF_SCOPE (need_free_if) = NULL; - r = do_poplevel (scope); - add_stmt (r); + finish_if_stmt (need_free_if); - /* done. */ - r = build_stmt (loc, RETURN_EXPR, NULL); - suppress_warning (r); /* We don't want a warning about this. */ - r = maybe_cleanup_point_expr_void (r); - add_stmt (r); + /* Done. */ + finish_return_stmt (NULL_TREE); /* This is the suspend return point. */ - r = build_stmt (loc, LABEL_EXPR, ret_label); - add_stmt (r); + add_stmt (build_stmt (loc, LABEL_EXPR, ret_label)); - r = build_stmt (loc, RETURN_EXPR, NULL); - suppress_warning (r); /* We don't want a warning about this. */ - r = maybe_cleanup_point_expr_void (r); - add_stmt (r); + finish_return_stmt (NULL_TREE); /* This is the 'continuation' return point. For such a case we have a coro handle (from the await_suspend() call) and we want handle.resume() to execute as a tailcall allowing arbitrary chaining of coroutines. */ - r = build_stmt (loc, LABEL_EXPR, continue_label); - add_stmt (r); + add_stmt (build_stmt (loc, LABEL_EXPR, continue_label)); /* Should have been set earlier by the coro_initialized code. */ gcc_assert (void_coro_handle_address); diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index e5e20e1..3cf4a76 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7956,6 +7956,7 @@ extern bool perform_deferred_access_checks (tsubst_flags_t); extern bool perform_or_defer_access_check (tree, tree, tree, tsubst_flags_t, access_failure_info *afi = NULL); +extern tree maybe_convert_cond (tree); /* RAII sentinel to ensures that deferred access checks are popped before a function returns. */ diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc index 6364345..69da381 100644 --- a/gcc/cp/error.cc +++ b/gcc/cp/error.cc @@ -3269,6 +3269,27 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags) break; } + case CO_AWAIT_EXPR: + pp_cxx_ws_string (pp, "co_await"); + pp_cxx_whitespace (pp); + dump_expr (pp, TREE_OPERAND (t, 0), flags); + break; + + case CO_YIELD_EXPR: + pp_cxx_ws_string (pp, "co_yield"); + pp_cxx_whitespace (pp); + dump_expr (pp, TREE_OPERAND (t, 0), flags); + break; + + case CO_RETURN_EXPR: + pp_cxx_ws_string (pp, "co_return"); + if (TREE_OPERAND (t, 0)) + { + pp_cxx_whitespace (pp); + dump_expr (pp, TREE_OPERAND (t, 0), flags); + } + break; + /* This list is incomplete, but should suffice for now. It is very important that `sorry' does not call `report_error_function'. That could cause an infinite loop. */ diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc index 3a675d9..67a80a3 100644 --- a/gcc/cp/method.cc +++ b/gcc/cp/method.cc @@ -2251,6 +2251,8 @@ constructible_expr (tree to, tree from) const int len = TREE_VEC_LENGTH (from); if (CLASS_TYPE_P (to)) { + if (ABSTRACT_CLASS_TYPE_P (to)) + return error_mark_node; tree ctype = to; vec<tree, va_gc> *args = NULL; if (!TYPE_REF_P (to)) @@ -2330,17 +2332,35 @@ constructible_expr (tree to, tree from) return expr; } -/* Return declval<T>().~T() treated as an unevaluated operand. */ +/* Valid if "Either T is a reference type, or T is a complete object type for + which the expression declval<U&>().~U() is well-formed when treated as an + unevaluated operand ([expr.context]), where U is remove_all_extents_t<T>." + + For a class U, return the destructor call; otherwise return void_node if + valid or error_mark_node if not. */ static tree destructible_expr (tree to) { cp_unevaluated cp_uneval_guard; int flags = LOOKUP_NORMAL|LOOKUP_DESTRUCTOR; - to = build_trait_object (to); - tree r = build_delete (input_location, TREE_TYPE (to), to, - sfk_complete_destructor, flags, 0, tf_none); - return r; + if (TYPE_REF_P (to)) + return void_node; + if (!COMPLETE_TYPE_P (complete_type (to))) + return error_mark_node; + to = strip_array_types (to); + if (CLASS_TYPE_P (to)) + { + to = build_trait_object (to); + return build_delete (input_location, TREE_TYPE (to), to, + sfk_complete_destructor, flags, 0, tf_none); + } + /* [expr.prim.id.dtor] If the id-expression names a pseudo-destructor, T + shall be a scalar type.... */ + else if (scalarish_type_p (to)) + return void_node; + else + return error_mark_node; } /* Returns a tree iff TO is assignable (if CODE is MODIFY_EXPR) or @@ -2352,7 +2372,7 @@ is_xible_helper (enum tree_code code, tree to, tree from, bool trivial) { to = complete_type (to); deferring_access_check_sentinel acs (dk_no_deferred); - if (VOID_TYPE_P (to) || ABSTRACT_CLASS_TYPE_P (to) + if (VOID_TYPE_P (to) || (from && FUNC_OR_METHOD_TYPE_P (from) && (TYPE_READONLY (from) || FUNCTION_REF_QUALIFIED (from)))) return error_mark_node; diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h index 4216a51..2fa736b 100644 --- a/gcc/cp/name-lookup.h +++ b/gcc/cp/name-lookup.h @@ -501,6 +501,10 @@ enum WMB_Flags WMB_Hidden = 1 << 3, WMB_Purview = 1 << 4, }; +inline WMB_Flags operator|(WMB_Flags x, WMB_Flags y) +{ return WMB_Flags(+x|y); } +inline WMB_Flags& operator|=(WMB_Flags& x, WMB_Flags y) +{ return x = x|y; } extern unsigned walk_module_binding (tree binding, bitmap partitions, bool (*)(tree decl, WMB_Flags, void *data), diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 3d30339..8633763 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -49986,12 +49986,25 @@ cp_parser_omp_context_selector (cp_parser *parser, enum omp_tss_code set, && !value_dependent_expression_p (t)) { t = fold_non_dependent_expr (t); - if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) + if (property_kind == OMP_TRAIT_PROPERTY_BOOL_EXPR) { - error_at (token->location, - "property must be integer expression"); - return error_mark_node; + t = maybe_convert_cond (t); + if (t == error_mark_node) + return error_mark_node; + } + else + { + t = convert_from_reference (t); + if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + error_at (token->location, + "property must be integer expression"); + return error_mark_node; + } } + if (!processing_template_decl + && TREE_CODE (t) != CLEANUP_POINT_EXPR) + t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); } properties = make_trait_property (NULL_TREE, t, properties); break; diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index ccb623d..c5a3abe 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -18380,7 +18380,9 @@ tsubst_omp_context_selector (tree ctx, tree args, tsubst_flags_t complain, } } - switch (omp_ts_map[OMP_TS_CODE (sel)].tp_type) + enum omp_tp_type property_kind + = omp_ts_map[OMP_TS_CODE (sel)].tp_type; + switch (property_kind) { case OMP_TRAIT_PROPERTY_DEV_NUM_EXPR: case OMP_TRAIT_PROPERTY_BOOL_EXPR: @@ -18388,12 +18390,26 @@ tsubst_omp_context_selector (tree ctx, tree args, tsubst_flags_t complain, args, complain, in_decl); t = fold_non_dependent_expr (t); if (!value_dependent_expression_p (t) - && !type_dependent_expression_p (t) - && !INTEGRAL_TYPE_P (TREE_TYPE (t))) - error_at (cp_expr_loc_or_input_loc (t), - "property must be integer expression"); - else - properties = make_trait_property (NULL_TREE, t, NULL_TREE); + && !type_dependent_expression_p (t)) + { + if (property_kind == OMP_TRAIT_PROPERTY_BOOL_EXPR) + t = maybe_convert_cond (t); + else + { + t = convert_from_reference (t); + if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + error_at (cp_expr_loc_or_input_loc (t), + "property must be integer expression"); + t = error_mark_node; + } + } + } + if (t != error_mark_node + && !processing_template_decl + && TREE_CODE (t) != CLEANUP_POINT_EXPR) + t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); + properties = make_trait_property (NULL_TREE, t, NULL_TREE); break; case OMP_TRAIT_PROPERTY_CLAUSE_LIST: if (OMP_TS_CODE (sel) == OMP_TRAIT_CONSTRUCT_SIMD) diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index cafc9d0..7bc346b 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -52,7 +52,6 @@ along with GCC; see the file COPYING3. If not see during template instantiation, which may be regarded as a degenerate form of parsing. */ -static tree maybe_convert_cond (tree); static tree finalize_nrv_r (tree *, int *, void *); /* Used for OpenMP non-static data member privatization. */ @@ -1117,7 +1116,7 @@ annotate_saver::restore (tree new_inner) statement. Convert it to a boolean value, if appropriate. In addition, verify sequence points if -Wsequence-point is enabled. */ -static tree +tree maybe_convert_cond (tree cond) { /* Empty conditions remain empty. */ @@ -13420,6 +13419,7 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2) if (CLASS_TYPE_P (type1) && type_build_dtor_call (type1)) { deferring_access_check_sentinel dacs (dk_no_check); + cp_unevaluated un; tree fn = get_dtor (type1, tf_none); if (!fn && !seen_error ()) warning (0, "checking %qs for type %qT with a destructor that " diff --git a/gcc/doc/gm2.texi b/gcc/doc/gm2.texi index 8293da4..9bd0f0d 100644 --- a/gcc/doc/gm2.texi +++ b/gcc/doc/gm2.texi @@ -540,6 +540,9 @@ lines compiled. @item -fm2-strict-type experimental flag to turn on the new strict type checker. +@item -fm2-strict-type-reason +provides more detail why the types are incompatible. + @item -fm2-whole-program compile all implementation modules and program module at once. Notice that you need to take care if you are compiling different dialect diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 0150ad0..8de0085 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -30911,12 +30911,13 @@ to store the immediate to a register first. @opindex mcmodel= @opindex mcmodel=small @item -mcmodel=small -Generate OpenRISC code for the small model: The GOT is limited to 64k. This is -the default model. +Generate OpenRISC code for the small model: The GOT is limited to 64k and +function call jumps are limited to 64M offsets. This is the default model. @opindex mcmodel=large @item -mcmodel=large -Generate OpenRISC code for the large model: The GOT may grow up to 4G in size. +Generate OpenRISC code for the large model: The GOT may grow up to 4G in size +and function call jumps can target the full 4G address space. @end table diff --git a/gcc/doc/riscv-ext.texi b/gcc/doc/riscv-ext.texi index 7a22d84..e64c0d6 100644 --- a/gcc/doc/riscv-ext.texi +++ b/gcc/doc/riscv-ext.texi @@ -494,6 +494,10 @@ @tab 1.0 @tab Advanced interrupt architecture extension +@item smcntrpmf +@tab 1.0 +@tab Cycle and instret privilege mode filtering + @item smepmp @tab 1.0 @tab PMP Enhancements for memory access and execution prevention on Machine mode diff --git a/gcc/doc/sourcebuild.texi b/gcc/doc/sourcebuild.texi index 9043002..6c5586e 100644 --- a/gcc/doc/sourcebuild.texi +++ b/gcc/doc/sourcebuild.texi @@ -1976,6 +1976,9 @@ at plain @option{-O2}. @item tls Target supports thread-local storage. +@item tls_link +Target supports linking TLS executables. + @item tls_native Target supports native (rather than emulated) thread-local storage. diff --git a/gcc/final.cc b/gcc/final.cc index 12c6eb0..a4dbab7 100644 --- a/gcc/final.cc +++ b/gcc/final.cc @@ -2072,7 +2072,7 @@ output_alternate_entry_point (FILE *file, rtx_insn *insn) /* Given a CALL_INSN, find and return the nested CALL. */ static rtx -call_from_call_insn (rtx_call_insn *insn) +call_from_call_insn (const rtx_call_insn *insn) { rtx x; gcc_assert (CALL_P (insn)); @@ -2098,6 +2098,15 @@ call_from_call_insn (rtx_call_insn *insn) return x; } +/* Return the CALL in X if there is one. */ + +rtx +get_call_rtx_from (const rtx_insn *insn) +{ + const rtx_call_insn *call_insn = as_a<const rtx_call_insn *> (insn); + return call_from_call_insn (call_insn); +} + /* Print a comment into the asm showing FILENAME, LINENUM, and the corresponding source line, if available. */ diff --git a/gcc/fortran/data.cc b/gcc/fortran/data.cc index 5c83f69..a438c26 100644 --- a/gcc/fortran/data.cc +++ b/gcc/fortran/data.cc @@ -593,7 +593,13 @@ gfc_assign_data_value (gfc_expr *lvalue, gfc_expr *rvalue, mpz_t index, { /* Point the container at the new expression. */ if (last_con == NULL) - symbol->value = expr; + { + symbol->value = expr; + /* For a new initializer use the location from the + constructor as fallback. */ + if (!GFC_LOCUS_IS_SET(expr->where) && con != NULL) + symbol->value->where = con->where; + } else last_con->expr = expr; } diff --git a/gcc/function.h b/gcc/function.h index 2260d67..370629f 100644 --- a/gcc/function.h +++ b/gcc/function.h @@ -333,7 +333,6 @@ struct GTY(()) function { /* Properties used by the pass manager. */ unsigned int curr_properties; - unsigned int last_verified; /* Different from normal TODO_flags which are handled right at the beginning or the end of one pass execution, the pending_TODOs diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc index 0f43761..185f9db 100644 --- a/gcc/gimple-fold.cc +++ b/gcc/gimple-fold.cc @@ -198,10 +198,7 @@ can_refer_decl_in_current_unit_p (tree decl, tree from_decl) tree create_tmp_reg_or_ssa_name (tree type, gimple *stmt) { - if (gimple_in_ssa_p (cfun)) - return make_ssa_name (type, stmt); - else - return create_tmp_reg (type); + return make_ssa_name (type, stmt); } /* CVAL is value taken from DECL_INITIAL of variable. Try to transform it into diff --git a/gcc/gimple-harden-conditionals.cc b/gcc/gimple-harden-conditionals.cc index 3ad3bb9..d4a418d 100644 --- a/gcc/gimple-harden-conditionals.cc +++ b/gcc/gimple-harden-conditionals.cc @@ -61,8 +61,7 @@ const pass_data pass_data_harden_compares = { 0, // properties_destroyed 0, // properties_start TODO_update_ssa - | TODO_cleanup_cfg - | TODO_verify_il, // properties_finish + | TODO_cleanup_cfg, // properties_finish }; class pass_harden_compares : public gimple_opt_pass @@ -96,8 +95,7 @@ const pass_data pass_data_harden_conditional_branches = { 0, // properties_destroyed 0, // properties_start TODO_update_ssa - | TODO_cleanup_cfg - | TODO_verify_il, // properties_finish + | TODO_cleanup_cfg, // properties_finish }; class pass_harden_conditional_branches : public gimple_opt_pass diff --git a/gcc/gimple-harden-control-flow.cc b/gcc/gimple-harden-control-flow.cc index e46acaf..f129ff1 100644 --- a/gcc/gimple-harden-control-flow.cc +++ b/gcc/gimple-harden-control-flow.cc @@ -1549,8 +1549,7 @@ pass_harden_control_flow_redundancy::execute (function *fun) return TODO_update_ssa - | TODO_cleanup_cfg - | TODO_verify_il; + | TODO_cleanup_cfg; } /* Instantiate a hardcfr pass. */ diff --git a/gcc/ipa-strub.cc b/gcc/ipa-strub.cc index 99cc9d9..d7c0a92 100644 --- a/gcc/ipa-strub.cc +++ b/gcc/ipa-strub.cc @@ -1770,8 +1770,7 @@ const pass_data pass_data_ipa_strub = { 0, // properties_start TODO_update_ssa | TODO_cleanup_cfg - | TODO_rebuild_cgraph_edges - | TODO_verify_il, // properties_finish + | TODO_rebuild_cgraph_edges, // properties_finish }; class pass_ipa_strub : public simple_ipa_opt_pass diff --git a/gcc/lra-eliminations.cc b/gcc/lra-eliminations.cc index d84a7d1..bb708b0 100644 --- a/gcc/lra-eliminations.cc +++ b/gcc/lra-eliminations.cc @@ -1185,7 +1185,7 @@ update_reg_eliminate (bitmap insns_with_changed_offsets) setup_can_eliminate (ep, false); continue; } - if (ep->can_eliminate != prev && elimination_map[ep->from] == ep) + if (!ep->can_eliminate && elimination_map[ep->from] == ep) { /* We cannot use this elimination anymore -- find another one. */ diff --git a/gcc/lra-spills.cc b/gcc/lra-spills.cc index fc912c4..4febc69 100644 --- a/gcc/lra-spills.cc +++ b/gcc/lra-spills.cc @@ -556,7 +556,7 @@ spill_pseudos (void) fprintf (lra_dump_file, "Changing spilled pseudos to memory in insn #%u\n", INSN_UID (insn)); - lra_push_insn (insn); + lra_push_insn_and_update_insn_regno_info (insn); if (lra_reg_spill_p || targetm.different_addr_displacement_p ()) lra_set_used_insn_alternative (insn, LRA_UNKNOWN_ALT); } diff --git a/gcc/m2/ChangeLog b/gcc/m2/ChangeLog index 0009211..6b19a4d 100644 --- a/gcc/m2/ChangeLog +++ b/gcc/m2/ChangeLog @@ -1,3 +1,105 @@ +2025-06-01 Gaius Mulley <gaiusmod2@gmail.com> + + PR modula2/120474 + * gm2-libs-log/InOut.mod (LocalWrite): Call FIO.FlushBuffer. + +2025-06-01 Gaius Mulley <gaiusmod2@gmail.com> + + PR modula2/120497 + * gm2-compiler/M2Range.mod (IsAssignmentCompatible): Remove from + import list. + (FoldTypeReturnFunc): Rewrite to skip the Lvalue of a var + variable. + (CodeTypeReturnFunc): Ditto. + (CodeTypeIndrX): Call AssignmentTypeCompatible rather than + IsAssignmentCompatible. + (FoldTypeIndrX): Ditto. + +2025-05-31 Gaius Mulley <gaiusmod2@gmail.com> + + PR modula2/120389 + * gm2-compiler/M2Check.def (AssignmentTypeCompatible): Add new + parameter enableReason. + * gm2-compiler/M2Check.mod (EquivalenceProcedure): New type. + (falseReason2): New procedure function. + (falseReason1): Ditto. + (falseReason0): Ditto. + (checkTypeEquivalence): Rewrite. + (checkUnboundedArray): Ditto. + (checkUnbounded): Ditto. + (checkArrayTypeEquivalence): Ditto. + (checkCharStringTypeEquivalence): Ditto. + (buildError4): Add false reason. + (buildError2): Ditto. + (IsTyped): Use GetDType. + (IsTypeEquivalence): New procedure function. + (checkVarTypeEquivalence): Ditto. + (checkVarEquivalence ): Rewrite. + (checkConstMeta): Ditto. + (checkEnumField): New procedure function. + (checkEnumFieldEquivalence): Ditto. + (checkSubrangeTypeEquivalence): Rewrite. + (checkSystemEquivalence): Ditto. + (checkTypeKindViolation): Ditto. + (doCheckPair): Ditto. + (InitEquivalenceArray): New procedure. + (addEquivalence): Ditto. + (checkProcType): Rewrite. + (deconstruct): Deallocate reason string. + (AssignmentTypeCompatible): Initialize reason and reasonEnable + fields. + (ParameterTypeCompatible): Ditto. + (doExpressionTypeCompatible): Ditto. + * gm2-compiler/M2GenGCC.mod (CodeIndrX) Rewrite. + (CheckBinaryExpressionTypes): Rewrite and simplify now that the + type checker is more robust. + (CheckElementSetTypes): Ditto. + (CodeXIndr): Add new range assignment type check. + * gm2-compiler/M2MetaError.def: Correct comments. + * gm2-compiler/M2Options.def (SetStrictTypeAssignment): New procedure. + (SetStrictTypeReason): Ditto. + * gm2-compiler/M2Options.mod: (SetStrictTypeAssignment): New procedure. + (SetStrictTypeReason): Ditto. + (StrictTypeReason): Initialize. + (StrictTypeAssignment): Ditto. + * gm2-compiler/M2Quads.mod (CheckBreak): Delete. + (BreakQuad): New global variable. + (BreakAtQuad): Delete. + (gdbhook): New procedure. + (BreakWhenQuadCreated): Ditto. + (CheckBreak): Ditto. + (Init): Call BreakWhenQuadCreated and gdbhook. + (doBuildAssignment): Add type assignment range check. + (CheckProcTypeAndProcedure): Only check if the procedure + types differ. + (doIndrX): Add type IndrX range check. + (CheckReturnType): Add range return type check. + * gm2-compiler/M2Range.def (InitTypesIndrXCheck): New procedure + function. + (InitTypesReturnTypeCheck): Ditto. + * gm2-compiler/M2Range.mod (InitTypesIndrXCheck): New procedure + function. + (InitTypesReturnTypeCheck): Ditto. + (HandlerExists): Add new clauses. + (FoldAssignment): Pass extra FALSE parameter to + AssignmentTypeCompatible. + (FoldTypeReturnFunc): New procedure. + (FoldTypeAssign): Ditto. + (FoldTypeIndrX): Ditto. + (CodeTypeAssign): Rewrite. + (CodeTypeIndrX): New procedure. + (CodeTypeReturnFunc): Ditto. + (FoldTypeCheck): Add new case clauses. + (CodeTypeCheck): Ditto. + (FoldRangeCheckLower): Ditto. + (IssueWarning): Ditto. + * gm2-gcc/m2options.h (M2Options_SetStrictTypeAssignment): New + function prototype. + (M2Options_SetStrictTypeReason): Ditto. + * gm2-lang.cc (gm2_langhook_handle_option): New case clause + OPT_fm2_strict_type_reason. + * lang.opt (-fm2-strict-type-reason): New option. + 2025-05-22 Gaius Mulley <gaiusmod2@gmail.com> PR modula2/120389 diff --git a/gcc/m2/gm2-compiler/M2Check.def b/gcc/m2/gm2-compiler/M2Check.def index 0ceb173..9d9f760 100644 --- a/gcc/m2/gm2-compiler/M2Check.def +++ b/gcc/m2/gm2-compiler/M2Check.def @@ -50,7 +50,8 @@ PROCEDURE ParameterTypeCompatible (token: CARDINAL; format: ARRAY OF CHAR; *) PROCEDURE AssignmentTypeCompatible (token: CARDINAL; format: ARRAY OF CHAR; - des, expr: CARDINAL) : BOOLEAN ; + des, expr: CARDINAL; + enableReason: BOOLEAN) : BOOLEAN ; (* diff --git a/gcc/m2/gm2-compiler/M2Check.mod b/gcc/m2/gm2-compiler/M2Check.mod index d86ef8e..614526c 100644 --- a/gcc/m2/gm2-compiler/M2Check.mod +++ b/gcc/m2/gm2-compiler/M2Check.mod @@ -36,26 +36,33 @@ FROM M2System IMPORT IsSystemType, IsGenericSystemType, IsSameSize, IsComplexN ; FROM M2Base IMPORT IsParameterCompatible, IsAssignmentCompatible, IsExpressionCompatible, IsComparisonCompatible, IsBaseType, IsMathType, ZType, CType, RType, IsComplexType, Char ; FROM Indexing IMPORT Index, InitIndex, GetIndice, PutIndice, KillIndex, HighIndice, LowIndice, IncludeIndiceIntoIndex, ForeachIndiceInIndexDo ; FROM M2Error IMPORT Error, InternalError, NewError, ErrorString, ChainError ; -FROM M2MetaError IMPORT MetaErrorStringT2, MetaErrorStringT3, MetaErrorStringT4, MetaString2, MetaString3, MetaString4, MetaError1 ; + +FROM M2MetaError IMPORT MetaErrorStringT0, MetaErrorStringT2, MetaErrorStringT3, + MetaErrorStringT4, + MetaString0, MetaString1, MetaString2, MetaString3, + MetaString4, + MetaError0, MetaError1 ; + FROM StrLib IMPORT StrEqual ; FROM M2Debug IMPORT Assert ; -FROM SymbolTable IMPORT NulSym, IsRecord, IsSet, GetDType, GetSType, IsType, +FROM SymbolTable IMPORT NulSym, IsRecord, IsSet, GetDType, GetType, IsType, SkipType, IsProcedure, NoOfParamAny, IsVarParamAny, GetNth, GetNthParamAny, IsProcType, IsVar, IsEnumeration, IsArray, IsSubrange, GetArraySubscript, IsConst, IsReallyPointer, IsPointer, IsParameter, ModeOfAddr, - GetMode, GetType, IsUnbounded, IsComposite, IsConstructor, + GetMode, IsUnbounded, IsComposite, IsConstructor, IsParameter, IsConstString, IsConstLitInternal, IsConstLit, GetStringLength, GetProcedureProcType, IsHiddenType, - IsHiddenReallyPointer, GetDimension ; + IsHiddenReallyPointer, GetDimension, IsFieldEnumeration ; FROM M2GCCDeclare IMPORT GetTypeMin, GetTypeMax ; FROM M2System IMPORT Address ; FROM M2ALU IMPORT Equ, PushIntegerTree ; +FROM M2Options IMPORT StrictTypeReason ; FROM m2expr IMPORT AreConstantsEqual ; -FROM SymbolConversion IMPORT Mod2Gcc ; -FROM DynamicStrings IMPORT String, InitString, KillString ; +FROM SymbolConversion IMPORT Mod2Gcc, GccKnowsAbout ; +FROM DynamicStrings IMPORT String, InitString, KillString, ConCat, Mark ; FROM M2LexBuf IMPORT GetTokenNo ; FROM Storage IMPORT ALLOCATE ; FROM SYSTEM IMPORT ADR ; @@ -63,7 +70,8 @@ FROM libc IMPORT printf ; CONST - debugging = FALSE ; + debugging = FALSE ; + MaxEquvalence = 20 ; TYPE errorSig = POINTER TO RECORD @@ -83,6 +91,8 @@ TYPE checkType = (parameter, assignment, expression) ; tInfo = POINTER TO RECORD + reasonEnable: BOOLEAN ; + reason, format : String ; kind : checkType ; token, @@ -105,11 +115,14 @@ TYPE status = (true, false, unknown, visited, unused) ; + EquivalenceProcedure = PROCEDURE (status, tInfo, CARDINAL, CARDINAL) : status ; VAR - pairFreeList : pair ; - tinfoFreeList: tInfo ; - errors : Index ; + pairFreeList : pair ; + tinfoFreeList : tInfo ; + errors : Index ; + HighEquivalence: CARDINAL ; + Equivalence : ARRAY [1..MaxEquvalence] OF EquivalenceProcedure ; (* @@ -159,6 +172,53 @@ END dumptInfo ; (* + falseReason2 - return false. It also stores the message as the + reason for the false value. +*) + +PROCEDURE falseReason2 (message: ARRAY OF CHAR; tinfo: tInfo; + left, right: CARDINAL) : status ; +BEGIN + IF tinfo^.reasonEnable AND (tinfo^.reason = NIL) + THEN + tinfo^.reason := MetaString2 (InitString (message), left, right) + END ; + RETURN false +END falseReason2 ; + + +(* + falseReason1 - return false. It also stores the message as the + reason for the false value. +*) + +PROCEDURE falseReason1 (message: ARRAY OF CHAR; tinfo: tInfo; + operand: CARDINAL) : status ; +BEGIN + IF tinfo^.reasonEnable AND (tinfo^.reason = NIL) + THEN + tinfo^.reason := MetaString1 (InitString (message), operand) + END ; + RETURN false +END falseReason1 ; + + +(* + falseReason0 - return false. It also stores the message as the + reason for the false value. +*) + +PROCEDURE falseReason0 (message: ARRAY OF CHAR; tinfo: tInfo) : status ; +BEGIN + IF tinfo^.reasonEnable AND (tinfo^.reason = NIL) + THEN + tinfo^.reason := MetaString0 (InitString (message)) + END ; + RETURN false +END falseReason0 ; + + +(* isKnown - returns BOOLEAN:TRUE if result is status:true or status:false. *) @@ -192,31 +252,29 @@ END isFalse ; checkTypeEquivalence - returns TRUE if left and right can be skipped and found to be equal. *) -PROCEDURE checkTypeEquivalence (result: status; left, right: CARDINAL) : status ; -VAR - leftT, rightT: CARDINAL ; +PROCEDURE checkTypeEquivalence (result: status; + tinfo: tInfo; + left, right: CARDINAL) : status ; BEGIN - (* firstly check to see if we already have resolved this as false. *) - IF isFalse (result) + IF left = right THEN - RETURN result - ELSE - (* check to see if we dont care about left or right. *) - IF (left = NulSym) OR (right = NulSym) + RETURN true + ELSIF IsType (left) AND IsType (right) + THEN + IF IsHiddenType (left) AND IsHiddenType (right) + THEN + RETURN falseReason2 ('opaque types {%1a} {%2a} differ', tinfo, left, right) + ELSIF (IsHiddenType (left) AND (right = Address)) OR + (IsHiddenType (right) AND (left = Address)) THEN RETURN true - ELSE - leftT := SkipType (left) ; - rightT := SkipType (right) ; - IF leftT = rightT - THEN - RETURN true - ELSIF IsType (leftT) AND IsType (rightT) - THEN - (* the fundamental types are definitely different. *) - RETURN false - END END + ELSIF IsTypeEquivalence (left) + THEN + RETURN checkPair (result, tinfo, GetDType (left), right) + ELSIF IsTypeEquivalence (right) + THEN + RETURN checkPair (result, tinfo, left, GetDType (right)) END ; RETURN result END checkTypeEquivalence ; @@ -246,13 +304,15 @@ BEGIN PushIntegerTree (Mod2Gcc (rLow)) ; IF NOT Equ (tinfo^.token) THEN - RETURN false + RETURN falseReason2 ('low values of the subrange types {%1a} {%2a} differ', + tinfo, left, right) END ; PushIntegerTree (Mod2Gcc (lHigh)) ; PushIntegerTree (Mod2Gcc (rHigh)) ; IF NOT Equ (tinfo^.token) THEN - RETURN false + RETURN falseReason2 ('high values of the subrange types {%1a} {%2a} differ', + tinfo, left, right) END END ; RETURN true @@ -266,6 +326,7 @@ END checkSubrange ; *) PROCEDURE checkUnboundedArray (result: status; + tinfo: tInfo; unbounded, array: CARDINAL) : status ; VAR dim : CARDINAL ; @@ -280,13 +341,13 @@ BEGIN Assert (IsUnbounded (unbounded)) ; Assert (IsArray (array)) ; dim := GetDimension (unbounded) ; - ubtype := GetType (unbounded) ; + ubtype := GetDType (unbounded) ; type := array ; REPEAT - type := GetType (type) ; + type := GetDType (type) ; DEC (dim) ; (* Check type equivalences. *) - IF checkTypeEquivalence (result, type, ubtype) = true + IF checkTypeEquivalence (result, tinfo, type, ubtype) = true THEN RETURN true END ; @@ -294,11 +355,13 @@ BEGIN (* If we have run out of dimensions we conclude false. *) IF dim = 0 THEN - RETURN false + RETURN falseReason0 ('unbounded array has less dimensions than the array', + tinfo) END ; UNTIL NOT IsArray (type) END ; - RETURN false + RETURN falseReason0 ('array has less dimensions than the unbounded array', + tinfo) END checkUnboundedArray ; @@ -327,14 +390,18 @@ BEGIN referenced. We use GetDimension for 'bar' which is 2. *) IF GetDimension (formal) # GetDimension (tinfo^.actual) THEN - RETURN false + RETURN falseReason2 ('the formal parameter unbounded array {%1a} has a different number' + + ' of dimensions to the actual parameter unbounded array {%2a}', + tinfo, formal, actual) END ; - IF checkTypeEquivalence (result, GetType (formal), GetType (actual)) = true + IF checkTypeEquivalence (result, tinfo, GetType (formal), GetType (actual)) = true THEN RETURN true END END ; - RETURN false + RETURN falseReason2 ('the formal unbounded array type {%1a}' + + ' and the actual unbounded array type {%2a} differ', + tinfo, formal, actual) END checkUnboundedUnbounded ; @@ -373,10 +440,14 @@ BEGIN END ELSIF IsArray (right) THEN - RETURN checkUnboundedArray (result, unbounded, right) + RETURN checkUnboundedArray (result, tinfo, unbounded, right) ELSIF IsUnbounded (right) THEN RETURN checkUnboundedUnbounded (result, tinfo, unbounded, right) + ELSE + RETURN falseReason2 ('the formal unbounded array type {%1a}' + + ' and the actual unbounded array type {%2a} differ', + tinfo, unbounded, right) END END END ; @@ -400,7 +471,7 @@ BEGIN THEN lSub := GetArraySubscript (left) ; rSub := GetArraySubscript (right) ; - result := checkPair (result, tinfo, GetSType (left), GetSType (right)) ; + result := checkPair (result, tinfo, GetDType (left), GetDType (right)) ; IF (lSub # NulSym) AND (rSub # NulSym) THEN result := checkSubrange (result, tinfo, getSType (lSub), getSType (rSub)) @@ -423,31 +494,58 @@ BEGIN END ELSIF IsArray (left) AND IsConst (right) THEN - result := checkPair (result, tinfo, GetType (left), GetType (right)) + result := checkPair (result, tinfo, GetDType (left), GetDType (right)) ELSIF IsArray (right) AND IsConst (left) THEN - result := checkPair (result, tinfo, GetType (left), GetType (right)) + result := checkPair (result, tinfo, GetDType (left), GetDType (right)) END ; RETURN result END checkArrayTypeEquivalence ; (* - checkGenericTypeEquivalence - check left and right for generic equivalence. + checkCharStringTypeEquivalence - check char and string constants for type equivalence. *) -PROCEDURE checkGenericTypeEquivalence (result: status; left, right: CARDINAL) : status ; +PROCEDURE checkCharStringTypeEquivalence (result: status; tinfo: tInfo; + left, right: CARDINAL) : status ; BEGIN IF isFalse (result) THEN RETURN result - ELSIF left = right + ELSIF left = Char THEN - RETURN true - ELSE - RETURN result - END -END checkGenericTypeEquivalence ; + IF IsConst (right) + THEN + (* We might not know the length of the string yet, in which case we return true. *) + IF IsConstString (right) AND + ((NOT GccKnowsAbout (right)) OR (GetStringLength (tinfo^.token, right) <= 1)) + THEN + RETURN true + ELSE + RETURN falseReason2 ('the string {%2a} does not fit into a {%1a}', + tinfo, left, right) + END + ELSIF IsParameter (right) + THEN + right := GetDType (right) ; + IF (right = Char) OR (IsUnbounded (right) AND (SkipType (GetDType (right)) = Char)) + THEN + RETURN true + END + ELSIF IsArray (right) + THEN + IF Char = SkipType (GetDType (right)) + THEN + RETURN true + END + END + ELSIF right = Char + THEN + RETURN checkCharStringTypeEquivalence (result, tinfo, right, left) + END ; + RETURN result +END checkCharStringTypeEquivalence ; (* @@ -491,7 +589,7 @@ BEGIN THEN IF tinfo^.error = NIL THEN - (* need to create top level error message first. *) + (* We need to create top level error message first. *) tinfo^.error := NewError (tinfo^.token) ; (* The parameters to MetaString4 in buildError4 must match the order of paramters passed to ParameterTypeCompatible. *) @@ -499,9 +597,17 @@ BEGIN tinfo^.procedure, tinfo^.formal, tinfo^.actual, tinfo^.nth) ; + (* Append the overall reason for the failure. *) + IF tinfo^.reason # NIL + THEN + (* The string tinfo^.reason is given to the error handler. *) + s := ConCat (s, Mark (InitString (" because "))) ; + s := ConCat (s, tinfo^.reason) ; + tinfo^.reason := NIL (* Hand over deconstructing to M2MetaError. *) + END ; ErrorString (tinfo^.error, s) END ; - (* and also generate a sub error containing detail. *) + (* And now also generate a sub error containing detail. *) IF (left # tinfo^.left) OR (right # tinfo^.right) THEN MetaError1 ('formal parameter {%1EDad}', right) ; @@ -512,7 +618,7 @@ END buildError4 ; (* - buildError2 - generate a MetaString2 error. This is called by all three kinds of errors. + buildError2 - generate a MetaString2 error. *) PROCEDURE buildError2 (tinfo: tInfo; left, right: CARDINAL) ; @@ -543,6 +649,14 @@ BEGIN left, right) END ; + (* Lastly the overall reason for the failure. *) + IF tinfo^.reason # NIL + THEN + (* The string tinfo^.reason is given to the error handler. *) + s := ConCat (s, Mark (InitString (" because "))) ; + s := ConCat (s, tinfo^.reason) ; + tinfo^.reason := NIL (* Hand over deconstructing to M2MetaError. *) + END ; ErrorString (tinfo^.error, s) END END @@ -559,7 +673,7 @@ BEGIN THEN RETURN true ELSE - (* check whether errors are required. *) + (* Check whether errors are required. *) IF tinfo^.format # NIL THEN CASE tinfo^.kind OF @@ -700,11 +814,21 @@ PROCEDURE IsTyped (sym: CARDINAL) : BOOLEAN ; BEGIN RETURN IsVar (sym) OR IsParameter (sym) OR IsConstructor (sym) OR (IsConst (sym) AND IsConstructor (sym)) OR IsParameter (sym) OR - (IsConst (sym) AND (GetType (sym) # NulSym)) + (IsConst (sym) AND (GetDType (sym) # NulSym)) END IsTyped ; (* + IsTypeEquivalence - returns TRUE if sym is a type equivalence symbol. +*) + +PROCEDURE IsTypeEquivalence (sym: CARDINAL) : BOOLEAN ; +BEGIN + RETURN IsType (sym) AND (GetDType (sym) # NulSym) AND (GetDType (sym) # sym) +END IsTypeEquivalence ; + + +(* isLValue - *) @@ -715,6 +839,38 @@ END isLValue ; (* + checkVarTypeEquivalence - +*) + +PROCEDURE checkVarTypeEquivalence (result: status; tinfo: tInfo; + left, right: CARDINAL) : status ; +BEGIN + IF isFalse (result) + THEN + RETURN result + ELSIF (left = NulSym) OR (right = NulSym) + THEN + RETURN true + ELSE + IF IsVar (left) OR IsVar (right) + THEN + (* Either left or right will change, so we can call doCheckPair. *) + IF IsVar (left) + THEN + left := getType (left) + END ; + IF IsVar (right) + THEN + right := getType (right) + END ; + RETURN doCheckPair (result, tinfo, left, right) + END + END ; + RETURN result +END checkVarTypeEquivalence ; + + +(* checkVarEquivalence - this test must be done early as it checks the symbol mode. An LValue is treated as a pointer during assignment and the LValue is attached to a variable. This function skips the variable @@ -722,40 +878,44 @@ END isLValue ; *) PROCEDURE checkVarEquivalence (result: status; tinfo: tInfo; - left, right: CARDINAL) : status ; + des, expr: CARDINAL) : status ; BEGIN IF isFalse (result) THEN RETURN result - ELSIF IsTyped (left) OR IsTyped (right) + ELSIF IsTyped (des) OR IsTyped (expr) THEN IF tinfo^.kind = assignment THEN + IF GetDType (des) = GetDType (expr) + THEN + RETURN true (* LValues are only relevant during assignment. *) - IF isLValue (left) AND (NOT isLValue (right)) + ELSIF isLValue (des) AND (NOT isLValue (expr)) THEN - IF SkipType (getType (right)) = Address + IF SkipType (getType (expr)) = Address THEN RETURN true - ELSIF IsPointer (SkipType (getType (right))) + ELSIF IsPointer (SkipType (getType (expr))) THEN - right := GetDType (SkipType (getType (right))) + expr := GetDType (SkipType (getType (expr))) ; + RETURN doCheckPair (result, tinfo, getType (des), expr) END - ELSIF isLValue (right) AND (NOT isLValue (left)) + ELSIF isLValue (expr) AND (NOT isLValue (des)) THEN - IF SkipType (getType (left)) = Address + IF SkipType (getType (des)) = Address THEN RETURN true - ELSIF IsPointer (SkipType (getType (left))) + ELSIF IsPointer (SkipType (getType (des))) THEN - left := GetDType (SkipType (getType (left))) + des := GetDType (SkipType (getType (des))) ; + RETURN doCheckPair (result, tinfo, des, getType (expr)) END END END ; - RETURN doCheckPair (result, tinfo, getType (left), getType (right)) - ELSE - RETURN result - END + RETURN doCheckPair (result, tinfo, getType (des), getType (expr)) + END ; + RETURN result END checkVarEquivalence ; @@ -790,10 +950,15 @@ BEGIN IsProcedure (typeRight) OR IsRecord (typeRight) OR IsReallyPointer (typeRight) THEN - RETURN false + RETURN falseReason1 ('constant string is incompatible with {%1ad}', + tinfo, typeRight) ELSIF IsArray (typeRight) THEN - RETURN doCheckPair (result, tinfo, Char, GetType (typeRight)) + RETURN doCheckPair (result, tinfo, Char, GetDType (typeRight)) + ELSIF NOT GccKnowsAbout (left) + THEN + (* We do not know the length of this string, so assume true. *) + RETURN true ELSIF GetStringLength (tinfo^.token, left) = 1 THEN RETURN doCheckPair (result, tinfo, Char, typeRight) @@ -805,7 +970,9 @@ BEGIN typeLeft := GetDType (left) ; IF IsZRCType (typeLeft) AND IsUnbounded (typeRight) THEN - RETURN false + RETURN falseReason2 ('the constant {%1a} is incompatible' + + ' with an unbounded array of {%2a}', + tinfo, typeLeft, typeRight) ELSE RETURN doCheckPair (result, tinfo, typeLeft, typeRight) END @@ -815,6 +982,58 @@ END checkConstMeta ; (* + checkEnumField - +*) + +PROCEDURE checkEnumField (result: status; tinfo: tInfo; + left, right: CARDINAL) : status ; +VAR + typeRight: CARDINAL ; +BEGIN + Assert (IsFieldEnumeration (left)) ; + IF isFalse (result) + THEN + RETURN result + ELSIF IsTyped (right) + THEN + typeRight := GetDType (right) ; + IF typeRight = NulSym + THEN + RETURN result + ELSE + RETURN doCheckPair (result, tinfo, GetDType (left), typeRight) + END + END ; + RETURN result +END checkEnumField ; + + +(* + checkEnumFieldEquivalence - +*) + +PROCEDURE checkEnumFieldEquivalence (result: status; tinfo: tInfo; + left, right: CARDINAL) : status ; +BEGIN + IF isFalse (result) + THEN + RETURN result + ELSIF (left = NulSym) OR (right = NulSym) + THEN + (* No option but to return true. *) + RETURN true + ELSIF IsFieldEnumeration (left) + THEN + RETURN checkEnumField (result, tinfo, left, right) + ELSIF IsFieldEnumeration (right) + THEN + RETURN checkEnumField (result, tinfo, right, left) + END ; + RETURN result +END checkEnumFieldEquivalence ; + + +(* checkConstEquivalence - this check can be done first as it checks symbols which may have no type. Ie constant strings. These constants will likely have their type set during quadruple folding. @@ -861,14 +1080,9 @@ BEGIN IF IsSubrange (right) THEN RETURN doCheckPair (result, tinfo, left, GetDType (right)) - END ; - IF left = right - THEN - RETURN true - ELSE - RETURN result END - END + END ; + RETURN result END checkSubrangeTypeEquivalence ; @@ -892,7 +1106,7 @@ PROCEDURE isZRC (zrc, sym: CARDINAL) : BOOLEAN ; BEGIN IF IsConst (sym) THEN - sym := SkipType (GetType (sym)) + sym := SkipType (GetDType (sym)) END ; IF (zrc = CType) AND (IsComplexN (sym) OR IsComplexType (sym)) THEN @@ -911,11 +1125,11 @@ PROCEDURE isSameSizeConst (a, b: CARDINAL) : BOOLEAN ; BEGIN IF IsConst (a) THEN - a := SkipType (GetType (a)) ; + a := SkipType (GetDType (a)) ; RETURN isZRC (a, b) OR (a = b) OR ((a # NulSym) AND isSameSize (a, b)) ELSIF IsConst (b) THEN - b := SkipType (GetType (b)) ; + b := SkipType (GetDType (b)) ; RETURN isZRC (b, a) OR (a = b) OR ((b # NulSym) AND isSameSize (a, b)) END ; RETURN FALSE @@ -936,13 +1150,15 @@ END isSameSize ; checkSystemEquivalence - check whether left and right are system types and whether they have the same size. *) -PROCEDURE checkSystemEquivalence (result: status; left, right: CARDINAL) : status ; +PROCEDURE checkSystemEquivalence (result: status; tinfo: tInfo <* unused *>; + left, right: CARDINAL) : status ; BEGIN IF isFalse (result) OR (result = visited) THEN RETURN result ELSE IF (IsGenericSystemType (left) OR IsGenericSystemType (right)) AND + GccKnowsAbout (left) AND GccKnowsAbout (right) AND isSameSize (left, right) THEN RETURN true @@ -957,7 +1173,7 @@ END checkSystemEquivalence ; a set, record or array. *) -PROCEDURE checkTypeKindViolation (result: status; +PROCEDURE checkTypeKindViolation (result: status; tinfo: tInfo; left, right: CARDINAL) : status ; BEGIN IF isFalse (result) OR (result = visited) @@ -969,7 +1185,8 @@ BEGIN (IsRecord (left) OR IsRecord (right)) OR (IsArray (left) OR IsArray (right)) THEN - RETURN false + RETURN falseReason2 ('a {%1ad} is incompatible with a {%2ad}', + tinfo, left, right) END END ; RETURN result @@ -977,7 +1194,7 @@ END checkTypeKindViolation ; (* - doCheckPair - invoke a series of ordered type checks checking compatibility + doCheckPair - invoke a series of type checks checking compatibility between left and right modula2 symbols. Pre-condition: left and right are modula-2 symbols. tinfo is configured. @@ -989,50 +1206,28 @@ END checkTypeKindViolation ; PROCEDURE doCheckPair (result: status; tinfo: tInfo; left, right: CARDINAL) : status ; +VAR + i: CARDINAL ; BEGIN - IF isFalse (result) OR (result = visited) + IF (left = NulSym) OR (right = NulSym) + THEN + (* We cannot check NulSym. *) + RETURN true + ELSIF isKnown (result) THEN RETURN return (result, tinfo, left, right) ELSIF left = right THEN RETURN return (true, tinfo, left, right) ELSE - result := checkConstEquivalence (unknown, tinfo, left, right) ; - IF NOT isKnown (result) - THEN - result := checkVarEquivalence (unknown, tinfo, left, right) ; - IF NOT isKnown (result) + i := 1 ; + WHILE i <= HighEquivalence DO + result := Equivalence[i] (result, tinfo, left, right) ; + IF isKnown (result) THEN - result := checkSystemEquivalence (unknown, left, right) ; - IF NOT isKnown (result) - THEN - result := checkSubrangeTypeEquivalence (unknown, tinfo, left, right) ; - IF NOT isKnown (result) - THEN - result := checkBaseTypeEquivalence (unknown, tinfo, left, right) ; - IF NOT isKnown (result) - THEN - result := checkTypeEquivalence (unknown, left, right) ; - IF NOT isKnown (result) - THEN - result := checkArrayTypeEquivalence (result, tinfo, left, right) ; - IF NOT isKnown (result) - THEN - result := checkGenericTypeEquivalence (result, left, right) ; - IF NOT isKnown (result) - THEN - result := checkTypeKindEquivalence (result, tinfo, left, right) ; - IF NOT isKnown (result) - THEN - result := checkTypeKindViolation (result, left, right) - END - END - END - END - END - END - END - END + RETURN return (result, tinfo, left, right) + END ; + INC (i) END END ; RETURN return (result, tinfo, left, right) @@ -1040,6 +1235,45 @@ END doCheckPair ; (* + InitEquivalenceArray - populate the Equivalence array with the + checking procedures. +*) + +PROCEDURE InitEquivalenceArray ; +BEGIN + HighEquivalence := 0 ; + addEquivalence (checkVarEquivalence) ; + addEquivalence (checkVarTypeEquivalence) ; + addEquivalence (checkCharStringTypeEquivalence) ; + addEquivalence (checkConstEquivalence); + addEquivalence (checkEnumFieldEquivalence) ; + addEquivalence (checkSystemEquivalence) ; + addEquivalence (checkSubrangeTypeEquivalence) ; + addEquivalence (checkBaseTypeEquivalence) ; + addEquivalence (checkTypeEquivalence) ; + addEquivalence (checkArrayTypeEquivalence) ; + addEquivalence (checkTypeKindEquivalence) ; + addEquivalence (checkTypeKindViolation) +END InitEquivalenceArray ; + + +(* + addEquivalence - places proc into Equivalence array. +*) + +PROCEDURE addEquivalence (proc: EquivalenceProcedure) ; +BEGIN + INC (HighEquivalence) ; + IF HighEquivalence <= MaxEquvalence + THEN + Equivalence[HighEquivalence] := proc + ELSE + InternalError ('increase MaxEquivalence constant in M2Check.mod') + END +END addEquivalence ; + + +(* checkProcType - *) @@ -1090,6 +1324,12 @@ BEGIN i := 1 ; n := NoOfParamAny (left) ; WHILE i <= n DO + IF isFalse (result) OR (result = visited) + THEN + (* Seen a mismatch therefore return. *) + RETURN return (result, tinfo, left, right) + END ; + result := unknown ; (* Each parameter must match. *) IF IsVarParamAny (left, i) # IsVarParamAny (right, i) THEN IF IsVarParamAny (left, i) @@ -1281,7 +1521,6 @@ BEGIN END checkProcTypeEquivalence ; - (* checkTypeKindEquivalence - *) @@ -1551,7 +1790,7 @@ BEGIN THEN RETURN Address ELSE - RETURN GetSType (sym) + RETURN GetDType (sym) END END getSType ; @@ -1627,11 +1866,19 @@ BEGIN printf ("doCheck (%d, %d)\n", left, right) ; dumptInfo (tinfo) END ; - IF isInternal (left) OR isInternal (right) + IF (left = NulSym) OR (right = NulSym) + THEN + (* Cannot test if a type is NulSym, we assume true. + It maybe that later on a symbols type is set and later + on checking will be called and more accurately resolved. + For example constant strings can be concatenated during + the quadruple folding phase. *) + RETURN TRUE + ELSIF isInternal (left) OR isInternal (right) THEN (* Do not check constants which have been generated internally. - Currently these are generated by the default BY constant value - in a FOR loop. *) + Currently these are generated by the default BY constant + value in a FOR loop. *) RETURN TRUE END ; (* @@ -1650,9 +1897,9 @@ BEGIN result := tinfo^.checkFunc (unknown, tinfo, left, right) ; IF isKnown (result) THEN - (* remove this pair from the unresolved list. *) + (* Remove this pair from the unresolved list. *) exclude (tinfo^.unresolved, left, right) ; - (* add it to the resolved list. *) + (* Add it to the resolved list. *) include (tinfo^.resolved, left, right, result) ; IF result = false THEN @@ -1757,6 +2004,7 @@ END deconstructIndex ; PROCEDURE deconstruct (tinfo: tInfo) ; BEGIN tinfo^.format := KillString (tinfo^.format) ; + tinfo^.reason := KillString (tinfo^.reason) ; tinfo^.visited := deconstructIndex (tinfo^.visited) ; tinfo^.resolved := deconstructIndex (tinfo^.resolved) ; tinfo^.unresolved := deconstructIndex (tinfo^.unresolved) @@ -1803,11 +2051,14 @@ END collapseString ; *) PROCEDURE AssignmentTypeCompatible (token: CARDINAL; format: ARRAY OF CHAR; - des, expr: CARDINAL) : BOOLEAN ; + des, expr: CARDINAL; + enableReason: BOOLEAN) : BOOLEAN ; VAR tinfo: tInfo ; BEGIN tinfo := newtInfo () ; + tinfo^.reason := NIL ; + tinfo^.reasonEnable := enableReason AND StrictTypeReason ; tinfo^.format := collapseString (format) ; tinfo^.token := token ; tinfo^.kind := assignment ; @@ -1852,6 +2103,8 @@ BEGIN tinfo := newtInfo () ; formalT := getSType (formal) ; actualT := getSType (actual) ; + tinfo^.reasonEnable := StrictTypeReason ; + tinfo^.reason := NIL ; tinfo^.format := collapseString (format) ; tinfo^.token := token ; tinfo^.kind := parameter ; @@ -1896,6 +2149,8 @@ VAR tinfo: tInfo ; BEGIN tinfo := newtInfo () ; + tinfo^.reasonEnable := StrictTypeReason ; + tinfo^.reason := NIL ; tinfo^.format := collapseString (format) ; tinfo^.token := token ; tinfo^.kind := expression ; @@ -1960,7 +2215,8 @@ PROCEDURE init ; BEGIN pairFreeList := NIL ; tinfoFreeList := NIL ; - errors := InitIndex (1) + errors := InitIndex (1) ; + InitEquivalenceArray END init ; diff --git a/gcc/m2/gm2-compiler/M2GenGCC.mod b/gcc/m2/gm2-compiler/M2GenGCC.mod index 2dfa566..4a9ced3 100644 --- a/gcc/m2/gm2-compiler/M2GenGCC.mod +++ b/gcc/m2/gm2-compiler/M2GenGCC.mod @@ -681,7 +681,7 @@ BEGIN IfGreOp : CodeIfGre (q) | IfInOp : CodeIfIn (q) | IfNotInOp : CodeIfNotIn (q) | - IndrXOp : CodeIndrX (q, op1, op2, op3) | + IndrXOp : CodeIndrX (q) | XIndrOp : CodeXIndr (q) | CallOp : CodeCall (CurrentQuadToken, op3) | ParamOp : CodeParam (q) | @@ -3004,7 +3004,7 @@ BEGIN despos, op2pos, exprpos) ; Assert (op2pos = UnknownTokenNo) ; IF StrictTypeChecking AND - (NOT AssignmentTypeCompatible (despos, "", des, expr)) + (NOT AssignmentTypeCompatible (despos, "", des, expr, TRUE)) THEN MetaErrorT2 (MakeVirtualTok (becomespos, despos, exprpos), 'assignment check caught mismatch between {%1Ead} and {%2ad}', @@ -3233,7 +3233,7 @@ BEGIN IF SkipType(GetTypeMode(op1))#SkipType(GetTypeMode(op3)) THEN DescribeTypeError (tokenno, op1, op3) ; - (* Assigning an errant op3 might ICE, therefore it is safer to return op1. *) + (* Assigning an errant op3 might ICE, therefore it is safer to return op1. *) RETURN( Mod2Gcc (op1) ) END END ; @@ -3550,7 +3550,7 @@ BEGIN location := TokenToLocation (virtpos) ; IF StrictTypeChecking AND - (NOT AssignmentTypeCompatible (virtpos, "", des, expr)) + (NOT AssignmentTypeCompatible (virtpos, "", des, expr, TRUE)) THEN ErrorMessageDecl (virtpos, 'assignment check caught mismatch between {%1Ead} and {%2ad}', @@ -3918,8 +3918,6 @@ END NoWalkProcedure ; PROCEDURE CheckBinaryExpressionTypes (quad: CARDINAL; p: WalkAction) : BOOLEAN ; VAR - lefttype, - righttype, des, left, right: CARDINAL ; typeChecking, constExpr, @@ -3937,10 +3935,8 @@ BEGIN IF typeChecking AND (op # LogicalRotateOp) AND (op # LogicalShiftOp) THEN subexprpos := MakeVirtualTok (operatorpos, leftpos, rightpos) ; - lefttype := GetType (left) ; - righttype := GetType (right) ; IF StrictTypeChecking AND - (NOT ExpressionTypeCompatible (subexprpos, "", lefttype, righttype, + (NOT ExpressionTypeCompatible (subexprpos, "", left, right, StrictTypeChecking, FALSE)) THEN MetaErrorT2 (subexprpos, @@ -3950,19 +3946,6 @@ BEGIN SubQuad (quad) ; p (des) ; RETURN FALSE - END ; - (* --fixme-- the ExpressionTypeCompatible above should be enough - and the code below can be removed once ExpressionTypeCompatible - is bug free. *) - IF NOT IsExpressionCompatible (lefttype, righttype) - THEN - ErrorMessageDecl (subexprpos, - 'expression mismatch between {%1Etad} and {%2tad}', - left, right, TRUE) ; - NoChange := FALSE ; - SubQuad (quad) ; - p (des) ; - RETURN FALSE END END ; RETURN TRUE @@ -3978,7 +3961,6 @@ END CheckBinaryExpressionTypes ; PROCEDURE CheckElementSetTypes (quad: CARDINAL) : BOOLEAN ; VAR - lefttype, righttype, ignore, left, right: CARDINAL ; constExpr, @@ -3995,13 +3977,9 @@ BEGIN overflowChecking, constExpr, leftpos, rightpos, ignorepos) ; subexprpos := MakeVirtualTok (operatorpos, leftpos, rightpos) ; - lefttype := GetType (left) ; righttype := GetType (right) ; - (* --fixme-- the ExpressionTypeCompatible below does not always catch - type errors, it needs to be fixed and then some of the subsequent tests - can be removed (and/or this procedure function rewritten). *) IF StrictTypeChecking AND - (NOT ExpressionTypeCompatible (subexprpos, "", lefttype, righttype, + (NOT ExpressionTypeCompatible (subexprpos, "", left, right, StrictTypeChecking, TRUE)) THEN MetaErrorT2 (subexprpos, @@ -4020,17 +3998,6 @@ BEGIN SubQuad (quad) ; RETURN FALSE END ; - righttype := GetType (SkipType (righttype)) ; - (* Now fall though and compare the set element left against the type of set righttype. *) - IF NOT IsExpressionCompatible (lefttype, righttype) - THEN - ErrorMessageDecl (subexprpos, - 'the types used in expression {%1Etad} {%kIN} {%2tad} are incompatible', - left, right, TRUE) ; - NoChange := FALSE ; - SubQuad (quad) ; - RETURN FALSE - END ; RETURN TRUE END CheckElementSetTypes ; @@ -8174,25 +8141,52 @@ END CodeIfNotIn ; (op2 is the type of the data being indirectly copied) *) -PROCEDURE CodeIndrX (quad: CARDINAL; op1, op2, op3: CARDINAL) ; +PROCEDURE CodeIndrX (quad: CARDINAL) ; VAR - location: location_t ; + constExpr, + overflowChecking: BOOLEAN ; + op : QuadOperator ; + tokenno, + left, + type, + right, + leftpos, + rightpos, + typepos, + indrxpos : CARDINAL ; + length, + newstr : tree ; + location : location_t ; BEGIN - location := TokenToLocation (CurrentQuadToken) ; + GetQuadOtok (quad, indrxpos, op, left, type, right, + overflowChecking, constExpr, + leftpos, typepos, rightpos) ; + tokenno := MakeVirtualTok (indrxpos, leftpos, rightpos) ; + location := TokenToLocation (tokenno) ; (* Follow the Quadruple rules: *) - DeclareConstant (CurrentQuadToken, op3) ; (* checks to see whether it is a constant and declares it *) - DeclareConstructor (CurrentQuadToken, quad, op3) ; - IF IsConstString (op3) + DeclareConstant (rightpos, right) ; (* Checks to see whether it is a constant + and if necessary declare it. *) + DeclareConstructor (rightpos, quad, right) ; + IF IsConstString (right) THEN InternalError ('not expecting to index through a constant string') + ELSIF StrictTypeChecking AND + (NOT AssignmentTypeCompatible (indrxpos, "", left, GetType (right), TRUE)) + THEN + MetaErrorT2 (tokenno, + 'assignment check caught mismatch between {%1Ead} and {%2ad}', + left, right) ; + SubQuad (quad) ELSE + (* Mem[op1] := Mem[Mem[op3]] *) - BuildAssignmentStatement (location, Mod2Gcc (op1), BuildIndirect (location, Mod2Gcc (op3), Mod2Gcc (op2))) + BuildAssignmentStatement (location, Mod2Gcc (left), + BuildIndirect (location, Mod2Gcc (right), Mod2Gcc (type))) END END CodeIndrX ; @@ -8230,7 +8224,7 @@ BEGIN DeclareConstant (rightpos, right) ; DeclareConstructor (rightpos, quad, right) ; IF StrictTypeChecking AND - (NOT AssignmentTypeCompatible (xindrpos, "", GetType (left), right)) + (NOT AssignmentTypeCompatible (xindrpos, "", GetType (left), right, TRUE)) THEN MetaErrorT2 (tokenno, 'assignment check caught mismatch between {%1Ead} and {%2ad}', diff --git a/gcc/m2/gm2-compiler/M2MetaError.def b/gcc/m2/gm2-compiler/M2MetaError.def index cfe9195..3dfe9fa 100644 --- a/gcc/m2/gm2-compiler/M2MetaError.def +++ b/gcc/m2/gm2-compiler/M2MetaError.def @@ -93,9 +93,9 @@ FROM NameKey IMPORT Name ; %} } the error messages may also embed optional strings such as: - {%1a:this string is emitted if the symbol name is non null} - {!%1a:this string is emitted if the symbol name is null} - {!%1a:{%1d}} + {%1a:this string is emitted if the symbol name is null} + {!%1a:this string is emitted if the symbol name is non null} + {%1a:{%1d}} if the symbol name does not exist then print a description of the symbol. {%1atd} was incompatible with the return type of the procedure diff --git a/gcc/m2/gm2-compiler/M2Options.def b/gcc/m2/gm2-compiler/M2Options.def index 2b78add..4cb7f8f 100644 --- a/gcc/m2/gm2-compiler/M2Options.def +++ b/gcc/m2/gm2-compiler/M2Options.def @@ -87,6 +87,8 @@ VAR LineDirectives, (* Should compiler understand preprocessor *) (* # linenumber "filename" markers? *) StrictTypeChecking, (* -fm2-strict-type experimental checker. *) + StrictTypeAssignment, (* -fm2-strict-assignment. *) + StrictTypeReason, (* -fm2-strict-reason. *) CPreProcessor, (* Must we run the cpp on the source? *) Xcode, (* Should errors follow Xcode format? *) ExtendedOpaque, (* Do we allow non pointer opaque types? *) @@ -756,6 +758,20 @@ PROCEDURE SetStrictTypeChecking (value: BOOLEAN) ; (* + SetStrictTypeAssignment - assigns the StrictTypeAssignment flag to value. +*) + +PROCEDURE SetStrictTypeAssignment (value: BOOLEAN) ; + + +(* + SetStrictTypeReason - assigns the StrictTypeReason flag to value. +*) + +PROCEDURE SetStrictTypeReason (value: BOOLEAN) ; + + +(* setdefextension - set the source file definition module extension to arg. This should include the . and by default it is set to .def. *) diff --git a/gcc/m2/gm2-compiler/M2Options.mod b/gcc/m2/gm2-compiler/M2Options.mod index 39f0b2a..542b87b 100644 --- a/gcc/m2/gm2-compiler/M2Options.mod +++ b/gcc/m2/gm2-compiler/M2Options.mod @@ -657,6 +657,26 @@ END SetStrictTypeChecking ; (* + SetStrictTypeAssignment - assigns the StrictTypeAssignment flag to value. +*) + +PROCEDURE SetStrictTypeAssignment (value: BOOLEAN) ; +BEGIN + StrictTypeAssignment := value +END SetStrictTypeAssignment ; + + +(* + SetStrictTypeReason - assigns the StrictTypeReason flag to value. +*) + +PROCEDURE SetStrictTypeReason (value: BOOLEAN) ; +BEGIN + StrictTypeReason := value +END SetStrictTypeReason ; + + +(* SetVerboseUnbounded - sets the VerboseUnbounded flag to, value. *) @@ -2111,6 +2131,8 @@ BEGIN UnusedVariableChecking := FALSE ; UnusedParameterChecking := FALSE ; StrictTypeChecking := TRUE ; + StrictTypeAssignment := TRUE ; + StrictTypeReason := TRUE ; AutoInit := FALSE ; SaveTemps := FALSE ; ScaffoldDynamic := TRUE ; diff --git a/gcc/m2/gm2-compiler/M2Quads.mod b/gcc/m2/gm2-compiler/M2Quads.mod index 4022657..3c29fdd 100644 --- a/gcc/m2/gm2-compiler/M2Quads.mod +++ b/gcc/m2/gm2-compiler/M2Quads.mod @@ -226,6 +226,7 @@ FROM M2Options IMPORT NilChecking, GenerateLineDebug, Exceptions, Profiling, Coding, Optimizing, UninitVariableChecking, + StrictTypeAssignment, ScaffoldDynamic, ScaffoldStatic, cflag, ScaffoldMain, SharedFlag, WholeProgram, GetDumpDir, GetM2DumpFilter, @@ -258,8 +259,10 @@ FROM M2Range IMPORT InitAssignmentRangeCheck, InitRotateCheck, InitShiftCheck, InitTypesAssignmentCheck, + InitTypesIndrXCheck, InitTypesExpressionCheck, InitTypesParameterCheck, + InitTypesReturnTypeCheck, InitForLoopBeginRangeCheck, InitForLoopToRangeCheck, InitForLoopEndRangeCheck, @@ -284,7 +287,6 @@ IMPORT M2Error, FIO, SFIO, DynamicStrings, StdIO ; CONST DebugStackOn = TRUE ; DebugVarients = FALSE ; - BreakAtQuad = 758 ; DebugTokPos = FALSE ; TYPE @@ -397,6 +399,7 @@ VAR (* in order. *) NoOfQuads : CARDINAL ; (* Number of used quadruples. *) Head : CARDINAL ; (* Head of the list of quadruples. *) + BreakQuad : CARDINAL ; (* Stop when BreakQuad is created. *) (* @@ -1487,22 +1490,6 @@ BEGIN END AddQuadInformation ; -PROCEDURE stop ; BEGIN END stop ; - - -(* - CheckBreak - check whether QuadNo = BreakAtQuad and if so call stop. -*) - -PROCEDURE CheckBreak (QuadNo: CARDINAL) ; -BEGIN - IF QuadNo = BreakAtQuad - THEN - stop - END -END CheckBreak ; - - (* PutQuadO - alters a quadruple QuadNo with Op, Oper1, Oper2, Oper3, and sets a boolean to determinine whether overflow should be checked. @@ -3888,6 +3875,10 @@ BEGIN THEN MetaErrorT1 (combinedtok, 'combined {%1Oad}', Des) END ; + IF StrictTypeAssignment + THEN + BuildRange (InitTypesAssignmentCheck (combinedtok, Des, Exp)) + END ; IF (GetSType (Des) # NulSym) AND (NOT IsSet (GetDType (Des))) THEN (* Tell code generator to test runtime values of assignment so ensure we @@ -5628,7 +5619,7 @@ VAR proctok, paramtok : CARDINAL ; n1, n2 : Name ; - ParamCheckId, + ParamCheckId, Dim, Actual, FormalI, @@ -5770,42 +5761,46 @@ VAR CheckedProcedure: CARDINAL ; e : Error ; BEGIN - n := NoOfParamAny (ProcType) ; IF IsVar(call) OR IsTemporary(call) OR IsParameter(call) THEN CheckedProcedure := GetDType(call) ELSE CheckedProcedure := call END ; - IF n # NoOfParamAny (CheckedProcedure) + IF ProcType # CheckedProcedure THEN - e := NewError(GetDeclaredMod(ProcType)) ; - n1 := GetSymName(call) ; - n2 := GetSymName(ProcType) ; - ErrorFormat2(e, 'procedure (%a) is a parameter being passed as variable (%a) but they are declared with different number of parameters', - n1, n2) ; - e := ChainError(GetDeclaredMod(call), e) ; - t := NoOfParamAny (CheckedProcedure) ; - IF n<2 + n := NoOfParamAny (ProcType) ; + (* We need to check the formal parameters between the procedure and proc type. *) + IF n # NoOfParamAny (CheckedProcedure) THEN - ErrorFormat3(e, 'procedure (%a) is being called incorrectly with (%d) parameter, declared with (%d)', - n1, n, t) - ELSE - ErrorFormat3(e, 'procedure (%a) is being called incorrectly with (%d) parameters, declared with (%d)', - n1, n, t) - END - ELSE - i := 1 ; - WHILE i<=n DO - IF IsVarParamAny (ProcType, i) # IsVarParamAny (CheckedProcedure, i) + e := NewError(GetDeclaredMod(ProcType)) ; + n1 := GetSymName(call) ; + n2 := GetSymName(ProcType) ; + ErrorFormat2(e, 'procedure (%a) is a parameter being passed as variable (%a) but they are declared with different number of parameters', + n1, n2) ; + e := ChainError(GetDeclaredMod(call), e) ; + t := NoOfParamAny (CheckedProcedure) ; + IF n<2 THEN - MetaError3 ('parameter {%3n} in {%1dD} causes a mismatch it was declared as a {%2d}', ProcType, GetNth (ProcType, i), i) ; - MetaError3 ('parameter {%3n} in {%1dD} causes a mismatch it was declared as a {%2d}', call, GetNth (call, i), i) - END ; - BuildRange (InitTypesParameterCheck (tokno, CheckedProcedure, i, - GetNthParamAnyClosest (CheckedProcedure, i, GetCurrentModule ()), - GetParam (ProcType, i), ParamCheckId)) ; - INC(i) + ErrorFormat3(e, 'procedure (%a) is being called incorrectly with (%d) parameter, declared with (%d)', + n1, n, t) + ELSE + ErrorFormat3(e, 'procedure (%a) is being called incorrectly with (%d) parameters, declared with (%d)', + n1, n, t) + END + ELSE + i := 1 ; + WHILE i<=n DO + IF IsVarParamAny (ProcType, i) # IsVarParamAny (CheckedProcedure, i) + THEN + MetaError3 ('parameter {%3n} in {%1dD} causes a mismatch it was declared as a {%2d}', ProcType, GetNth (ProcType, i), i) ; + MetaError3 ('parameter {%3n} in {%1dD} causes a mismatch it was declared as a {%2d}', call, GetNth (call, i), i) + END ; + BuildRange (InitTypesParameterCheck (tokno, CheckedProcedure, i, + GetNthParamAnyClosest (CheckedProcedure, i, GetCurrentModule ()), + GetParam (ProcType, i), ParamCheckId)) ; + INC(i) + END END END END CheckProcTypeAndProcedure ; @@ -6272,21 +6267,24 @@ END ExpectVariable ; doIndrX - perform des = *exp with a conversion if necessary. *) -PROCEDURE doIndrX (tok: CARDINAL; - des, exp: CARDINAL) ; +PROCEDURE doIndrX (tok: CARDINAL; des, exp: CARDINAL) ; VAR t: CARDINAL ; BEGIN - IF GetDType(des)=GetDType(exp) + IF GetDType (des) = GetDType (exp) THEN GenQuadOtok (tok, IndrXOp, des, GetSType (des), exp, TRUE, tok, tok, tok) ELSE + IF StrictTypeAssignment + THEN + BuildRange (InitTypesIndrXCheck (tok, des, exp)) + END ; t := MakeTemporary (tok, RightValue) ; PutVar (t, GetSType (exp)) ; GenQuadOtok (tok, IndrXOp, t, GetSType (exp), exp, TRUE, tok, tok, tok) ; - GenQuadOtok (tok, BecomesOp, des, NulSym, doVal (GetSType(des), t), TRUE, + GenQuadOtok (tok, BecomesOp, des, NulSym, doVal (GetSType (des), t), TRUE, tok, UnknownTokenNo, tok) END END doIndrX ; @@ -11295,7 +11293,7 @@ BEGIN n1, n2) ELSE (* this checks the types are compatible, not the data contents. *) - BuildRange (InitTypesAssignmentCheck (tokno, currentProc, actualVal)) + BuildRange (InitTypesReturnTypeCheck (tokno, currentProc, actualVal)) END END CheckReturnType ; @@ -16061,12 +16059,55 @@ END StressStack ; (* + gdbhook - a debugger convenience hook. +*) + +PROCEDURE gdbhook ; +END gdbhook ; + + +(* + BreakWhenQuadCreated - to be called interactively by gdb. +*) + +PROCEDURE BreakWhenQuadCreated (quad: CARDINAL) ; +BEGIN + BreakQuad := quad +END BreakWhenQuadCreated ; + + +(* + CheckBreak - if quad = BreakQuad then call gdbhook. +*) + +PROCEDURE CheckBreak (quad: CARDINAL) ; +BEGIN + IF quad = BreakQuad + THEN + gdbhook + END +END CheckBreak ; + + +(* Init - initialize the M2Quads module, all the stacks, all the lists and the quads list. *) PROCEDURE Init ; BEGIN + BreakWhenQuadCreated (0) ; (* Disable the intereactive quad watch. *) + (* To examine the quad table when a quad is created run cc1gm2 from gdb + and set a break point on gdbhook. + (gdb) break gdbhook + (gdb) run + Now below interactively call BreakWhenQuadCreated with the quad + under investigation. *) + gdbhook ; + (* Now is the time to interactively call gdb, for example: + (gdb) print BreakWhenQuadCreated (1234) + (gdb) cont + and you will arrive at gdbhook when this quad is created. *) LogicalOrTok := MakeKey('_LOR') ; LogicalAndTok := MakeKey('_LAND') ; LogicalXorTok := MakeKey('_LXOR') ; diff --git a/gcc/m2/gm2-compiler/M2Range.def b/gcc/m2/gm2-compiler/M2Range.def index 42aa142..e825d94 100644 --- a/gcc/m2/gm2-compiler/M2Range.def +++ b/gcc/m2/gm2-compiler/M2Range.def @@ -291,6 +291,24 @@ PROCEDURE InitTypesExpressionCheck (tokno: CARDINAL; d, e: CARDINAL; (* + InitTypesIndrXCheck - checks to see that the types of d and e + are assignment compatible. The type checking + will dereference *e during the type check. + d = *e. +*) + +PROCEDURE InitTypesIndrXCheck (tokno: CARDINAL; d, e: CARDINAL) : CARDINAL ; + + +(* + InitTypesReturnTypeCheck - checks to see that the type of val can + be returned from func. +*) + +PROCEDURE InitTypesReturnTypeCheck (tokno: CARDINAL; func, val: CARDINAL) : CARDINAL ; + + +(* InitCaseBounds - creates a case bound range check. *) diff --git a/gcc/m2/gm2-compiler/M2Range.mod b/gcc/m2/gm2-compiler/M2Range.mod index 8e3943a..dcac2ba 100644 --- a/gcc/m2/gm2-compiler/M2Range.mod +++ b/gcc/m2/gm2-compiler/M2Range.mod @@ -58,7 +58,7 @@ FROM M2Debug IMPORT Assert ; FROM Indexing IMPORT Index, InitIndex, InBounds, PutIndice, GetIndice ; FROM Storage IMPORT ALLOCATE ; FROM M2ALU IMPORT PushIntegerTree, PushInt, ConvertToInt, Equ, Gre, Less, GreEqu ; -FROM M2Options IMPORT VariantValueChecking, CaseEnumChecking, GetPIM ; +FROM M2Options IMPORT VariantValueChecking, CaseEnumChecking, GetPIM, StrictTypeAssignment ; FROM M2Error IMPORT Error, InternalError, ErrorFormat0, ErrorFormat1, ErrorFormat2, FlushErrors, GetAnnounceScope ; @@ -91,7 +91,6 @@ FROM M2Check IMPORT ParameterTypeCompatible, ExpressionTypeCompatible, Assignmen FROM M2Base IMPORT Nil, IsRealType, GetBaseTypeMinMax, Cardinal, Integer, ZType, IsComplexType, - IsAssignmentCompatible, IsExpressionCompatible, IsParameterCompatible, ExceptionAssign, @@ -115,7 +114,9 @@ FROM M2CaseList IMPORT CaseBoundsResolved, OverlappingCaseBounds, TYPE TypeOfRange = (assignment, returnassignment, subrangeassignment, inc, dec, incl, excl, shift, rotate, - typeexpr, typeassign, typeparam, paramassign, + typeindrx, typeexpr, typeassign, typeparam, + typereturn, + paramassign, staticarraysubscript, dynamicarraysubscript, forloopbegin, forloopto, forloopend, @@ -289,9 +290,10 @@ BEGIN excl : RETURN( ExceptionExcl ) | shift : RETURN( ExceptionShift ) | rotate : RETURN( ExceptionRotate ) | - typeassign : InternalError ('not expecting this case value') | - typeparam : InternalError ('not expecting this case value') | - typeexpr : InternalError ('not expecting this case value') | + typeassign, + typeparam, + typeexpr, + typeindrx : InternalError ('not expecting this case value') | paramassign : RETURN( ExceptionParameterBounds ) | staticarraysubscript : RETURN( ExceptionStaticArray ) | dynamicarraysubscript: RETURN( ExceptionDynamicArray ) | @@ -822,7 +824,7 @@ END InitRotateCheck ; (* - InitTypesAssignmentCheck - checks to see that the types of, d, and, e, + InitTypesAssignmentCheck - checks to see that the types of d and e are assignment compatible. *) @@ -837,6 +839,38 @@ END InitTypesAssignmentCheck ; (* + InitTypesIndrXCheck - checks to see that the types of d and e + are assignment compatible. The type checking + will dereference *e during the type check. + d = *e. +*) + +PROCEDURE InitTypesIndrXCheck (tokno: CARDINAL; d, e: CARDINAL) : CARDINAL ; +VAR + r: CARDINAL ; +BEGIN + r := InitRange () ; + Assert (PutRangeNoLow (tokno, GetIndice (RangeIndex, r), typeindrx, d, e) # NIL) ; + RETURN r +END InitTypesIndrXCheck ; + + +(* + InitTypesReturnTypeCheck - checks to see that the types of des and func + are assignment compatible. +*) + +PROCEDURE InitTypesReturnTypeCheck (tokno: CARDINAL; func, val: CARDINAL) : CARDINAL ; +VAR + r: CARDINAL ; +BEGIN + r := InitRange () ; + Assert (PutRangeNoLow (tokno, GetIndice (RangeIndex, r), typereturn, func, val) # NIL) ; + RETURN r +END InitTypesReturnTypeCheck ; + + +(* InitTypesParameterCheck - checks to see that the types of, d, and, e, are parameter compatible. *) @@ -1219,9 +1253,11 @@ BEGIN excl : RETURN( ExceptionExcl#NulSym ) | shift : RETURN( ExceptionShift#NulSym ) | rotate : RETURN( ExceptionRotate#NulSym ) | - typeassign : RETURN( FALSE ) | - typeparam : RETURN( FALSE ) | - typeexpr : RETURN( FALSE ) | + typereturn, + typeassign, + typeparam, + typeexpr, + typeindrx : RETURN( FALSE ) | paramassign : RETURN( ExceptionParameterBounds#NulSym ) | staticarraysubscript : RETURN( ExceptionStaticArray#NulSym ) | dynamicarraysubscript: RETURN( ExceptionDynamicArray#NulSym ) | @@ -1246,7 +1282,9 @@ END HandlerExists ; (* - FoldAssignment - + FoldAssignment - attempts to fold the range violation checks. + It does not issue errors on type violations as that + is performed by FoldTypeAssign. *) PROCEDURE FoldAssignment (tokenno: CARDINAL; q: CARDINAL; r: CARDINAL) ; @@ -1259,7 +1297,7 @@ BEGIN TryDeclareConstant (exprtok, expr) ; IF desLowestType # NulSym THEN - IF AssignmentTypeCompatible (tokenno, "", des, expr) + IF AssignmentTypeCompatible (tokenno, "", des, expr, FALSE) THEN IF GccKnowsAbout (expr) AND IsConst (expr) AND GetMinMax (tokenno, desLowestType, min, max) @@ -1275,6 +1313,8 @@ BEGIN END END ELSE + (* We do not issue an error if these types are incompatible here + as this is done by FoldTypeAssign. *) SubQuad (q) END END @@ -1757,21 +1797,94 @@ END FoldRotate ; (* + FoldTypeReturnFunc - checks to see that val can be returned from func. +*) + +PROCEDURE FoldTypeReturnFunc (q: CARDINAL; tokenNo: CARDINAL; func, val: CARDINAL; r: CARDINAL) ; +VAR + valType, + returnType: CARDINAL ; +BEGIN + returnType := GetType (func) ; + IF returnType = NulSym + THEN + IF NOT reportedError (r) + THEN + MetaErrorsT2 (tokenNo, + 'procedure {%1Da} is not a procedure function', + '{%2ad} cannot be returned from {%1Da}', + func, val) ; + SubQuad(q) + END + ELSE + valType := val ; + IF IsVar (val) AND (GetMode (val) = LeftValue) + THEN + valType := GetType (val) + END ; + IF AssignmentTypeCompatible (tokenNo, "", returnType, valType, FALSE) + THEN + SubQuad (q) + ELSE + IF NOT reportedError (r) + THEN + MetaErrorsT2 (tokenNo, + 'the return type {%1Etad} used in procedure {%1Da}', + 'is incompatible with the returned expression {%1ad}}', + func, val) ; + setReported (r) ; + FlushErrors + END + END + END +END FoldTypeReturnFunc ; + + +(* FoldTypeAssign - *) PROCEDURE FoldTypeAssign (q: CARDINAL; tokenNo: CARDINAL; des, expr: CARDINAL; r: CARDINAL) ; +BEGIN + IF NOT reportedError (r) + THEN + IF AssignmentTypeCompatible (tokenNo, + 'assignment designator {%1Ea} {%1ta:of type {%1ta}}' + + ' cannot be assigned with' + + ' {%2ad: a {%2td} {%2ad}}{!%2ad: {%2ad} of type {%2tad}}', + des, expr, TRUE) + THEN + SubQuad (q) + ELSE + setReported (r) ; + FlushErrors + END + END +END FoldTypeAssign ; + + +(* + FoldTypeIndrX - check to see that des = *expr is type compatible. +*) + +PROCEDURE FoldTypeIndrX (q: CARDINAL; tokenNo: CARDINAL; des, expr: CARDINAL; r: CARDINAL) ; VAR + desType, exprType: CARDINAL ; BEGIN - IF IsProcedure(expr) + (* Need to skip over a variable or temporary in des and expr so + long as expr is not a procedure. In the case of des = *expr, + both expr and des will be variables due to the property of + indirection. *) + desType := GetType (des) ; + IF IsProcedure (expr) THEN + (* Must not GetType for a procedure as it gives the return type. *) exprType := expr ELSE - exprType := GetType(expr) + exprType := GetType (expr) END ; - - IF IsAssignmentCompatible (GetType(des), exprType) + IF AssignmentTypeCompatible (tokenNo, "", GetType (des), GetType (expr), FALSE) THEN SubQuad(q) ELSE @@ -1785,14 +1898,16 @@ BEGIN des, expr) ; ELSE MetaErrorT3 (tokenNo, - 'assignment designator {%1Ea} {%1ta:of type {%1ta}} {%1d:is a {%1d}} and expression {%2a} {%3ad:of type {%3ad}} are incompatible', + 'assignment designator {%1Ea} {%1ta:of type {%1ta}}' + + ' {%1d:is a {%1d}} and expression {%2a} {%3ad:of type' + + ' {%3ad}} are incompatible', des, expr, exprType) END ; setReported (r) ; FlushErrors END END -END FoldTypeAssign ; +END FoldTypeIndrX ; (* @@ -1859,35 +1974,90 @@ END FoldTypeExpr ; *) PROCEDURE CodeTypeAssign (tokenNo: CARDINAL; des, expr: CARDINAL; r: CARDINAL) ; +BEGIN + IF NOT AssignmentTypeCompatible (tokenNo, "", des, expr, FALSE) + THEN + IF NOT reportedError (r) + THEN + MetaErrorT2 (tokenNo, + 'assignment designator {%1Ea} {%1ta:of type {%1ta}} {%1d:is a {%1d}} and expression {%2a} {%2tad:of type {%2tad}} are incompatible', + des, expr) + END ; + setReported (r) + END +END CodeTypeAssign ; + + +(* + CodeTypeReturnFunc - +*) + +PROCEDURE CodeTypeReturnFunc (tokenNo: CARDINAL; func, val: CARDINAL; r: CARDINAL) ; VAR - exprType: CARDINAL ; + valType, + returnType: CARDINAL ; BEGIN - IF IsProcedure(expr) + returnType := GetType (func) ; + IF returnType = NulSym THEN - exprType := expr + IF NOT reportedError (r) + THEN + MetaErrorsT2 (tokenNo, + 'procedure {%1Da} is not a procedure function', + '{%2ad} cannot be returned from {%1Da}', + func, val) ; + END ELSE - exprType := GetType(expr) - END ; - IF NOT IsAssignmentCompatible(GetType(des), exprType) + valType := val ; + IF IsVar (val) AND (GetMode (val) = LeftValue) + THEN + valType := GetType (val) + END ; + IF NOT AssignmentTypeCompatible (tokenNo, "", returnType, valType, FALSE) + THEN + IF NOT reportedError (r) + THEN + MetaErrorsT2 (tokenNo, + 'the return type {%1Etad} used in procedure function {%1Da}', + 'is incompatible with the returned expression {%2EUa} {%2tad:of type {%2tad}}', + func, val) + END + END + END +END CodeTypeReturnFunc ; + + +(* + CodeTypeIndrX - checks that des = *expr is type compatible and generates an error if they + are not compatible. It skips over the LValue type so that to allow + the error messages to pick up the source variable name rather than + a temporary name or vague name 'expression'. +*) + +PROCEDURE CodeTypeIndrX (tokenNo: CARDINAL; des, expr: CARDINAL; r: CARDINAL) ; +BEGIN + IF NOT AssignmentTypeCompatible (tokenNo, "", GetType (des), GetType (expr), FALSE) THEN IF NOT reportedError (r) THEN - IF IsProcedure(des) + IF IsProcedure (des) THEN - MetaErrorsT2(tokenNo, - 'the return type {%1Etad} declared in procedure {%1Da}', - 'is incompatible with the returned expression {%2EUa} {%2tad:of type {%2tad}}', - des, expr) ; + MetaErrorsT2 (tokenNo, + 'the return type {%1Etad} declared in procedure {%1Da}', + 'is incompatible with the returned expression {%2EUa} {%2tad:of type {%2tad}}', + des, expr) ; ELSE - MetaErrorT2(tokenNo, - 'assignment designator {%1Ea} {%1ta:of type {%1ta}} {%1d:is a {%1d}} and expression {%2a} {%2tad:of type {%2tad}} are incompatible', - des, expr) + MetaErrorT2 (tokenNo, + 'assignment designator {%1Ea} {%1ta:of type {%1ta}}' + + ' {%1d:is a {%1d}} and expression {%2a}' + + ' {%2tad:of type {%2tad}} are incompatible', + des, expr) END ; setReported (r) END (* FlushErrors *) END -END CodeTypeAssign ; +END CodeTypeIndrX ; (* @@ -1941,9 +2111,11 @@ BEGIN THEN CASE type OF - typeassign: FoldTypeAssign(q, tokenNo, des, expr, r) | - typeparam: FoldTypeParam(q, tokenNo, des, expr, procedure, paramNo, r) | - typeexpr: FoldTypeExpr(q, tokenNo, des, expr, strict, isin, r) + typeassign: FoldTypeAssign (q, tokenNo, des, expr, r) | + typeparam : FoldTypeParam (q, tokenNo, des, expr, procedure, paramNo, r) | + typeexpr : FoldTypeExpr (q, tokenNo, des, expr, strict, isin, r) | + typeindrx : FoldTypeIndrX (q, tokenNo, des, expr, r) | + typereturn: FoldTypeReturnFunc (q, tokenNo, des, expr, r) ELSE InternalError ('not expecting to reach this point') @@ -1974,9 +2146,11 @@ BEGIN THEN CASE type OF - typeassign: CodeTypeAssign(tokenNo, des, expr, r) | - typeparam: CodeTypeParam(tokenNo, des, expr, procedure, paramNo) | - typeexpr: CodeTypeExpr(tokenNo, des, expr, strict, isin, r) + typeassign: CodeTypeAssign (tokenNo, des, expr, r) | + typeparam : CodeTypeParam (tokenNo, des, expr, procedure, paramNo) | + typeexpr : CodeTypeExpr (tokenNo, des, expr, strict, isin, r) | + typeindrx : CodeTypeIndrX (tokenNo, des, expr, r) | + typereturn: CodeTypeReturnFunc (tokenNo, des, expr, r) ELSE InternalError ('not expecting to reach this point') @@ -2005,7 +2179,7 @@ BEGIN success := TRUE ; WITH p^ DO combinedtok := MakeVirtual2Tok (destok, exprtok) ; - IF NOT AssignmentTypeCompatible (combinedtok, "", des, expr) + IF NOT AssignmentTypeCompatible (combinedtok, "", des, expr, TRUE) THEN MetaErrorT2 (combinedtok, 'type incompatibility between {%1Et} and {%2t} detected during the assignment of the designator {%1a} to the first expression {%2a} in the {%kFOR} loop', @@ -2419,9 +2593,11 @@ BEGIN excl : FoldExcl(tokenno, quad, range) | shift : FoldShift(tokenno, quad, range) | rotate : FoldRotate(tokenno, quad, range) | - typeassign : FoldTypeCheck(tokenno, quad, range) | - typeparam : FoldTypeCheck(tokenno, quad, range) | - typeexpr : FoldTypeCheck(tokenno, quad, range) | + typereturn, + typeassign, + typeparam, + typeexpr, + typeindrx : FoldTypeCheck (tokenno, quad, range) | paramassign : FoldParameterAssign(tokenno, quad, range) | staticarraysubscript : FoldStaticArraySubscript(tokenno, quad, range) | dynamicarraysubscript: FoldDynamicArraySubscript(tokenno, quad, range) | @@ -3557,6 +3733,8 @@ BEGIN typeassign : s := NIL | typeparam : s := NIL | typeexpr : s := NIL | + typeindrx : s := InitString ('assignment between designator {%1ad} and {%2ad} is incompatible') | + typereturn : s := InitString ('the value {%2ad} returned from procedure function {%1a} is type incompatible, expecting {%1tad} rather than a {%2tad}') | paramassign : s := InitString('if this call is executed then the actual parameter {%2Wa} will be out of range of the {%3N} formal parameter {%1a}') | staticarraysubscript : s := InitString('if this access to the static array {%1Wa:{%2a:{%1a}[{%2a}]}} is ever made then the index will be out of bounds in the {%3N} array subscript') | dynamicarraysubscript: s := InitString('if this access to the dynamic array {%1Wa:{%2a:{%1a}[{%2a}]}} is ever made then the index will be out of bounds in the {%3N} array subscript') | @@ -3605,9 +3783,11 @@ BEGIN excl : CodeInclExcl (tokenNo, r, function, message) | shift, rotate : CodeShiftRotate (tokenNo, r, function, message) | - typeassign : CodeTypeCheck (tokenNo, r) | - typeparam : CodeTypeCheck (tokenNo, r) | - typeexpr : CodeTypeCheck (tokenNo, r) | + typeassign, + typeparam, + typeexpr, + typeindrx, + typereturn : CodeTypeCheck (tokenNo, r) | staticarraysubscript : CodeStaticArraySubscript (tokenNo, r, function, message) | dynamicarraysubscript: CodeDynamicArraySubscript (tokenNo, r, function, message) | forloopbegin : CodeForLoopBegin (tokenNo, r, function, message) | @@ -3743,6 +3923,8 @@ BEGIN rotate : WriteString('rotate(') ; WriteOperand(des) ; WriteString(', ') ; WriteOperand(expr) | typeexpr : WriteString('expr compatible (') ; WriteOperand(des) ; WriteString(', ') ; WriteOperand(expr) | typeassign : WriteString('assignment compatible (') ; WriteOperand(des) ; WriteString(', ') ; WriteOperand(expr) | + typeindrx : WriteString('indrx compatible (') ; WriteOperand(des) ; WriteString(', ') ; WriteOperand(expr) | + typereturn : WriteString('return compatible (') ; WriteOperand(des) ; WriteString(', ') ; WriteOperand(expr) | typeparam : WriteString('parameter compatible (') ; WriteOperand(des) ; WriteString(', ') ; WriteOperand(expr) | paramassign : WriteString('parameter range (') ; WriteOperand(des) ; WriteString(', ') ; WriteOperand(expr) | staticarraysubscript : WriteString('staticarraysubscript(') ; WriteOperand(des) ; WriteString(', ') ; WriteOperand(expr) | diff --git a/gcc/m2/gm2-gcc/m2options.h b/gcc/m2/gm2-gcc/m2options.h index d60b510..041de26 100644 --- a/gcc/m2/gm2-gcc/m2options.h +++ b/gcc/m2/gm2-gcc/m2options.h @@ -168,6 +168,8 @@ EXTERN char *M2Options_GetM2DumpFilter (void); EXTERN void M2Options_SetM2DebugTraceFilter (bool value, const char *arg); EXTERN bool M2Options_SetM2Dump (bool value, const char *arg); EXTERN bool M2Options_GetDumpGimple (void); +EXTERN void M2Options_SetStrictTypeAssignment (bool value); +EXTERN void M2Options_SetStrictTypeReason (bool value); #undef EXTERN #endif /* m2options_h. */ diff --git a/gcc/m2/gm2-lang.cc b/gcc/m2/gm2-lang.cc index e8820da..31a2e46 100644 --- a/gcc/m2/gm2-lang.cc +++ b/gcc/m2/gm2-lang.cc @@ -525,6 +525,9 @@ gm2_langhook_handle_option ( case OPT_fm2_strict_type: M2Options_SetStrictTypeChecking (value); return 1; + case OPT_fm2_strict_type_reason: + M2Options_SetStrictTypeReason (value); + return 1; case OPT_fm2_debug_trace_: M2Options_SetM2DebugTraceFilter (value, arg); return 1; diff --git a/gcc/m2/gm2-libs-log/InOut.mod b/gcc/m2/gm2-libs-log/InOut.mod index 79c706a..6b03034 100644 --- a/gcc/m2/gm2-libs-log/InOut.mod +++ b/gcc/m2/gm2-libs-log/InOut.mod @@ -257,16 +257,8 @@ END WriteString ; PROCEDURE LocalWrite (ch: CHAR) ; BEGIN FIO.WriteChar(outFile, ch) ; - Done := FIO.IsNoError(outFile) -(* - IF outUsed - THEN - FIO.WriteChar(outFile, ch) ; - Done := FIO.IsNoError(outFile) - ELSE - Done := (write(stdout, ADR(ch), 1) = 1) - END -*) + Done := FIO.IsNoError(outFile) ; + FIO.FlushBuffer (outFile) END LocalWrite ; diff --git a/gcc/m2/lang.opt b/gcc/m2/lang.opt index 1ea55f2..48c2380 100644 --- a/gcc/m2/lang.opt +++ b/gcc/m2/lang.opt @@ -190,6 +190,10 @@ fm2-strict-type Modula-2 experimental flag to turn on the new strict type checker +fm2-strict-type-reason +Modula-2 +provides more detail why the types are incompatible + fm2-whole-program Modula-2 compile all implementation modules and program module at once diff --git a/gcc/passes.cc b/gcc/passes.cc index e86aa1f..6c67ffe 100644 --- a/gcc/passes.cc +++ b/gcc/passes.cc @@ -64,6 +64,9 @@ along with GCC; see the file COPYING3. If not see #include "stringpool.h" #include "attribs.h" +/* Reserved TODOs */ +#define TODO_verify_il (1u << 31) + using namespace gcc; /* This is used for debugging. It allows the current pass to printed @@ -2059,7 +2062,6 @@ execute_function_todo (function *fn, void *data) { bool from_ipa_pass = (cfun == NULL); unsigned int flags = (size_t)data; - flags &= ~fn->last_verified; if (!flags) return; @@ -2127,8 +2129,6 @@ execute_function_todo (function *fn, void *data) gcc_assert (dom_info_state (fn, CDI_POST_DOMINATORS) == pre_verify_pstate); } - fn->last_verified = flags & TODO_verify_all; - pop_cfun (); /* For IPA passes make sure to release dominator info, it can be @@ -2193,14 +2193,6 @@ verify_interpass_invariants (void) gcc_checking_assert (!fold_deferring_overflow_warnings_p ()); } -/* Clear the last verified flag. */ - -static void -clear_last_verified (function *fn, void *data ATTRIBUTE_UNUSED) -{ - fn->last_verified = 0; -} - /* Helper function. Verify that the properties has been turn into the properties expected by the pass. */ @@ -2339,13 +2331,15 @@ execute_one_ipa_transform_pass (struct cgraph_node *node, if (pass->tv_id != TV_NONE) timevar_push (pass->tv_id); + gcc_checking_assert (!(ipa_pass->function_transform_todo_flags_start & TODO_verify_il)); /* Run pre-pass verification. */ execute_todo (ipa_pass->function_transform_todo_flags_start); /* Do it! */ todo_after = ipa_pass->function_transform (node); - /* Run post-pass cleanup and verification. */ + /* Run post-pass cleanup. */ + gcc_checking_assert (!(todo_after & TODO_verify_il)); execute_todo (todo_after); verify_interpass_invariants (); @@ -2649,6 +2643,7 @@ execute_one_pass (opt_pass *pass) /* Run pre-pass verification. */ + gcc_checking_assert (!(pass->todo_flags_start & TODO_verify_il)); execute_todo (pass->todo_flags_start); if (flag_checking) @@ -2697,11 +2692,11 @@ execute_one_pass (opt_pass *pass) return true; } - do_per_function (clear_last_verified, NULL); - do_per_function (update_properties_after_pass, pass); /* Run post-pass cleanup and verification. */ + gcc_checking_assert (!(todo_after & TODO_verify_il)); + gcc_checking_assert (!(pass->todo_flags_finish & TODO_verify_il)); execute_todo (todo_after | pass->todo_flags_finish | TODO_verify_il); if (profile_report) { @@ -960,6 +960,14 @@ is_a_helper <rtx_call_insn *>::test (rtx_insn *insn) template <> template <> inline bool +is_a_helper <const rtx_call_insn *>::test (const rtx_insn *insn) +{ + return CALL_P (insn); +} + +template <> +template <> +inline bool is_a_helper <rtx_jump_table_data *>::test (rtx rt) { return JUMP_TABLE_DATA_P (rt); @@ -3682,7 +3690,6 @@ extern bool nonzero_address_p (const_rtx); extern bool rtx_unstable_p (const_rtx); extern bool rtx_varies_p (const_rtx, bool); extern bool rtx_addr_varies_p (const_rtx, bool); -extern rtx get_call_rtx_from (const rtx_insn *); extern tree get_call_fndecl (const rtx_insn *); extern HOST_WIDE_INT get_integer_term (const_rtx); extern rtx get_related_value (const_rtx); @@ -4572,6 +4579,7 @@ extern void simplify_using_condition (rtx, rtx *, bitmap); extern void compute_alignments (void); extern void update_alignments (vec<rtx> &); extern int asm_str_count (const char *templ); +extern rtx get_call_rtx_from (const rtx_insn *); struct rtl_hooks { diff --git a/gcc/rtlanal.cc b/gcc/rtlanal.cc index 900f53e..239d669 100644 --- a/gcc/rtlanal.cc +++ b/gcc/rtlanal.cc @@ -813,21 +813,6 @@ rtx_addr_varies_p (const_rtx x, bool for_alias) return false; } -/* Return the CALL in X if there is one. */ - -rtx -get_call_rtx_from (const rtx_insn *insn) -{ - rtx x = PATTERN (insn); - if (GET_CODE (x) == PARALLEL) - x = XVECEXP (x, 0, 0); - if (GET_CODE (x) == SET) - x = SET_SRC (x); - if (GET_CODE (x) == CALL && MEM_P (XEXP (x, 0))) - return x; - return NULL_RTX; -} - /* Get the declaration of the function called by INSN. */ tree diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index f0d9128..ff68455 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,106 @@ +2025-06-02 Alexandre Oliva <oliva@adacore.com> + + PR rtl-optimization/120424 + PR middle-end/118939 + * g++.target/arm/pr120424.C: New. + * gnat.dg/controlled9.adb: New. + * gnat.dg/controlled9_pkg.ads: New. + +2025-06-02 Jason Merrill <jason@redhat.com> + + PR c++/107600 + * g++.dg/ext/is_destructible2.C: Add more cases. + +2025-06-02 Dongyan Chen <chendongyan@isrc.iscas.ac.cn> + + * gcc.target/riscv/arch-59.c: New test. + +2025-06-02 Jason Merrill <jason@redhat.com> + + PR c++/120506 + * g++.dg/cpp2a/constinit21.C: New test. + +2025-06-02 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/118903 + * g++.dg/coroutines/pr118903.C: New test. + +2025-06-02 Jason Merrill <jason@redhat.com> + + PR c++/107600 + * g++.dg/ext/is_destructible2.C: New test. + +2025-06-02 Jason Merrill <jason@redhat.com> + + PR c++/107600 + * g++.dg/ext/has_trivial_destructor-3.C: New test. + +2025-06-02 Stafford Horne <shorne@gmail.com> + + * gcc.target/or1k/return-2.c: Fix test. + +2025-06-02 Stafford Horne <shorne@gmail.com> + + * gcc.target/or1k/call-1.c: New test. + * gcc.target/or1k/got-1.c: New test. + +2025-06-02 Christophe Lyon <christophe.lyon@linaro.org> + + * lib/target-supports.exp (check_effective_target_tls_link): New. + * g++.dg/tls/pr102496-1.C: Require tls_link. + * g++.dg/tls/pr77285-1.C: Likewise. + +2025-06-02 Sandra Loosemore <sloosemore@baylibre.com> + + * c-c++-common/gomp/declare-variant-2.c: Update expected output. + * c-c++-common/gomp/metadirective-condition-constexpr.c: New. + * c-c++-common/gomp/metadirective-condition.c: New. + * c-c++-common/gomp/metadirective-error-recovery.c: Update expected + output. + * g++.dg/gomp/metadirective-condition-class.C: New. + * g++.dg/gomp/metadirective-condition-template.C: New. + +2025-06-02 Liao Shihua <shihua@iscas.ac.cn> + + * gcc.target/riscv/rvv/autovec/param-autovec-mode.c: Change + `autovec-mode` to `riscv-autovec-mode` in dg-options. + +2025-06-01 Jerry DeLisle <jvdelisle@gcc.gnu.org> + + PR libfortran/119856 + * gfortran.dg/pr119856.f90: New test. + +2025-06-01 Martin Uecker <uecker@tugraz.at> + + PR c/120380 + * gcc.dg/pr120380.c: New test. + +2025-06-01 Jason Merrill <jason@redhat.com> + + PR c++/120123 + * g++.dg/cpp23/explicit-obj-lambda18.C: Move to... + * g++.dg/cpp2a/concepts-lambda24.C: ...here. + +2025-06-01 Gaius Mulley <gaiusmod2@gmail.com> + + PR modula2/120497 + * gm2/pim/pass/ReturnType.mod: New test. + * gm2/pim/pass/ReturnType2.mod: New test. + +2025-05-31 Richard Biener <rguenther@suse.de> + + PR tree-optimization/120357 + * gcc.dg/vect/vect-early-break_136-pr120357.c: New testcase. + +2025-05-31 Gaius Mulley <gaiusmod2@gmail.com> + + PR modula2/120389 + * gm2/pim/fail/testcharint.mod: New test. + * gm2/pim/fail/testindrx.mod: New test. + * gm2/pim/pass/testxindr.mod: New test. + * gm2/pim/pass/testxindr2.mod: New test. + * gm2/pim/pass/testxindr3.mod: New test. + 2025-05-30 David Malcolm <dmalcolm@redhat.com> PR other/116792 diff --git a/gcc/testsuite/c-c++-common/gomp/declare-variant-2.c b/gcc/testsuite/c-c++-common/gomp/declare-variant-2.c index f8f5143..83e1bb1 100644 --- a/gcc/testsuite/c-c++-common/gomp/declare-variant-2.c +++ b/gcc/testsuite/c-c++-common/gomp/declare-variant-2.c @@ -38,7 +38,7 @@ void f18 (void); void f19 (void); #pragma omp declare variant (f1) match(user={condition()}) /* { dg-error "expected \[^\n\r]*expression before '\\)' token" } */ void f20 (void); -#pragma omp declare variant (f1) match(user={condition(f1)}) /* { dg-error "property must be integer expression" } */ +#pragma omp declare variant (f1) match(user={condition(f1)}) void f21 (void); #pragma omp declare variant (f1) match(user={condition(1, 2, 3)}) /* { dg-error "expected '\\)' before ',' token" } */ void f22 (void); diff --git a/gcc/testsuite/c-c++-common/gomp/metadirective-condition-constexpr.c b/gcc/testsuite/c-c++-common/gomp/metadirective-condition-constexpr.c new file mode 100644 index 0000000..3484478 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/metadirective-condition-constexpr.c @@ -0,0 +1,13 @@ +/* { dg-do compile { target { c || c++11 } } } */ +/* { dg-additional-options "-std=c23" { target c } } */ +/* { dg-additional-options "-fdump-tree-original" } */ + +constexpr int flag = 1; + +void f() { +#pragma omp metadirective when(user={condition(flag)} : nothing) \ + otherwise(error at(execution)) +} + +/* { dg-final { scan-tree-dump-not "__builtin_GOMP_error" "original" } } */ + diff --git a/gcc/testsuite/c-c++-common/gomp/metadirective-condition.c b/gcc/testsuite/c-c++-common/gomp/metadirective-condition.c new file mode 100644 index 0000000..099ad9d --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/metadirective-condition.c @@ -0,0 +1,25 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-fdump-tree-original" } */ + +static int arr[10]; +static int g (int a) { return -a; } + +void f (int *ptr, float x) { + + /* Implicit conversion float -> bool */ + #pragma omp metadirective when(user={condition(x)} : nothing) otherwise(nothing) + + /* Implicit conversion pointer -> bool */ + #pragma omp metadirective when(user={condition(ptr)} : nothing) otherwise(nothing) + + /* Array expression undergoes array->pointer conversion, OK but test is + always optimized away. */ + #pragma omp metadirective when(user={condition(arr)} : nothing) otherwise(nothing) + + /* Function reference has pointer-to-function type, OK but test is + always optimized away. */ + #pragma omp metadirective when(user={condition(g)} : nothing) otherwise(nothing) +} + +/* { dg-final { scan-tree-dump "x != 0.0" "original" } } */ +/* { dg-final { scan-tree-dump "ptr != 0B" "original" } } */ diff --git a/gcc/testsuite/c-c++-common/gomp/metadirective-error-recovery.c b/gcc/testsuite/c-c++-common/gomp/metadirective-error-recovery.c index 3242281..92995a2 100644 --- a/gcc/testsuite/c-c++-common/gomp/metadirective-error-recovery.c +++ b/gcc/testsuite/c-c++-common/gomp/metadirective-error-recovery.c @@ -15,6 +15,11 @@ void f (int aa, int bb) s2.b = bb + 1; /* A struct is not a valid argument for the condition selector. */ - #pragma omp metadirective when(user={condition(s1)} : nothing) otherwise(nothing) /* { dg-error "property must be integer expression" } */ - #pragma omp metadirective when(user={condition(s2)} : nothing) otherwise(nothing) /* { dg-error "property must be integer expression" } */ + #pragma omp metadirective when(user={condition(s1)} : nothing) otherwise(nothing) + /* { dg-error "used struct type value where scalar is required" "" { target c } .-1 } */ + /* { dg-error "could not convert .s1. from .s. to .bool." "" { target c++ } .-2 } */ + #pragma omp metadirective when(user={condition(s2)} : nothing) otherwise(nothing) + /* { dg-error "used struct type value where scalar is required" "" { target c } .-1 } */ + /* { dg-error "could not convert .s2. from .s. to .bool." "" { target c++ } .-2 } */ + } diff --git a/gcc/testsuite/g++.dg/coroutines/pr118903.C b/gcc/testsuite/g++.dg/coroutines/pr118903.C new file mode 100644 index 0000000..a577a9a --- /dev/null +++ b/gcc/testsuite/g++.dg/coroutines/pr118903.C @@ -0,0 +1,40 @@ +// { dg-additional-options "-fsyntax-only" } + +#include <coroutine> + +struct awaitable { + constexpr bool await_ready() { + return true; + } + void await_suspend(std::coroutine_handle<void>) { + + } + constexpr int await_resume() { + return 42; + } +}; + +struct super_simple_coroutine { + struct promise_type { + constexpr auto initial_suspend() { + return std::suspend_never(); + } + constexpr auto final_suspend() const noexcept { + return std::suspend_never(); + } + constexpr void unhandled_exception() { + // do nothing + } + constexpr auto get_return_object() { + return super_simple_coroutine{}; + } + constexpr void return_void() { + } + }; +}; + +auto fib (float f) -> super_simple_coroutine { + // if `co_await` is part of BodyStatement of a function + // it makes it coroutine + constexpr int x = co_await awaitable{}; // { dg-error {'co_await awaitable..' is not a constant expression} } +} diff --git a/gcc/testsuite/g++.dg/cpp23/explicit-obj-lambda18.C b/gcc/testsuite/g++.dg/cpp2a/concepts-lambda24.C index 21bd2e9..28f56ca 100644 --- a/gcc/testsuite/g++.dg/cpp23/explicit-obj-lambda18.C +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-lambda24.C @@ -1,5 +1,5 @@ // PR c++/120123 -// { dg-do compile { target c++23 } } +// { dg-do compile { target c++20 } } struct H { void member(int) {} diff --git a/gcc/testsuite/g++.dg/cpp2a/constinit21.C b/gcc/testsuite/g++.dg/cpp2a/constinit21.C new file mode 100644 index 0000000..18bca90 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/constinit21.C @@ -0,0 +1,28 @@ +// PR c++/120506 +// { dg-do compile { target c++20 } } +// Test that we give more information about why the init is non-constant + +struct A +{ + constexpr A(int c) : counter(c) { } + + int counter; +}; + + +struct B : A +{ + constexpr B(int c) : A(c) { } + + int i; // OOPS, not initialized +}; + +struct C +{ + B sem; + + constexpr C(int c) : sem(c) { } +}; + +constinit C s(0); // { dg-error "incompletely initialized" } +// { dg-prune-output "constant" } diff --git a/gcc/testsuite/g++.dg/ext/has_trivial_destructor-3.C b/gcc/testsuite/g++.dg/ext/has_trivial_destructor-3.C new file mode 100644 index 0000000..a179be5 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/has_trivial_destructor-3.C @@ -0,0 +1,21 @@ +// { dg-do compile { target c++11 } } + +struct X; + +template<class T> +struct default_delete +{ + void operator()(T*) { static_assert(sizeof(T), "type is not incomplete"); } +}; + +template<class T, class D = default_delete<T>> +struct unique_ptr +{ + ~unique_ptr() { del(ptr); } + + T* ptr; + D del; +}; + + +constexpr bool b = __has_trivial_destructor(unique_ptr<X>); diff --git a/gcc/testsuite/g++.dg/ext/is_destructible2.C b/gcc/testsuite/g++.dg/ext/is_destructible2.C new file mode 100644 index 0000000..2edf440 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/is_destructible2.C @@ -0,0 +1,24 @@ +// PR c++/107600 +// { dg-additional-options -Wno-c++17-extensions } +// { dg-do compile { target c++11 } } + +struct A +{ + A& operator= (const A&); + virtual ~A() = 0; +}; + +static_assert( __is_destructible(A) ); +static_assert( __is_assignable(A, A) ); +static_assert( not __is_destructible(int()) ); +static_assert( not __is_nothrow_destructible(int()) ); +static_assert( not __is_trivially_destructible(int()) ); +static_assert( __is_destructible(int&) ); +static_assert( __is_destructible(int&&) ); +static_assert( __is_destructible(int(&)[1]) ); +static_assert( __is_destructible(const int(&)[1]) ); +static_assert( __is_destructible(void(&)()) ); +static_assert( not __is_destructible(int[]) ); +static_assert( not __is_destructible(const int[]) ); +static_assert( not __is_destructible(int[][1]) ); +static_assert( not __is_destructible(const int[][1]) ); diff --git a/gcc/testsuite/g++.dg/gomp/metadirective-condition-class.C b/gcc/testsuite/g++.dg/gomp/metadirective-condition-class.C new file mode 100644 index 0000000..6403611 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/metadirective-condition-class.C @@ -0,0 +1,43 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-fdump-tree-original" } */ + +class c +{ + public: + int x; + c (int xx) { x = xx; } + operator bool() { return x != 0; } +}; + +void f (c &objref) +{ + #pragma omp metadirective when(user={condition(objref)} : nothing) otherwise(nothing) +} + + +template <typename T> class d +{ + public: + T x; + d (T xx) { x = xx; } + operator bool() { return x != 0; } +}; + +template <typename T> +void g (d<T> &objref) +{ + #pragma omp metadirective when(user={condition(objref)} : nothing) otherwise(nothing) +} + +int main (void) +{ + c obj1 (42); + d<int> obj2 (69); + + f (obj1); + g (obj2); +} + +/* { dg-final { scan-tree-dump "c::operator bool \\(\\(struct c .\\) objref\\)" "original" } } */ + +/* { dg-final { scan-tree-dump "d<int>::operator bool \\(\\(struct d .\\) objref\\)" "original" } } */ diff --git a/gcc/testsuite/g++.dg/gomp/metadirective-condition-template.C b/gcc/testsuite/g++.dg/gomp/metadirective-condition-template.C new file mode 100644 index 0000000..30783d9 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/metadirective-condition-template.C @@ -0,0 +1,41 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-fdump-tree-original" } */ + +template<typename T, typename T2> +void f (T x, T2 y) +{ + #pragma omp metadirective when(user={condition(x)}, \ + target_device={device_num(y)} : flush) +} + +class c +{ + public: + int x; + c (int xx) { x = xx; } + operator bool() { return x != 0; } +}; + +template <typename T> class d +{ + public: + T x; + d (T xx) { x = xx; } + operator bool() { return x != 0; } +}; + +int main (void) +{ + c obj1 (42); + d<int> obj2 (69); + + f (42, 0); + f (&obj1, 0); + f (obj1, 0); + f (obj2, 0); +} + +/* { dg-final { scan-tree-dump-times "if \\(x != 0 &&" 1 "original" } } */ +/* { dg-final { scan-tree-dump-times "if \\(x != 0B &&" 1 "original" } } */ +/* { dg-final { scan-tree-dump-times "if \\(<<cleanup_point c::operator bool \\(&x\\)>> &&" 1 "original" } } */ +/* { dg-final { scan-tree-dump-times "if \\(<<cleanup_point d<int>::operator bool \\(&x\\)>> &&" 1 "original" } } */ diff --git a/gcc/testsuite/g++.dg/modules/cpp-1.C b/gcc/testsuite/g++.dg/modules/cpp-1.C index 2ad9637..56ef05fe 100644 --- a/gcc/testsuite/g++.dg/modules/cpp-1.C +++ b/gcc/testsuite/g++.dg/modules/cpp-1.C @@ -1,4 +1,5 @@ // { dg-do preprocess } +// { dg-additional-options -fno-modules } module bob; #if 1 @@ -11,4 +12,4 @@ import gru; EXPORT import mabel; int i; -// { dg-final { scan-file cpp-1.i "cpp-1.C\"\n\n\nmodule bob;\n\nexport import stuart;\n\n\n\nimport gru;\n\n import mabel;\n" } } +// { dg-final { scan-file cpp-1.i "cpp-1.C\"\n\n\n\nmodule bob;\n\nexport import stuart;\n\n\n\nimport gru;\n\n import mabel;\n" } } diff --git a/gcc/testsuite/g++.dg/modules/cpp-3.C b/gcc/testsuite/g++.dg/modules/cpp-3.C index 3aa0c6e..cd776ae 100644 --- a/gcc/testsuite/g++.dg/modules/cpp-3.C +++ b/gcc/testsuite/g++.dg/modules/cpp-3.C @@ -1,4 +1,5 @@ // { dg-do preprocess } +// { dg-additional-options -fno-modules } #define NAME(X) X; diff --git a/gcc/testsuite/g++.dg/modules/cpp-4.C b/gcc/testsuite/g++.dg/modules/cpp-4.C index 6c19431..c423de2 100644 --- a/gcc/testsuite/g++.dg/modules/cpp-4.C +++ b/gcc/testsuite/g++.dg/modules/cpp-4.C @@ -1,3 +1,4 @@ +// { dg-additional-options -fno-modules } // { dg-do preprocess } #if 1 diff --git a/gcc/testsuite/g++.dg/tls/pr102496-1.C b/gcc/testsuite/g++.dg/tls/pr102496-1.C index 8220e1e..e015ae9 100644 --- a/gcc/testsuite/g++.dg/tls/pr102496-1.C +++ b/gcc/testsuite/g++.dg/tls/pr102496-1.C @@ -1,6 +1,6 @@ // PR c++/102496 // { dg-do link { target c++11 } } -// { dg-require-effective-target tls } +// { dg-require-effective-target tls_link } // { dg-add-options tls } // { dg-additional-sources pr102496-2.C } diff --git a/gcc/testsuite/g++.dg/tls/pr77285-1.C b/gcc/testsuite/g++.dg/tls/pr77285-1.C index 7a93414..340c88b 100644 --- a/gcc/testsuite/g++.dg/tls/pr77285-1.C +++ b/gcc/testsuite/g++.dg/tls/pr77285-1.C @@ -1,5 +1,5 @@ // { dg-do link { target c++11 } } -// { dg-require-effective-target tls } +// { dg-require-effective-target tls_link } // { dg-add-options tls } // { dg-additional-sources pr77285-2.C } diff --git a/gcc/testsuite/g++.target/arm/pr120424.C b/gcc/testsuite/g++.target/arm/pr120424.C new file mode 100644 index 0000000..4d0e490 --- /dev/null +++ b/gcc/testsuite/g++.target/arm/pr120424.C @@ -0,0 +1,34 @@ +/* { dg-do compile } */ +/* { dg-options "-march=armv7 -O2 -fstack-clash-protection -fnon-call-exceptions" } */ +/* { dg-final { scan-assembler-not {#-8} } } */ +/* LRA register elimination gets confused when register spilling + causes arm_frame_pointer_required to switch from false to true, and + ends up using a stack slot below sp. */ + +void f() { + int i = 0, j = 0; + asm ("" : : "m" (i), "m" (j)); +} + +void g(void (*fn[])(), int i) +{ + auto fn0 = fn[i+0]; + auto fn1 = fn[i+1]; + auto fn2 = fn[i+2]; + auto fn3 = fn[i+3]; + fn0(); + fn1(); + if (!fn2) + throw i+2; + fn2(); + fn3(); + fn0(); + fn1(); +} + +int +main() +{ + void (*fn[4])() = { f, f, f, f }; + g (fn, 0); +} diff --git a/gcc/testsuite/g++.target/i386/pr103750.C b/gcc/testsuite/g++.target/i386/pr103750.C new file mode 100644 index 0000000..c82c10a --- /dev/null +++ b/gcc/testsuite/g++.target/i386/pr103750.C @@ -0,0 +1,39 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -march=x86-64-v4 -std=c++17" } */ +/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */ +/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.} } } */ + +#include <x86intrin.h> + +/* +**_Z8qustrchrPDsS_Ds: +**... +**.L[0-9]+: +** vpcmpeqw \(%[a-x]+\), %ymm0, %k1 +** vpcmpeqw 32\(%[a-x]+\), %ymm0, %k0 +** kortestw %k0, %k1 +** je .L[0-9]+ +**... +*/ + +const char16_t * +qustrchr(char16_t *n, char16_t *e, char16_t c) noexcept +{ + __m256i mch256 = _mm256_set1_epi16(c); + for ( ; n < e; n += 32) { + __m256i data1 = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(n)); + __m256i data2 = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(n) + 1); + __mmask16 mask1 = _mm256_cmpeq_epu16_mask(data1, mch256); + __mmask16 mask2 = _mm256_cmpeq_epu16_mask(data2, mch256); + if (_kortestz_mask16_u8(mask1, mask2)) + continue; + + unsigned idx = _tzcnt_u32(mask1); + if (mask1 == 0) { + idx = __tzcnt_u16(mask2); + n += 16; + } + return n + idx; + } + return e; +} diff --git a/gcc/testsuite/gcc.dg/Wjump-misses-init-3.c b/gcc/testsuite/gcc.dg/Wjump-misses-init-3.c new file mode 100644 index 0000000..c3110c4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wjump-misses-init-3.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-Wc++-compat" } */ + +void f() +{ + goto skip; /* { dg-warning "jump skips variable initialization" } */ + int i = 1; +skip: ; +} + diff --git a/gcc/testsuite/gcc.dg/gnu23-tag-composite-6.c b/gcc/testsuite/gcc.dg/gnu23-tag-composite-6.c index 2411b04..076c066 100644 --- a/gcc/testsuite/gcc.dg/gnu23-tag-composite-6.c +++ b/gcc/testsuite/gcc.dg/gnu23-tag-composite-6.c @@ -1,11 +1,31 @@ /* { dg-do compile } */ /* { dg-options "-std=gnu23" } */ +#define NEST(...) typeof(({ (__VA_ARGS__){ }; })) + int f() { typedef struct foo bar; - struct foo { typeof(({ (struct foo { bar * x; }){ }; })) * x; } *q; - typeof(q->x) p; - 1 ? p : q; + struct foo { NEST(struct foo { bar *x; }) *x; } *q; + typeof(q->x) p0; + typeof(q->x) p1; + 1 ? p0 : q; + 1 ? p1 : q; + 1 ? p0 : p1; +} + +int g() +{ + typedef struct fo2 bar; + struct fo2 { NEST(struct fo2 { NEST(struct fo2 { bar *x; }) * x; }) *x; } *q; + typeof(q->x) p0; + typeof(q->x->x) p1; + typeof(q->x->x->x) p2; + 1 ? p0 : q; + 1 ? p1 : q; + 1 ? p2 : q; + 1 ? p0 : p1; + 1 ? p2 : p1; + 1 ? p0 : p2; } diff --git a/gcc/testsuite/gcc.dg/pr116892.c b/gcc/testsuite/gcc.dg/pr116892.c new file mode 100644 index 0000000..7eb431b --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr116892.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-g -std=gnu23" } */ + +enum fmt_type; + +void foo(const enum fmt_type a); + +enum [[gnu::packed]] fmt_type { + A +} const a; + diff --git a/gcc/testsuite/gcc.dg/pr120380.c b/gcc/testsuite/gcc.dg/pr120380.c new file mode 100644 index 0000000..10577a1 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr120380.c @@ -0,0 +1,24 @@ +/* PR c/120380 */ +/* { dg-do compile } */ + +struct pair_t { + char c; + int i; +}; +typedef struct foo_ { /* { dg-error "no member" } */ + struct foo_ { /* { dg-error "nested redefinition" } */ + /* { dg-error "no member" "" { target *-*-* } .-1 } */ + struct foo_ { /* { dg-error "nested redefinition" } */ + int value; + } + } /* { dg-error "does not declare anything" } */ + /* { dg-error "no semicolon" "" { target *-*-* } .-1 } */ +} __attribute__((packed)) foo; /* { dg-error "does not declare anything" } */ + /* { dg-error "no semicolon" "" { target *-*-* } .-1 } */ +struct pair_t p = {0, 1}; +foo *addr = (foo *)&p.i; +int main() { + addr->value = 0; /* { dg-error "has no member" } */ + return 0; +} + diff --git a/gcc/testsuite/gcc.dg/tree-ssa/cswtch-6.c b/gcc/testsuite/gcc.dg/tree-ssa/cswtch-6.c new file mode 100644 index 0000000..d765a03 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/cswtch-6.c @@ -0,0 +1,43 @@ +/* PR tree-optimization/120451 */ +/* { dg-do compile { target elf } } */ +/* { dg-options "-O2" } */ + +void foo (int, int); + +__attribute__((noinline, noclone)) void +f1 (int v, int w) +{ + int i, j; + if (w) + { + i = 129; + j = i - 1; + goto lab; + } + switch (v) + { + case 170: + j = 7; + i = 27; + break; + case 171: + i = 8; + j = 122; + break; + case 172: + i = 21; + j = -19; + break; + case 173: + i = 18; + j = 17; + break; + default: + __builtin_abort (); + } + + lab: + foo (i, j); +} + +/* { dg-final { scan-assembler ".rodata.cst16" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/phiprop-2.c b/gcc/testsuite/gcc.dg/tree-ssa/phiprop-2.c new file mode 100644 index 0000000..7181787 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/phiprop-2.c @@ -0,0 +1,28 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-phiopt2 -fdump-tree-phiprop1-details" } */ + +/* PR tree-optimization/116824 */ + +int g(int i, int *tt) +{ + const int t = 10; + const int *a; + { + if (t < i) + { + *tt = 1; + a = &t; + } + else + { + *tt = 1; + a = &i; + } + } + return *a; +} + +/* Check that phiprop1 can do the insert of the loads. */ +/* { dg-final { scan-tree-dump-times "Inserting PHI for result of load" 1 "phiprop1"} } */ +/* Should be able to get MIN_EXPR in phiopt2 after cselim and phiprop. */ +/* { dg-final { scan-tree-dump-times "MIN_EXPR " 1 "phiopt2" } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-early-break_136-pr120357.c b/gcc/testsuite/gcc.dg/vect/vect-early-break_136-pr120357.c new file mode 100644 index 0000000..8a51cfc --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-early-break_136-pr120357.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-add-options vect_early_break } */ +/* { dg-additional-options "-O3" } */ + +char a; +unsigned long long t[2][22]; +int u[22]; +void f(void) +{ + for (int v = 0; v < 22; v++) + for (_Bool w = 0; w < (u[v] < 0) + 1; w = 1) + a *= 0 != t[w][v]; +} diff --git a/gcc/testsuite/gcc.target/or1k/call-1.c b/gcc/testsuite/gcc.target/or1k/call-1.c new file mode 100644 index 0000000..593e402 --- /dev/null +++ b/gcc/testsuite/gcc.target/or1k/call-1.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mcmodel=large" } */ + +/* Generate local and global function calls. */ + +extern int geti (void); + +__attribute__ ((noinline)) int +calc (int a, int b) +{ + return a * b + 255; +} + +int +main (void) +{ + return geti () + calc (3, 4); +} + +/* Ensure the 2 calls use register not immediate jumps. */ +/* { dg-final { scan-assembler-times "l.movhi\\s+" 2 } } */ +/* { dg-final { scan-assembler-times "l.jalr\\s+" 2 } } */ diff --git a/gcc/testsuite/gcc.target/or1k/got-1.c b/gcc/testsuite/gcc.target/or1k/got-1.c new file mode 100644 index 0000000..5357096 --- /dev/null +++ b/gcc/testsuite/gcc.target/or1k/got-1.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fPIC -mcmodel=large" } */ + +/* Generate references to the GOT. */ + +extern int geti (void); +extern int j; + +int +calc (int a) +{ + return a * j + geti (); +} + +/* Ensure the 2 references use gotha relocations and that the function call does + not use an immediate jump instruction. */ +/* { dg-final { scan-assembler-times "gotha" 2 } } */ +/* { dg-final { scan-assembler "l.jalr\\s+" } } */ diff --git a/gcc/testsuite/gcc.target/or1k/return-2.c b/gcc/testsuite/gcc.target/or1k/return-2.c index add3720..c072ae2 100644 --- a/gcc/testsuite/gcc.target/or1k/return-2.c +++ b/gcc/testsuite/gcc.target/or1k/return-2.c @@ -16,4 +16,4 @@ struct a getstruct (long aa) { /* Ensure our return value is returned on stack. */ /* { dg-final { scan-assembler-not "r12," } } */ /* { dg-final { scan-assembler "l.or\\s+r11, r3, r3" } } */ -/* { dg-final { scan-assembler-times "l.sw\\s+\\d+.r11.," 3 } } */ +/* { dg-final { scan-assembler-times "l.sw\\s+\\d+.r3.," 3 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/arch-59.c b/gcc/testsuite/gcc.target/riscv/arch-59.c new file mode 100644 index 0000000..511cf22 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/arch-59.c @@ -0,0 +1,5 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64i_smcntrpmf -mabi=lp64" } */ +int foo() +{ +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv32gcv-nofm.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv32gcv-nofm.c index 0750d8e..4685ed2 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv32gcv-nofm.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv32gcv-nofm.c @@ -3,13 +3,13 @@ #include "vdiv-template.h" -/* { dg-final { scan-assembler-times {\tvdiv\.vv} 5 } } */ -/* { dg-final { scan-assembler-times {\tvdiv\.vx} 3 } } */ +/* { dg-final { scan-assembler-times {\tvdiv\.vv} 8 } } */ +/* { dg-final { scan-assembler-not {\tvdiv\.vx} } } */ /* { dg-final { scan-assembler-times {\tvdivu\.vv} 5 } } */ /* { dg-final { scan-assembler-times {\tvdivu\.vx} 3 } } */ -/* { dg-final { scan-assembler-times {\tvfdiv\.vv} 3 } } */ -/* { dg-final { scan-assembler-times {\tvfdiv\.vf} 3 } } */ +/* { dg-final { scan-assembler-times {\tvfdiv\.vv} 6 } } */ +/* { dg-final { scan-assembler-not {\tvfdiv\.vf} } } */ /* { dg-final { scan-tree-dump-times "\.COND_LEN_DIV" 16 "optimized" } } */ /* { dg-final { scan-tree-dump-times "\.COND_LEN_RDIV" 6 "optimized" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv32gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv32gcv.c index 31b2284..59c48d2 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv32gcv.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv32gcv.c @@ -3,8 +3,8 @@ #include "vdiv-template.h" -/* { dg-final { scan-assembler-times {\tvdiv\.vv} 5 } } */ -/* { dg-final { scan-assembler-times {\tvdiv\.vx} 3 } } */ +/* { dg-final { scan-assembler-times {\tvdiv\.vv} 8 } } */ +/* { dg-final { scan-assembler-not {\tvdiv\.vx} } } */ /* { dg-final { scan-assembler-times {\tvdivu\.vv} 5 } } */ /* { dg-final { scan-assembler-times {\tvdivu\.vx} 3 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv64gcv-nofm.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv64gcv-nofm.c index 6015af9..b574dc4 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv64gcv-nofm.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv64gcv-nofm.c @@ -3,13 +3,13 @@ #include "vdiv-template.h" -/* { dg-final { scan-assembler-times {\tvdiv\.vv} 4 } } */ -/* { dg-final { scan-assembler-times {\tvdiv\.vx} 4 } } */ +/* { dg-final { scan-assembler-times {\tvdiv\.vv} 8 } } */ +/* { dg-final { scan-assembler-not {\tvdiv\.vx} } } */ /* { dg-final { scan-assembler-times {\tvdivu\.vv} 4 } } */ /* { dg-final { scan-assembler-times {\tvdivu\.vx} 4 } } */ -/* { dg-final { scan-assembler-times {\tvfdiv\.vv} 3 } } */ -/* { dg-final { scan-assembler-times {\tvfdiv\.vf} 3 } } */ +/* { dg-final { scan-assembler-times {\tvfdiv\.vv} 6 } } */ +/* { dg-final { scan-assembler-not {\tvfdiv\.vf} } } */ /* { dg-final { scan-tree-dump-times "\.COND_LEN_DIV" 16 "optimized" } } */ /* { dg-final { scan-tree-dump-times "\.COND_LEN_RDIV" 6 "optimized" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv64gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv64gcv.c index ccaa2f8..9b46c6b 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv64gcv.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv64gcv.c @@ -3,8 +3,8 @@ #include "vdiv-template.h" -/* { dg-final { scan-assembler-times {\tvdiv\.vv} 4 } } */ -/* { dg-final { scan-assembler-times {\tvdiv\.vx} 4 } } */ +/* { dg-final { scan-assembler-times {\tvdiv\.vv} 8 } } */ +/* { dg-final { scan-assembler-not {\tvdiv\.vx} } } */ /* { dg-final { scan-assembler-times {\tvdivu\.vv} 4 } } */ /* { dg-final { scan-assembler-times {\tvdivu\.vx} 4 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/param-autovec-mode.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/param-autovec-mode.c index b2ec8f9..1ee7eb3 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/param-autovec-mode.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/param-autovec-mode.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O3 -march=rv64gcv -mabi=lp64d --param=autovec-mode=V4QI -fdump-tree-vect-details" } */ +/* { dg-options "-O3 -march=rv64gcv -mabi=lp64d --param=riscv-autovec-mode=V4QI -fdump-tree-vect-details" } */ /* By default we will use RVVM1SI mode for vectorization because N is not known. Check that we use V4QI and create an epilogue when the autovec-mode diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-1-f16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-1-f16.c new file mode 100644 index 0000000..821e5c5 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-1-f16.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh -mabi=lp64d --param=fpr2vr-cost=0" } */ + +#include "vf_mulop.h" + +DEF_VF_MULOP_CASE_0(_Float16, +, add) +DEF_VF_MULOP_CASE_0(_Float16, -, sub) + +/* { dg-final { scan-assembler-times {vfmadd.vf} 1 } } */ +/* { dg-final { scan-assembler-times {vfmsub.vf} 1 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-1-f32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-1-f32.c new file mode 100644 index 0000000..49b4287 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-1-f32.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv -mabi=lp64d --param=fpr2vr-cost=0" } */ + +#include "vf_mulop.h" + +DEF_VF_MULOP_CASE_0(float, +, add) +DEF_VF_MULOP_CASE_0(float, -, sub) + +/* { dg-final { scan-assembler-times {vfmadd.vf} 1 } } */ +/* { dg-final { scan-assembler-times {vfmsub.vf} 1 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-1-f64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-1-f64.c new file mode 100644 index 0000000..2bb5d89 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-1-f64.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv -mabi=lp64d --param=fpr2vr-cost=0" } */ + +#include "vf_mulop.h" + +DEF_VF_MULOP_CASE_0(double, +, add) +DEF_VF_MULOP_CASE_0(double, -, sub) + +/* { dg-final { scan-assembler-times {vfmadd.vf} 1 } } */ +/* { dg-final { scan-assembler-times {vfmsub.vf} 1 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-2-f16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-2-f16.c new file mode 100644 index 0000000..cbb43ca --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-2-f16.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh -mabi=lp64d --param=fpr2vr-cost=1" } */ + +#include "vf_mulop.h" + +DEF_VF_MULOP_CASE_0(_Float16, +, add) +DEF_VF_MULOP_CASE_0(_Float16, -, sub) + +/* { dg-final { scan-assembler-not {vfmadd.vf} } } */ +/* { dg-final { scan-assembler-not {vfmsub.vf} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-2-f32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-2-f32.c new file mode 100644 index 0000000..66ff9b8 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-2-f32.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv -mabi=lp64d --param=fpr2vr-cost=1" } */ + +#include "vf_mulop.h" + +DEF_VF_MULOP_CASE_0(float, +, add) +DEF_VF_MULOP_CASE_0(float, -, sub) + +/* { dg-final { scan-assembler-not {vfmadd.vf} } } */ +/* { dg-final { scan-assembler-not {vfmsub.vf} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-2-f64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-2-f64.c new file mode 100644 index 0000000..66ff9b8 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-2-f64.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv -mabi=lp64d --param=fpr2vr-cost=1" } */ + +#include "vf_mulop.h" + +DEF_VF_MULOP_CASE_0(float, +, add) +DEF_VF_MULOP_CASE_0(float, -, sub) + +/* { dg-final { scan-assembler-not {vfmadd.vf} } } */ +/* { dg-final { scan-assembler-not {vfmsub.vf} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-3-f16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-3-f16.c new file mode 100644 index 0000000..45980f4 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-3-f16.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh -mabi=lp64d --param=fpr2vr-cost=0" } */ + +#include "vf_mulop.h" + +DEF_VF_MULOP_CASE_1(_Float16, +, add, VF_MULOP_BODY_X16) +DEF_VF_MULOP_CASE_1(_Float16, -, sub, VF_MULOP_BODY_X16) + +/* { dg-final { scan-assembler {vfmadd.vf} } } */ +/* { dg-final { scan-assembler {vfmsub.vf} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-3-f32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-3-f32.c new file mode 100644 index 0000000..c853620 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-3-f32.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv -mabi=lp64d --param=fpr2vr-cost=0" } */ + +#include "vf_mulop.h" + +DEF_VF_MULOP_CASE_1(float, +, add, VF_MULOP_BODY_X16) +DEF_VF_MULOP_CASE_1(float, -, sub, VF_MULOP_BODY_X16) + +/* { dg-final { scan-assembler {vfmadd.vf} } } */ +/* { dg-final { scan-assembler {vfmsub.vf} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-3-f64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-3-f64.c new file mode 100644 index 0000000..d38ae8b --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-3-f64.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv -mabi=lp64d --param=fpr2vr-cost=0" } */ + +#include "vf_mulop.h" + +DEF_VF_MULOP_CASE_1(double, +, add, VF_MULOP_BODY_X16) +DEF_VF_MULOP_CASE_1(double, -, sub, VF_MULOP_BODY_X16) + +/* { dg-final { scan-assembler {vfmadd.vf} } } */ +/* { dg-final { scan-assembler {vfmsub.vf} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-4-f16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-4-f16.c new file mode 100644 index 0000000..f1ca34e --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-4-f16.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh -mabi=lp64d --param=fpr2vr-cost=4" } */ + +#include "vf_mulop.h" + +DEF_VF_MULOP_CASE_1(_Float16, +, add, VF_MULOP_BODY_X16) +DEF_VF_MULOP_CASE_1(_Float16, -, sub, VF_MULOP_BODY_X16) + +/* { dg-final { scan-assembler-not {vfmadd.vf} } } */ +/* { dg-final { scan-assembler-not {vfmsub.vf} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-4-f32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-4-f32.c new file mode 100644 index 0000000..6730d4b --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-4-f32.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv -mabi=lp64d --param=fpr2vr-cost=4" } */ + +#include "vf_mulop.h" + +DEF_VF_MULOP_CASE_1(float, +, add, VF_MULOP_BODY_X16) +DEF_VF_MULOP_CASE_1(float, -, sub, VF_MULOP_BODY_X16) + +/* { dg-final { scan-assembler-not {vfmadd.vf} } } */ +/* { dg-final { scan-assembler-not {vfmsub.vf} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-4-f64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-4-f64.c new file mode 100644 index 0000000..bcb6a6e --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-4-f64.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv -mabi=lp64d --param=fpr2vr-cost=4" } */ + +#include "vf_mulop.h" + +DEF_VF_MULOP_CASE_1(double, +, add, VF_MULOP_BODY_X16) +DEF_VF_MULOP_CASE_1(double, -, sub, VF_MULOP_BODY_X16) + +/* { dg-final { scan-assembler-not {vfmadd.vf} } } */ +/* { dg-final { scan-assembler-not {vfmsub.vf} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_mulop.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_mulop.h new file mode 100644 index 0000000..5253978 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_mulop.h @@ -0,0 +1,61 @@ +#ifndef HAVE_DEFINED_VF_MULOP_H +#define HAVE_DEFINED_VF_MULOP_H + +#include <stdint.h> + +#define DEF_VF_MULOP_CASE_0(T, OP, NAME) \ + void test_vf_mulop_##NAME##_##T##_case_0(T *restrict out, T *restrict in, \ + T x, unsigned n) { \ + for (unsigned i = 0; i < n; i++) \ + out[i] = in[i] OP out[i] * x; \ + } +#define DEF_VF_MULOP_CASE_0_WRAP(T, OP, NAME) DEF_VF_MULOP_CASE_0(T, OP, NAME) +#define RUN_VF_MULOP_CASE_0(T, NAME, out, in, x, n) \ + test_vf_mulop_##NAME##_##T##_case_0(out, in, x, n) +#define RUN_VF_MULOP_CASE_0_WRAP(T, NAME, out, in, x, n) \ + RUN_VF_MULOP_CASE_0(T, NAME, out, in, x, n) + +#define VF_MULOP_BODY(op) \ + out[k + 0] = in[k + 0] op tmp * out[k + 0]; \ + out[k + 1] = in[k + 1] op tmp * out[k + 1]; \ + k += 2; + +#define VF_MULOP_BODY_X4(op) \ + VF_MULOP_BODY(op) \ + VF_MULOP_BODY(op) + +#define VF_MULOP_BODY_X8(op) \ + VF_MULOP_BODY_X4(op) \ + VF_MULOP_BODY_X4(op) + +#define VF_MULOP_BODY_X16(op) \ + VF_MULOP_BODY_X8(op) \ + VF_MULOP_BODY_X8(op) + +#define VF_MULOP_BODY_X32(op) \ + VF_MULOP_BODY_X16(op) \ + VF_MULOP_BODY_X16(op) + +#define VF_MULOP_BODY_X64(op) \ + VF_MULOP_BODY_X32(op) \ + VF_MULOP_BODY_X32(op) + +#define VF_MULOP_BODY_X128(op) \ + VF_MULOP_BODY_X64(op) \ + VF_MULOP_BODY_X64(op) + +#define DEF_VF_MULOP_CASE_1(T, OP, NAME, BODY) \ + void test_vf_mulop_##NAME##_##T##_case_1(T *restrict out, T *restrict in, \ + T x, unsigned n) { \ + unsigned k = 0; \ + T tmp = x + 3; \ + \ + while (k < n) { \ + tmp = tmp * 0x3f; \ + BODY(OP) \ + } \ + } +#define DEF_VF_MULOP_CASE_1_WRAP(T, OP, NAME, BODY) \ + DEF_VF_MULOP_CASE_1(T, OP, NAME, BODY) + +#endif diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_mulop_data.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_mulop_data.h new file mode 100644 index 0000000..c16c1a9 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_mulop_data.h @@ -0,0 +1,413 @@ +#ifndef HAVE_DEFINED_VF_MULOP_DATA_H +#define HAVE_DEFINED_VF_MULOP_DATA_H + +#define N 16 + +#define TEST_MULOP_DATA(T, NAME) test_##T##_##NAME##_data +#define TEST_MULOP_DATA_WRAP(T, NAME) TEST_MULOP_DATA(T, NAME) + + +_Float16 TEST_MULOP_DATA(_Float16, add)[][4][N] = +{ + { + { 0.30f16 }, + { + 1.48f16, 1.48f16, 1.48f16, 1.48f16, + 0.80f16, 0.80f16, 0.80f16, 0.80f16, + 0.62f16, 0.62f16, 0.62f16, 0.62f16, + 1.18f16, 1.18f16, 1.18f16, 1.18f16, + }, + { + 1.25f16, 1.25f16, 1.25f16, 1.25f16, + 1.89f16, 1.89f16, 1.89f16, 1.89f16, + 1.57f16, 1.57f16, 1.57f16, 1.57f16, + 1.21f16, 1.21f16, 1.21f16, 1.21f16, + }, + { + 1.85f16, 1.85f16, 1.85f16, 1.85f16, + 1.37f16, 1.37f16, 1.37f16, 1.37f16, + 1.09f16, 1.09f16, 1.09f16, 1.09f16, + 1.54f16, 1.54f16, 1.54f16, 1.54f16, + } + }, + { + { -0.505f16 }, + { + -2.38f16, -2.38f16, -2.38f16, -2.38f16, + -2.06f16, -2.06f16, -2.06f16, -2.06f16, + -1.69f16, -1.69f16, -1.69f16, -1.69f16, + -1.1f16, -1.1f16, -1.1f16, -1.1f16, + }, + { + -1.77f16, -1.77f16, -1.77f16, -1.77f16, + -1.6f16, -1.6f16, -1.6f16, -1.6f16, + -1.f16, -1.f16, -1.f16, -1.f16, + -1.23f16, -1.23f16, -1.23f16, -1.23f16, + }, + { + -1.49f16, -1.49f16, -1.49f16, -1.49f16, + -1.25f16, -1.25f16, -1.25f16, -1.25f16, + -1.18f16, -1.18f16, -1.18f16, -1.18f16, + -0.479f16, -0.479f16, -0.479f16, -0.479f16, + } + }, + { + { 4.95e-04f16 }, + { + 1.4266e-05f16, 1.4266e-05f16, 1.4266e-05f16, 1.4266e-05f16, + 1.8129e-05f16, 1.8129e-05f16, 1.8129e-05f16, 1.8129e-05f16, + -8.4710e-06f16, -8.4710e-06f16, -8.4710e-06f16, -8.4710e-06f16, + 3.7876e-05f16, 3.7876e-05f16, 3.7876e-05f16, 3.7876e-05f16, + }, + { + 2.2808e-02f16, 2.2808e-02f16, 2.2808e-02f16, 2.2808e-02f16, + 3.9633e-02f16, 3.9633e-02f16, 3.9633e-02f16, 3.9633e-02f16, + 9.9657e-02f16, 9.9657e-02f16, 9.9657e-02f16, 9.9657e-02f16, + 7.7189e-02f16, 7.7189e-02f16, 7.7189e-02f16, 7.7189e-02f16, + }, + { + 2.5547e-05f16, 2.5547e-05f16, 2.5547e-05f16, 2.5547e-05f16, + 3.7732e-05f16, 3.7732e-05f16, 3.7732e-05f16, 3.7732e-05f16, + 4.0820e-05f16, 4.0820e-05f16, 4.0820e-05f16, 4.0820e-05f16, + 7.6054e-05f16, 7.6054e-05f16, 7.6054e-05f16, 7.6054e-05f16, + } + }, +}; + +float TEST_MULOP_DATA(float, add)[][4][N] = +{ + { + { 43.71f }, + { + -410.28f, -410.28f, -410.28f, -410.28f, + -276.91f, -276.91f, -276.91f, -276.91f, + -103.38f, -103.38f, -103.38f, -103.38f, + -378.24f, -378.24f, -378.24f, -378.24f, + }, + { + 9.56f, 9.56f, 9.56f, 9.56f, + 6.39f, 6.39f, 6.39f, 6.39f, + 2.40f, 2.40f, 2.40f, 2.40f, + 8.80f, 8.80f, 8.80f, 8.80f, + }, + { + 7.59f, 7.59f, 7.59f, 7.59f, + 2.40f, 2.40f, 2.40f, 2.40f, + 1.52f, 1.52f, 1.52f, 1.52f, + 6.41f, 6.41f, 6.41f, 6.41f, + } + }, + { + { 2.04f }, + { + -110.22f, -110.22f, -110.22f, -110.22f, + -25.13f, -25.13f, -25.13f, -25.13f, + -108.18f, -108.18f, -108.18f, -108.18f, + -107.14f, -107.14f, -107.14f, -107.14f, + }, + { + 64.82f, 64.82f, 64.82f, 64.82f, + 31.65f, 31.65f, 31.65f, 31.65f, + 87.32f, 87.32f, 87.32f, 87.32f, + 58.70f, 58.70f, 58.70f, 58.70f, + }, + { + 22.01f, 22.01f, 22.01f, 22.01f, + 39.44f, 39.44f, 39.44f, 39.44f, + 69.95f, 69.95f, 69.95f, 69.95f, + 12.61f, 12.61f, 12.61f, 12.61f, + } + }, + { + { 20.35f }, + { + 881.43f, 881.43f, 881.43f, 881.43f, + 3300.17f, 3300.17f, 3300.17f, 3300.17f, + 5217.85f, 5217.85f, 5217.85f, 5217.85f, + 66.57f, 66.57f, 66.57f, 66.57f, + }, + { + 64.82f, 64.82f, 64.82f, 64.82f, + 31.65f, 31.65f, 31.65f, 31.65f, + 87.32f, 87.32f, 87.32f, 87.32f, + 58.70f, 58.70f, 58.70f, 58.70f, + }, + { + 2200.52f, 2200.52f, 2200.52f, 2200.52f, + 3944.25f, 3944.25f, 3944.25f, 3944.25f, + 6994.81f, 6994.81f, 6994.81f, 6994.81f, + 1261.12f, 1261.12f, 1261.12f, 1261.12f, + } + }, +}; + +double TEST_MULOP_DATA(double, add)[][4][N] = +{ + { + { 1.16e+12 }, + { + 1.8757e+45, 1.8757e+45, 1.8757e+45, 1.8757e+45, + 7.5140e+45, 7.5140e+45, 7.5140e+45, 7.5140e+45, + 8.2069e+45, 8.2069e+45, 8.2069e+45, 8.2069e+45, + 4.9456e+45, 4.9456e+45, 4.9456e+45, 4.9456e+45, + }, + { + 9.0242e+32, 9.0242e+32, 9.0242e+32, 9.0242e+32, + 3.6908e+32, 3.6908e+32, 3.6908e+32, 3.6908e+32, + 3.9202e+32, 3.9202e+32, 3.9202e+32, 3.9202e+32, + 5.0276e+32, 5.0276e+32, 5.0276e+32, 5.0276e+32, + }, + { + 2.9201e+45, 2.9201e+45, 2.9201e+45, 2.9201e+45, + 7.9411e+45, 7.9411e+45, 7.9411e+45, 7.9411e+45, + 8.6606e+45, 8.6606e+45, 8.6606e+45, 8.6606e+45, + 5.5275e+45, 5.5275e+45, 5.5275e+45, 5.5275e+45, + } + }, + { + { -7.29e+23 }, + { + -6.4993e+65, -6.4993e+65, -6.4993e+65, -6.4993e+65, + -4.6760e+65, -4.6760e+65, -4.6760e+65, -4.6760e+65, + -8.1564e+65, -8.1564e+65, -8.1564e+65, -8.1564e+65, + -8.2899e+65, -8.2899e+65, -8.2899e+65, -8.2899e+65, + }, + { + -7.7764e+41, -7.7764e+41, -7.7764e+41, -7.7764e+41, + -1.9756e+41, -1.9756e+41, -1.9756e+41, -1.9756e+41, + -4.8980e+41, -4.8980e+41, -4.8980e+41, -4.8980e+41, + -8.1062e+41, -8.1062e+41, -8.1062e+41, -8.1062e+41, + }, + { + -8.2928e+64, -8.2928e+64, -8.2928e+64, -8.2928e+64, + -3.2356e+65, -3.2356e+65, -3.2356e+65, -3.2356e+65, + -4.5850e+65, -4.5850e+65, -4.5850e+65, -4.5850e+65, + -2.3794e+65, -2.3794e+65, -2.3794e+65, -2.3794e+65, + } + }, + { + { 2.02e-03 }, + { + -1.2191e-35, -1.2191e-35, -1.2191e-35, -1.2191e-35, + -1.0471e-36, -1.0471e-36, -1.0471e-36, -1.0471e-36, + -9.7582e-36, -9.7582e-36, -9.7582e-36, -9.7582e-36, + -2.2097e-36, -2.2097e-36, -2.2097e-36, -2.2097e-36, + }, + { + 9.7703e-33, 9.7703e-33, 9.7703e-33, 9.7703e-33, + 4.1632e-33, 4.1632e-33, 4.1632e-33, 4.1632e-33, + 8.1964e-33, 8.1964e-33, 8.1964e-33, 8.1964e-33, + 4.7314e-33, 4.7314e-33, 4.7314e-33, 4.7314e-33, + }, + { + 7.5586e-36, 7.5586e-36, 7.5586e-36, 7.5586e-36, + 7.3684e-36, 7.3684e-36, 7.3684e-36, 7.3684e-36, + 6.8101e-36, 6.8101e-36, 6.8101e-36, 6.8101e-36, + 7.3543e-36, 7.3543e-36, 7.3543e-36, 7.3543e-36, + } + }, +}; + +_Float16 TEST_MULOP_DATA(_Float16, sub)[][4][N] = +{ + { + { 0.676f16 }, + { + 1.39f16, 1.39f16, 1.39f16, 1.39f16, + 1.68f16, 1.68f16, 1.68f16, 1.68f16, + 1.63f16, 1.63f16, 1.63f16, 1.63f16, + 2.12f16, 2.12f16, 2.12f16, 2.12f16, + }, + { + 1.04f16, 1.04f16, 1.04f16, 1.04f16, + 1.64f16, 1.64f16, 1.64f16, 1.64f16, + 1.95f16, 1.95f16, 1.95f16, 1.95f16, + 1.39f16, 1.39f16, 1.39f16, 1.39f16, + }, + { + 0.687f16, 0.687f16, 0.687f16, 0.687f16, + 0.568f16, 0.568f16, 0.568f16, 0.568f16, + 0.315f16, 0.315f16, 0.315f16, 0.315f16, + 1.18f16, 1.18f16, 1.18f16, 1.18f16, + } +}, + { + { -0.324f16 }, + { + -0.679f16, -0.679f16, -0.679f16, -0.679f16, + -0.992f16, -0.992f16, -0.992f16, -0.992f16, + -1.34f16, -1.34f16, -1.34f16, -1.34f16, + -0.297f16, -0.297f16, -0.297f16, -0.297f16, + }, + { + -1.96f16, -1.96f16, -1.96f16, -1.96f16, + -1.36f16, -1.36f16, -1.36f16, -1.36f16, + -1.05f16, -1.05f16, -1.05f16, -1.05f16, + -1.61f16, -1.61f16, -1.61f16, -1.61f16, + }, + { + -1.31f16, -1.31f16, -1.31f16, -1.31f16, + -1.43f16, -1.43f16, -1.43f16, -1.43f16, + -1.68f16, -1.68f16, -1.68f16, -1.68f16, + -0.82f16, -0.82f16, -0.82f16, -0.82f16, + } + }, + { + { 7.08e+01f16 }, + { + 4.49e+03f16, 4.49e+03f16, 4.49e+03f16, 4.49e+03f16, + 7.73e+03f16, 7.73e+03f16, 7.73e+03f16, 7.73e+03f16, + 8.42e+03f16, 8.42e+03f16, 8.42e+03f16, 8.42e+03f16, + 9.12e+03f16, 9.12e+03f16, 9.12e+03f16, 9.12e+03f16, + }, + { + 1.40e+01f16, 1.40e+01f16, 1.40e+01f16, 1.40e+01f16, + 6.80e+01f16, 6.80e+01f16, 6.80e+01f16, 6.80e+01f16, + 9.54e+01f16, 9.54e+01f16, 9.54e+01f16, 9.54e+01f16, + 4.49e+01f16, 4.49e+01f16, 4.49e+01f16, 4.49e+01f16, + }, + { + 3.50e+03f16, 3.50e+03f16, 3.50e+03f16, 3.50e+03f16, + 2.91e+03f16, 2.91e+03f16, 2.91e+03f16, 2.91e+03f16, + 1.66e+03f16, 1.66e+03f16, 1.66e+03f16, 1.66e+03f16, + 5.94e+03f16, 5.94e+03f16, 5.94e+03f16, 5.94e+03f16, + } + }, +}; + +float TEST_MULOP_DATA(float, sub)[][4][N] = +{ + { + {8.51f }, + { + 24.21f, 24.21f, 24.21f, 24.21f, + 40.31f, 40.31f, 40.31f, 40.31f, + 59.68f, 59.68f, 59.68f, 59.68f, + 45.42f, 45.42f, 45.42f, 45.42f, + }, + { + 1.94f, 1.94f, 1.94f, 1.94f, + 4.24f, 4.24f, 4.24f, 4.24f, + 6.48f, 6.48f, 6.48f, 6.48f, + 4.68f, 4.68f, 4.68f, 4.68f, + }, + { + 7.70f, 7.70f, 7.70f, 7.70f, + 4.23f, 4.23f, 4.23f, 4.23f, + 4.54f, 4.54f, 4.54f, 4.54f, + 5.59f, 5.59f, 5.59f, 5.59f, + }, +}, + { + { 85.14f }, + { + 1731.29f, 1731.29f, 1731.29f, 1731.29f, + 3656.53f, 3656.53f, 3656.53f, 3656.53f, + 5565.07f, 5565.07f, 5565.07f, 5565.07f, + 4042.14f, 4042.14f, 4042.14f, 4042.14f, + }, + { + 19.43f, 19.43f, 19.43f, 19.43f, + 42.45f, 42.45f, 42.45f, 42.45f, + 64.83f, 64.83f, 64.83f, 64.83f, + 46.82f, 46.82f, 46.82f, 46.82f, + }, + { + 77.02f, 77.02f, 77.02f, 77.02f, + 42.34f, 42.34f, 42.34f, 42.34f, + 45.44f, 45.44f, 45.44f, 45.44f, + 55.89f, 55.89f, 55.89f, 55.89f, + } + }, + { + { 99.01f }, + { + 6240.43f, 6240.43f, 6240.43f, 6240.43f, + 2179.23f, 2179.23f, 2179.23f, 2179.23f, + 5346.65f, 5346.65f, 5346.65f, 5346.65f, + 2649.91f, 2649.91f, 2649.91f, 2649.91f, + }, + { + 59.46f, 59.46f, 59.46f, 59.46f, + 16.96f, 16.96f, 16.96f, 16.96f, + 52.55f, 52.55f, 52.55f, 52.55f, + 24.70f, 24.70f, 24.70f, 24.70f, + }, + { + 353.30f, 353.30f, 353.30f, 353.30f, + 500.02f, 500.02f, 500.02f, 500.02f, + 143.67f, 143.67f, 143.67f, 143.67f, + 204.36f, 204.36f, 204.36f, 204.36f, + } + }, +}; + +double TEST_MULOP_DATA(double, sub)[][4][N] = +{ + { + { 80.54 }, + { + 5731.60, 5731.60, 5731.60, 5731.60, + 6682.41, 6682.41, 6682.41, 6682.41, + 7737.53, 7737.53, 7737.53, 7737.53, + 4922.68, 4922.68, 4922.68, 4922.68, + }, + { + 67.14, 67.14, 67.14, 67.14, + 78.23, 78.23, 78.23, 78.23, + 94.35, 94.35, 94.35, 94.35, + 49.68, 49.68, 49.68, 49.68, + }, + { + 324.14, 324.14, 324.14, 324.14, + 381.77, 381.77, 381.77, 381.77, + 138.58, 138.58, 138.58, 138.58, + 921.45, 921.45, 921.45, 921.45, + } + }, + { + { 8.05e+01 }, + { + 8.65e+27, 8.65e+27, 8.65e+27, 8.65e+27, + 1.01e+28, 1.01e+28, 1.01e+28, 1.01e+28, + 8.99e+27, 8.99e+27, 8.99e+27, 8.99e+27, + 1.32e+28, 1.32e+28, 1.32e+28, 1.32e+28, + }, + { + 6.71e+25, 6.71e+25, 6.71e+25, 6.71e+25, + 7.82e+25, 7.82e+25, 7.82e+25, 7.82e+25, + 9.44e+25, 9.44e+25, 9.44e+25, 9.44e+25, + 4.97e+25, 4.97e+25, 4.97e+25, 4.97e+25, + }, + { + 3.24e+27, 3.24e+27, 3.24e+27, 3.24e+27, + 3.82e+27, 3.82e+27, 3.82e+27, 3.82e+27, + 1.39e+27, 1.39e+27, 1.39e+27, 1.39e+27, + 9.21e+27, 9.21e+27, 9.21e+27, 9.21e+27, + } + }, + { + { 2.02e-03 }, + { + 2.7308e-35, 2.7308e-35, 2.7308e-35, 2.7308e-35, + 1.5784e-35, 1.5784e-35, 1.5784e-35, 1.5784e-35, + 2.3378e-35, 2.3378e-35, 2.3378e-35, 2.3378e-35, + 1.6918e-35, 1.6918e-35, 1.6918e-35, 1.6918e-35, + }, + { + 9.7703e-33, 9.7703e-33, 9.7703e-33, 9.7703e-33, + 4.1632e-33, 4.1632e-33, 4.1632e-33, 4.1632e-33, + 8.1964e-33, 8.1964e-33, 8.1964e-33, 8.1964e-33, + 4.7314e-33, 4.7314e-33, 4.7314e-33, 4.7314e-33, + }, + { + 7.5586e-36, 7.5586e-36, 7.5586e-36, 7.5586e-36, + 7.3684e-36, 7.3684e-36, 7.3684e-36, 7.3684e-36, + 6.8101e-36, 6.8101e-36, 6.8101e-36, 6.8101e-36, + 7.3543e-36, 7.3543e-36, 7.3543e-36, 7.3543e-36, + } + }, +}; + + +#endif diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_mulop_run.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_mulop_run.h new file mode 100644 index 0000000..bc6f483d --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_mulop_run.h @@ -0,0 +1,34 @@ +#ifndef HAVE_DEFINED_VF_MULOP_RUN_H +#define HAVE_DEFINED_VF_MULOP_RUN_H + +#include <math.h> + +#define TYPE_FABS(x, T) \ + (__builtin_types_compatible_p (T, double) ? fabs (x) : fabsf (x)) + +int +main () +{ + unsigned i, k; + + for (i = 0; i < sizeof (TEST_DATA) / sizeof (TEST_DATA[0]); i++) + { + T x = TEST_DATA[i][0][0]; + T *in = TEST_DATA[i][1]; + T *out = TEST_DATA[i][2]; + T *expect = TEST_DATA[i][3]; + + TEST_RUN (T, NAME, out, in, x, N); + + for (k = 0; k < N; k++) + { + T diff = expect[k] - out[k]; + if (TYPE_FABS (diff, T) > .01 * TYPE_FABS (expect[k], T)) + __builtin_abort (); + } + } + + return 0; +} + +#endif diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmadd-run-1-f16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmadd-run-1-f16.c new file mode 100644 index 0000000..1bcf9e0 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmadd-run-1-f16.c @@ -0,0 +1,15 @@ +/* { dg-do run { target { riscv_v } } } */ +/* { dg-additional-options "--param=fpr2vr-cost=0" } */ + +#include "vf_mulop.h" +#include "vf_mulop_data.h" + +#define T _Float16 +#define NAME add + +DEF_VF_MULOP_CASE_0_WRAP(T, +, NAME) + +#define TEST_DATA TEST_MULOP_DATA_WRAP(T, NAME) +#define TEST_RUN(T, NAME, out, in, x, n) RUN_VF_MULOP_CASE_0_WRAP(T, NAME, out, in, x, n) + +#include "vf_mulop_run.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmadd-run-1-f32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmadd-run-1-f32.c new file mode 100644 index 0000000..199b9ad --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmadd-run-1-f32.c @@ -0,0 +1,15 @@ +/* { dg-do run { target { riscv_v } } } */ +/* { dg-additional-options "--param=fpr2vr-cost=0" } */ + +#include "vf_mulop.h" +#include "vf_mulop_data.h" + +#define T float +#define NAME add + +DEF_VF_MULOP_CASE_0_WRAP(T, +, NAME) + +#define TEST_DATA TEST_MULOP_DATA_WRAP(T, NAME) +#define TEST_RUN(T, NAME, out, in, x, n) RUN_VF_MULOP_CASE_0_WRAP(T, NAME, out, in, x, n) + +#include "vf_mulop_run.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmadd-run-1-f64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmadd-run-1-f64.c new file mode 100644 index 0000000..3857f58 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmadd-run-1-f64.c @@ -0,0 +1,15 @@ +/* { dg-do run { target { riscv_v } } } */ +/* { dg-additional-options "--param=fpr2vr-cost=0" } */ + +#include "vf_mulop.h" +#include "vf_mulop_data.h" + +#define T double +#define NAME add + +DEF_VF_MULOP_CASE_0_WRAP(T, +, NAME) + +#define TEST_DATA TEST_MULOP_DATA_WRAP(T, NAME) +#define TEST_RUN(T, NAME, out, in, x, n) RUN_VF_MULOP_CASE_0_WRAP(T, NAME, out, in, x, n) + +#include "vf_mulop_run.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmsub-run-1-f16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmsub-run-1-f16.c new file mode 100644 index 0000000..671c7d8 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmsub-run-1-f16.c @@ -0,0 +1,15 @@ +/* { dg-do run { target { riscv_v } } } */ +/* { dg-additional-options "--param=fpr2vr-cost=0" } */ + +#include "vf_mulop.h" +#include "vf_mulop_data.h" + +#define T _Float16 +#define NAME sub + +DEF_VF_MULOP_CASE_0_WRAP(T, -, NAME) + +#define TEST_DATA TEST_MULOP_DATA_WRAP(T, NAME) +#define TEST_RUN(T, NAME, out, in, x, n) RUN_VF_MULOP_CASE_0_WRAP(T, NAME, out, in, x, n) + +#include "vf_mulop_run.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmsub-run-1-f32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmsub-run-1-f32.c new file mode 100644 index 0000000..f896963 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmsub-run-1-f32.c @@ -0,0 +1,15 @@ +/* { dg-do run { target { riscv_v } } } */ +/* { dg-additional-options "--param=fpr2vr-cost=0" } */ + +#include "vf_mulop.h" +#include "vf_mulop_data.h" + +#define T float +#define NAME sub + +DEF_VF_MULOP_CASE_0_WRAP(T, -, NAME) + +#define TEST_DATA TEST_MULOP_DATA_WRAP(T, NAME) +#define TEST_RUN(T, NAME, out, in, x, n) RUN_VF_MULOP_CASE_0_WRAP(T, NAME, out, in, x, n) + +#include "vf_mulop_run.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmsub-run-1-f64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmsub-run-1-f64.c new file mode 100644 index 0000000..b42ab1e --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmsub-run-1-f64.c @@ -0,0 +1,15 @@ +/* { dg-do run { target { riscv_v } } } */ +/* { dg-additional-options "--param=fpr2vr-cost=0" } */ + +#include "vf_mulop.h" +#include "vf_mulop_data.h" + +#define T double +#define NAME sub + +DEF_VF_MULOP_CASE_0_WRAP(T, -, NAME) + +#define TEST_DATA TEST_MULOP_DATA_WRAP(T, NAME) +#define TEST_RUN(T, NAME, out, in, x, n) RUN_VF_MULOP_CASE_0_WRAP(T, NAME, out, in, x, n) + +#include "vf_mulop_run.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i16.c index 144d1ba..d88e76b 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i16.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i16.c @@ -12,6 +12,7 @@ DEF_VX_BINARY_CASE_0_WRAP(T, &, and) DEF_VX_BINARY_CASE_0_WRAP(T, |, or) DEF_VX_BINARY_CASE_0_WRAP(T, ^, xor) DEF_VX_BINARY_CASE_0_WRAP(T, *, mul) +DEF_VX_BINARY_CASE_0_WRAP(T, /, div) /* { dg-final { scan-assembler-times {vadd.vx} 1 } } */ /* { dg-final { scan-assembler-times {vsub.vx} 1 } } */ @@ -20,3 +21,4 @@ DEF_VX_BINARY_CASE_0_WRAP(T, *, mul) /* { dg-final { scan-assembler-times {vor.vx} 1 } } */ /* { dg-final { scan-assembler-times {vxor.vx} 1 } } */ /* { dg-final { scan-assembler-times {vmul.vx} 1 } } */ +/* { dg-final { scan-assembler-times {vdiv.vx} 1 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i32.c index 74d35d1..53189c2 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i32.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i32.c @@ -12,6 +12,7 @@ DEF_VX_BINARY_CASE_0_WRAP(T, &, and) DEF_VX_BINARY_CASE_0_WRAP(T, |, or) DEF_VX_BINARY_CASE_0_WRAP(T, ^, xor) DEF_VX_BINARY_CASE_0_WRAP(T, *, mul) +DEF_VX_BINARY_CASE_0_WRAP(T, /, div) /* { dg-final { scan-assembler-times {vadd.vx} 1 } } */ /* { dg-final { scan-assembler-times {vsub.vx} 1 } } */ @@ -20,3 +21,4 @@ DEF_VX_BINARY_CASE_0_WRAP(T, *, mul) /* { dg-final { scan-assembler-times {vor.vx} 1 } } */ /* { dg-final { scan-assembler-times {vxor.vx} 1 } } */ /* { dg-final { scan-assembler-times {vmul.vx} 1 } } */ +/* { dg-final { scan-assembler-times {vdiv.vx} 1 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i64.c index ac512ff..5059beb 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i64.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i64.c @@ -12,6 +12,7 @@ DEF_VX_BINARY_CASE_0_WRAP(T, &, and) DEF_VX_BINARY_CASE_0_WRAP(T, |, or) DEF_VX_BINARY_CASE_0_WRAP(T, ^, xor) DEF_VX_BINARY_CASE_0_WRAP(T, *, mul) +DEF_VX_BINARY_CASE_0_WRAP(T, /, div) /* { dg-final { scan-assembler-times {vadd.vx} 1 } } */ /* { dg-final { scan-assembler-times {vsub.vx} 1 } } */ @@ -20,3 +21,4 @@ DEF_VX_BINARY_CASE_0_WRAP(T, *, mul) /* { dg-final { scan-assembler-times {vor.vx} 1 } } */ /* { dg-final { scan-assembler-times {vxor.vx} 1 } } */ /* { dg-final { scan-assembler-times {vmul.vx} 1 } } */ +/* { dg-final { scan-assembler-times {vdiv.vx} 1 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i8.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i8.c index 4f7b675..4bbe5a4 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i8.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i8.c @@ -12,6 +12,7 @@ DEF_VX_BINARY_CASE_0_WRAP(T, &, and) DEF_VX_BINARY_CASE_0_WRAP(T, |, or) DEF_VX_BINARY_CASE_0_WRAP(T, ^, xor) DEF_VX_BINARY_CASE_0_WRAP(T, *, mul) +DEF_VX_BINARY_CASE_0_WRAP(T, /, div) /* { dg-final { scan-assembler-times {vadd.vx} 1 } } */ /* { dg-final { scan-assembler-times {vsub.vx} 1 } } */ @@ -20,3 +21,4 @@ DEF_VX_BINARY_CASE_0_WRAP(T, *, mul) /* { dg-final { scan-assembler-times {vor.vx} 1 } } */ /* { dg-final { scan-assembler-times {vxor.vx} 1 } } */ /* { dg-final { scan-assembler-times {vmul.vx} 1 } } */ +/* { dg-final { scan-assembler-times {vdiv.vx} 1 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i16.c index 075c8be..0437db4 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i16.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i16.c @@ -12,6 +12,7 @@ DEF_VX_BINARY_CASE_0_WRAP(T, &, and) DEF_VX_BINARY_CASE_0_WRAP(T, |, or) DEF_VX_BINARY_CASE_0_WRAP(T, ^, xor) DEF_VX_BINARY_CASE_0_WRAP(T, *, mul) +DEF_VX_BINARY_CASE_0_WRAP(T, /, div) /* { dg-final { scan-assembler-not {vadd.vx} } } */ /* { dg-final { scan-assembler-not {vsub.vx} } } */ @@ -20,3 +21,4 @@ DEF_VX_BINARY_CASE_0_WRAP(T, *, mul) /* { dg-final { scan-assembler-not {vor.vx} } } */ /* { dg-final { scan-assembler-not {vxor.vx} } } */ /* { dg-final { scan-assembler-not {vmul.vx} } } */ +/* { dg-final { scan-assembler-not {vdiv.vx} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i32.c index 595479c..95ed403 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i32.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i32.c @@ -12,6 +12,7 @@ DEF_VX_BINARY_CASE_0_WRAP(T, &, and) DEF_VX_BINARY_CASE_0_WRAP(T, |, or) DEF_VX_BINARY_CASE_0_WRAP(T, ^, xor) DEF_VX_BINARY_CASE_0_WRAP(T, *, mul) +DEF_VX_BINARY_CASE_0_WRAP(T, /, div) /* { dg-final { scan-assembler-not {vadd.vx} } } */ /* { dg-final { scan-assembler-not {vsub.vx} } } */ @@ -20,3 +21,4 @@ DEF_VX_BINARY_CASE_0_WRAP(T, *, mul) /* { dg-final { scan-assembler-not {vor.vx} } } */ /* { dg-final { scan-assembler-not {vxor.vx} } } */ /* { dg-final { scan-assembler-not {vmul.vx} } } */ +/* { dg-final { scan-assembler-not {vdiv.vx} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i64.c index 7b6fcbf..f8912a0 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i64.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i64.c @@ -12,6 +12,7 @@ DEF_VX_BINARY_CASE_0_WRAP(T, &, and) DEF_VX_BINARY_CASE_0_WRAP(T, |, or) DEF_VX_BINARY_CASE_0_WRAP(T, ^, xor) DEF_VX_BINARY_CASE_0_WRAP(T, *, mul) +DEF_VX_BINARY_CASE_0_WRAP(T, /, div) /* { dg-final { scan-assembler-not {vadd.vx} } } */ /* { dg-final { scan-assembler-not {vsub.vx} } } */ @@ -20,3 +21,4 @@ DEF_VX_BINARY_CASE_0_WRAP(T, *, mul) /* { dg-final { scan-assembler-not {vor.vx} } } */ /* { dg-final { scan-assembler-not {vxor.vx} } } */ /* { dg-final { scan-assembler-not {vmul.vx} } } */ +/* { dg-final { scan-assembler-not {vdiv.vx} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i8.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i8.c index 55fc717..3c8f915 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i8.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i8.c @@ -12,6 +12,7 @@ DEF_VX_BINARY_CASE_0_WRAP(T, &, and) DEF_VX_BINARY_CASE_0_WRAP(T, |, or) DEF_VX_BINARY_CASE_0_WRAP(T, ^, xor) DEF_VX_BINARY_CASE_0_WRAP(T, *, mul) +DEF_VX_BINARY_CASE_0_WRAP(T, /, div) /* { dg-final { scan-assembler-not {vadd.vx} } } */ /* { dg-final { scan-assembler-not {vsub.vx} } } */ @@ -20,3 +21,4 @@ DEF_VX_BINARY_CASE_0_WRAP(T, *, mul) /* { dg-final { scan-assembler-not {vor.vx} } } */ /* { dg-final { scan-assembler-not {vxor.vx} } } */ /* { dg-final { scan-assembler-not {vmul.vx} } } */ +/* { dg-final { scan-assembler-not {vdiv.vx} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i16.c index bec6b3a..f49dae4 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i16.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i16.c @@ -12,6 +12,7 @@ DEF_VX_BINARY_CASE_0_WRAP(T, &, and) DEF_VX_BINARY_CASE_0_WRAP(T, |, or) DEF_VX_BINARY_CASE_0_WRAP(T, ^, xor) DEF_VX_BINARY_CASE_0_WRAP(T, *, mul) +DEF_VX_BINARY_CASE_0_WRAP(T, /, div) /* { dg-final { scan-assembler-not {vadd.vx} } } */ /* { dg-final { scan-assembler-not {vsub.vx} } } */ @@ -20,3 +21,4 @@ DEF_VX_BINARY_CASE_0_WRAP(T, *, mul) /* { dg-final { scan-assembler-not {vor.vx} } } */ /* { dg-final { scan-assembler-not {vxor.vx} } } */ /* { dg-final { scan-assembler-not {vmul.vx} } } */ +/* { dg-final { scan-assembler-not {vdiv.vx} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i32.c index 98fce52..8f502a3 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i32.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i32.c @@ -12,6 +12,7 @@ DEF_VX_BINARY_CASE_0_WRAP(T, &, and) DEF_VX_BINARY_CASE_0_WRAP(T, |, or) DEF_VX_BINARY_CASE_0_WRAP(T, ^, xor) DEF_VX_BINARY_CASE_0_WRAP(T, *, mul) +DEF_VX_BINARY_CASE_0_WRAP(T, /, div) /* { dg-final { scan-assembler-not {vadd.vx} } } */ /* { dg-final { scan-assembler-not {vsub.vx} } } */ @@ -20,3 +21,4 @@ DEF_VX_BINARY_CASE_0_WRAP(T, *, mul) /* { dg-final { scan-assembler-not {vor.vx} } } */ /* { dg-final { scan-assembler-not {vxor.vx} } } */ /* { dg-final { scan-assembler-not {vmul.vx} } } */ +/* { dg-final { scan-assembler-not {vdiv.vx} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i64.c index 48dd57a..3277bf2 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i64.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i64.c @@ -12,6 +12,7 @@ DEF_VX_BINARY_CASE_0_WRAP(T, &, and) DEF_VX_BINARY_CASE_0_WRAP(T, |, or) DEF_VX_BINARY_CASE_0_WRAP(T, ^, xor) DEF_VX_BINARY_CASE_0_WRAP(T, *, mul) +DEF_VX_BINARY_CASE_0_WRAP(T, /, div) /* { dg-final { scan-assembler-not {vadd.vx} } } */ /* { dg-final { scan-assembler-not {vsub.vx} } } */ @@ -20,3 +21,4 @@ DEF_VX_BINARY_CASE_0_WRAP(T, *, mul) /* { dg-final { scan-assembler-not {vor.vx} } } */ /* { dg-final { scan-assembler-not {vxor.vx} } } */ /* { dg-final { scan-assembler-not {vmul.vx} } } */ +/* { dg-final { scan-assembler-not {vdiv.vx} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i8.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i8.c index 9bdce82..25ed2ad 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i8.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i8.c @@ -12,6 +12,7 @@ DEF_VX_BINARY_CASE_0_WRAP(T, &, and) DEF_VX_BINARY_CASE_0_WRAP(T, |, or) DEF_VX_BINARY_CASE_0_WRAP(T, ^, xor) DEF_VX_BINARY_CASE_0_WRAP(T, *, mul) +DEF_VX_BINARY_CASE_0_WRAP(T, /, div) /* { dg-final { scan-assembler-not {vadd.vx} } } */ /* { dg-final { scan-assembler-not {vsub.vx} } } */ @@ -20,3 +21,4 @@ DEF_VX_BINARY_CASE_0_WRAP(T, *, mul) /* { dg-final { scan-assembler-not {vor.vx} } } */ /* { dg-final { scan-assembler-not {vxor.vx} } } */ /* { dg-final { scan-assembler-not {vmul.vx} } } */ +/* { dg-final { scan-assembler-not {vdiv.vx} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-i16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-i16.c index a1b24f7..1e409de 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-i16.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-i16.c @@ -12,6 +12,7 @@ DEF_VX_BINARY_CASE_1_WRAP(T, &, and, VX_BINARY_BODY_X16) DEF_VX_BINARY_CASE_1_WRAP(T, |, or, VX_BINARY_BODY_X16) DEF_VX_BINARY_CASE_1_WRAP(T, ^, xor, VX_BINARY_BODY_X16) DEF_VX_BINARY_CASE_1_WRAP(T, *, mul, VX_BINARY_BODY_X16) +DEF_VX_BINARY_CASE_1_WRAP(T, /, div, VX_BINARY_BODY_X16) /* { dg-final { scan-assembler {vadd.vx} } } */ /* { dg-final { scan-assembler {vsub.vx} } } */ @@ -20,3 +21,4 @@ DEF_VX_BINARY_CASE_1_WRAP(T, *, mul, VX_BINARY_BODY_X16) /* { dg-final { scan-assembler {vor.vx} } } */ /* { dg-final { scan-assembler {vxor.vx} } } */ /* { dg-final { scan-assembler {vmul.vx} } } */ +/* { dg-final { scan-assembler {vdiv.vx} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-i32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-i32.c index 53bd744..2f242c7 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-i32.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-i32.c @@ -12,6 +12,7 @@ DEF_VX_BINARY_CASE_1_WRAP(T, &, and, VX_BINARY_BODY_X4) DEF_VX_BINARY_CASE_1_WRAP(T, |, or, VX_BINARY_BODY_X4) DEF_VX_BINARY_CASE_1_WRAP(T, ^, xor, VX_BINARY_BODY_X4) DEF_VX_BINARY_CASE_1_WRAP(T, *, mul, VX_BINARY_BODY_X4) +DEF_VX_BINARY_CASE_1_WRAP(T, /, div, VX_BINARY_BODY_X4) /* { dg-final { scan-assembler {vadd.vx} } } */ /* { dg-final { scan-assembler {vsub.vx} } } */ @@ -20,3 +21,4 @@ DEF_VX_BINARY_CASE_1_WRAP(T, *, mul, VX_BINARY_BODY_X4) /* { dg-final { scan-assembler {vor.vx} } } */ /* { dg-final { scan-assembler {vxor.vx} } } */ /* { dg-final { scan-assembler {vmul.vx} } } */ +/* { dg-final { scan-assembler {vdiv.vx} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-i64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-i64.c index 73cb89d..f027bd8 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-i64.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-i64.c @@ -12,6 +12,7 @@ DEF_VX_BINARY_CASE_1_WRAP(T, &, and, VX_BINARY_BODY) DEF_VX_BINARY_CASE_1_WRAP(T, |, or, VX_BINARY_BODY) DEF_VX_BINARY_CASE_1_WRAP(T, ^, xor, VX_BINARY_BODY) DEF_VX_BINARY_CASE_1_WRAP(T, *, mul, VX_BINARY_BODY) +DEF_VX_BINARY_CASE_1_WRAP(T, /, div, VX_BINARY_BODY) /* { dg-final { scan-assembler {vadd.vx} } } */ /* { dg-final { scan-assembler {vsub.vx} } } */ @@ -20,3 +21,4 @@ DEF_VX_BINARY_CASE_1_WRAP(T, *, mul, VX_BINARY_BODY) /* { dg-final { scan-assembler {vor.vx} } } */ /* { dg-final { scan-assembler {vxor.vx} } } */ /* { dg-final { scan-assembler {vmul.vx} } } */ +/* { dg-final { scan-assembler {vdiv.vx} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-i8.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-i8.c index ec20474..c4f55b0 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-i8.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-i8.c @@ -12,6 +12,7 @@ DEF_VX_BINARY_CASE_1_WRAP(T, &, and, VX_BINARY_BODY_X16) DEF_VX_BINARY_CASE_1_WRAP(T, |, or, VX_BINARY_BODY_X16) DEF_VX_BINARY_CASE_1_WRAP(T, ^, xor, VX_BINARY_BODY_X16) DEF_VX_BINARY_CASE_1_WRAP(T, *, mul, VX_BINARY_BODY_X16) +DEF_VX_BINARY_CASE_1_WRAP(T, /, div, VX_BINARY_BODY_X8) /* { dg-final { scan-assembler {vadd.vx} } } */ /* { dg-final { scan-assembler {vsub.vx} } } */ @@ -20,3 +21,4 @@ DEF_VX_BINARY_CASE_1_WRAP(T, *, mul, VX_BINARY_BODY_X16) /* { dg-final { scan-assembler {vor.vx} } } */ /* { dg-final { scan-assembler {vxor.vx} } } */ /* { dg-final { scan-assembler {vmul.vx} } } */ +/* { dg-final { scan-assembler {vdiv.vx} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-i16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-i16.c index 902ba1e..d6b05bc 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-i16.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-i16.c @@ -12,6 +12,7 @@ DEF_VX_BINARY_CASE_1_WRAP(T, &, and, VX_BINARY_BODY_X8) DEF_VX_BINARY_CASE_1_WRAP(T, |, or, VX_BINARY_BODY_X8) DEF_VX_BINARY_CASE_1_WRAP(T, ^, xor, VX_BINARY_BODY_X8) DEF_VX_BINARY_CASE_1_WRAP(T, *, mul, VX_BINARY_BODY_X8) +DEF_VX_BINARY_CASE_1_WRAP(T, /, div, VX_BINARY_BODY_X8) /* { dg-final { scan-assembler-not {vadd.vx} } } */ /* { dg-final { scan-assembler {vsub.vx} } } */ @@ -20,3 +21,4 @@ DEF_VX_BINARY_CASE_1_WRAP(T, *, mul, VX_BINARY_BODY_X8) /* { dg-final { scan-assembler {vor.vx} } } */ /* { dg-final { scan-assembler {vxor.vx} } } */ /* { dg-final { scan-assembler-not {vmul.vx} } } */ +/* { dg-final { scan-assembler {vdiv.vx} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-i32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-i32.c index e57cee6..e1c043f 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-i32.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-i32.c @@ -12,6 +12,7 @@ DEF_VX_BINARY_CASE_1_WRAP(T, &, and, VX_BINARY_BODY_X4) DEF_VX_BINARY_CASE_1_WRAP(T, |, or, VX_BINARY_BODY_X4) DEF_VX_BINARY_CASE_1_WRAP(T, ^, xor, VX_BINARY_BODY_X4) DEF_VX_BINARY_CASE_1_WRAP(T, *, mul, VX_BINARY_BODY_X4) +DEF_VX_BINARY_CASE_1_WRAP(T, /, div, VX_BINARY_BODY_X4) /* { dg-final { scan-assembler {vadd.vx} } } */ /* { dg-final { scan-assembler {vsub.vx} } } */ @@ -20,3 +21,4 @@ DEF_VX_BINARY_CASE_1_WRAP(T, *, mul, VX_BINARY_BODY_X4) /* { dg-final { scan-assembler {vor.vx} } } */ /* { dg-final { scan-assembler {vxor.vx} } } */ /* { dg-final { scan-assembler {vmul.vx} } } */ +/* { dg-final { scan-assembler {vdiv.vx} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-i64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-i64.c index 3b4138d..1beb914 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-i64.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-i64.c @@ -12,6 +12,7 @@ DEF_VX_BINARY_CASE_1_WRAP(T, &, and, VX_BINARY_BODY) DEF_VX_BINARY_CASE_1_WRAP(T, |, or, VX_BINARY_BODY) DEF_VX_BINARY_CASE_1_WRAP(T, ^, xor, VX_BINARY_BODY) DEF_VX_BINARY_CASE_1_WRAP(T, *, mul, VX_BINARY_BODY) +DEF_VX_BINARY_CASE_1_WRAP(T, /, div, VX_BINARY_BODY) /* { dg-final { scan-assembler {vadd.vx} } } */ /* { dg-final { scan-assembler {vsub.vx} } } */ @@ -20,3 +21,4 @@ DEF_VX_BINARY_CASE_1_WRAP(T, *, mul, VX_BINARY_BODY) /* { dg-final { scan-assembler {vor.vx} } } */ /* { dg-final { scan-assembler {vxor.vx} } } */ /* { dg-final { scan-assembler {vmul.vx} } } */ +/* { dg-final { scan-assembler {vdiv.vx} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-i8.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-i8.c index 0ad52b2..0291517 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-i8.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-i8.c @@ -12,6 +12,7 @@ DEF_VX_BINARY_CASE_1_WRAP(T, &, and, VX_BINARY_BODY_X16) DEF_VX_BINARY_CASE_1_WRAP(T, |, or, VX_BINARY_BODY_X16) DEF_VX_BINARY_CASE_1_WRAP(T, ^, xor, VX_BINARY_BODY_X16) DEF_VX_BINARY_CASE_1_WRAP(T, *, mul, VX_BINARY_BODY_X16) +DEF_VX_BINARY_CASE_1_WRAP(T, /, div, VX_BINARY_BODY_X8) /* { dg-final { scan-assembler-not {vadd.vx} } } */ /* { dg-final { scan-assembler {vsub.vx} } } */ @@ -20,3 +21,4 @@ DEF_VX_BINARY_CASE_1_WRAP(T, *, mul, VX_BINARY_BODY_X16) /* { dg-final { scan-assembler {vor.vx} } } */ /* { dg-final { scan-assembler {vxor.vx} } } */ /* { dg-final { scan-assembler-not {vmul.vx} } } */ +/* { dg-final { scan-assembler {vdiv.vx} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-i16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-i16.c index 5e04050..c22c82d 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-i16.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-i16.c @@ -12,6 +12,7 @@ DEF_VX_BINARY_CASE_1_WRAP(T, &, and, VX_BINARY_BODY_X8) DEF_VX_BINARY_CASE_1_WRAP(T, |, or, VX_BINARY_BODY_X8) DEF_VX_BINARY_CASE_1_WRAP(T, ^, xor, VX_BINARY_BODY_X8) DEF_VX_BINARY_CASE_1_WRAP(T, *, mul, VX_BINARY_BODY_X8) +DEF_VX_BINARY_CASE_1_WRAP(T, /, div, VX_BINARY_BODY_X8) /* { dg-final { scan-assembler-not {vadd.vx} } } */ /* { dg-final { scan-assembler {vsub.vx} } } */ @@ -20,3 +21,4 @@ DEF_VX_BINARY_CASE_1_WRAP(T, *, mul, VX_BINARY_BODY_X8) /* { dg-final { scan-assembler {vor.vx} } } */ /* { dg-final { scan-assembler {vxor.vx} } } */ /* { dg-final { scan-assembler-not {vmul.vx} } } */ +/* { dg-final { scan-assembler {vdiv.vx} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-i32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-i32.c index 13a9fe2..dc35600 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-i32.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-i32.c @@ -12,6 +12,7 @@ DEF_VX_BINARY_CASE_1_WRAP(T, &, and, VX_BINARY_BODY_X4) DEF_VX_BINARY_CASE_1_WRAP(T, |, or, VX_BINARY_BODY_X4) DEF_VX_BINARY_CASE_1_WRAP(T, ^, xor, VX_BINARY_BODY_X4) DEF_VX_BINARY_CASE_1_WRAP(T, *, mul, VX_BINARY_BODY_X4) +DEF_VX_BINARY_CASE_1_WRAP(T, /, div, VX_BINARY_BODY_X4) /* { dg-final { scan-assembler {vadd.vx} } } */ /* { dg-final { scan-assembler {vsub.vx} } } */ @@ -20,3 +21,4 @@ DEF_VX_BINARY_CASE_1_WRAP(T, *, mul, VX_BINARY_BODY_X4) /* { dg-final { scan-assembler {vor.vx} } } */ /* { dg-final { scan-assembler {vxor.vx} } } */ /* { dg-final { scan-assembler {vmul.vx} } } */ +/* { dg-final { scan-assembler {vdiv.vx} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-i64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-i64.c index ca515b4..cee1e3a 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-i64.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-i64.c @@ -12,6 +12,7 @@ DEF_VX_BINARY_CASE_1_WRAP(T, &, and, VX_BINARY_BODY) DEF_VX_BINARY_CASE_1_WRAP(T, |, or, VX_BINARY_BODY) DEF_VX_BINARY_CASE_1_WRAP(T, ^, xor, VX_BINARY_BODY) DEF_VX_BINARY_CASE_1_WRAP(T, *, mul, VX_BINARY_BODY) +DEF_VX_BINARY_CASE_1_WRAP(T, /, div, VX_BINARY_BODY) /* { dg-final { scan-assembler-not {vadd.vx} } } */ /* { dg-final { scan-assembler-not {vsub.vx} } } */ @@ -20,3 +21,4 @@ DEF_VX_BINARY_CASE_1_WRAP(T, *, mul, VX_BINARY_BODY) /* { dg-final { scan-assembler-not {vor.vx} } } */ /* { dg-final { scan-assembler-not {vxor.vx} } } */ /* { dg-final { scan-assembler-not {vmul.vx} } } */ +/* { dg-final { scan-assembler-not {vdiv.vx} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-i8.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-i8.c index 70e1abc..74fd2fb 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-i8.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-i8.c @@ -12,6 +12,7 @@ DEF_VX_BINARY_CASE_1_WRAP(T, &, and, VX_BINARY_BODY_X16) DEF_VX_BINARY_CASE_1_WRAP(T, |, or, VX_BINARY_BODY_X16) DEF_VX_BINARY_CASE_1_WRAP(T, ^, xor, VX_BINARY_BODY_X16) DEF_VX_BINARY_CASE_1_WRAP(T, *, mul, VX_BINARY_BODY_X16) +DEF_VX_BINARY_CASE_1_WRAP(T, /, div, VX_BINARY_BODY_X8) /* { dg-final { scan-assembler-not {vadd.vx} } } */ /* { dg-final { scan-assembler {vsub.vx} } } */ @@ -20,3 +21,4 @@ DEF_VX_BINARY_CASE_1_WRAP(T, *, mul, VX_BINARY_BODY_X16) /* { dg-final { scan-assembler {vor.vx} } } */ /* { dg-final { scan-assembler {vxor.vx} } } */ /* { dg-final { scan-assembler-not {vmul.vx} } } */ +/* { dg-final { scan-assembler {vdiv.vx} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_binary_data.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_binary_data.h index c7289ac..ed8c562 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_binary_data.h +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_binary_data.h @@ -2554,4 +2554,200 @@ int64_t TEST_BINARY_DATA(int64_t, mul)[][3][N] = }, }; +int8_t TEST_BINARY_DATA(int8_t, div)[][3][N] = +{ + { + { 1 }, + { + 2, 2, 2, 2, + 1, 1, 1, 1, + -1, -1, -1, -1, + -2, -2, -2, -2, + }, + { + 2, 2, 2, 2, + 1, 1, 1, 1, + -1, -1, -1, -1, + -2, -2, -2, -2, + }, + }, + { + { 127 }, + { + 127, 127, 127, 127, + -1, -1, -1, -1, + -128, -128, -128, -128, + -2, -2, -2, -2, + }, + { + 1, 1, 1, 1, + 0, 0, 0, 0, + -1, -1, -1, -1, + 0, 0, 0, 0, + }, + }, + { + { -128 }, + { + -128, -128, -128, -128, + 1, 1, 1, 1, + 127, 127, 127, 127, + 2, 2, 2, 2, + }, + { + 1, 1, 1, 1, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + }, + }, +}; + +int16_t TEST_BINARY_DATA(int16_t, div)[][3][N] = +{ + { + { 1 }, + { + 2, 2, 2, 2, + 1, 1, 1, 1, + -1, -1, -1, -1, + -2, -2, -2, -2, + }, + { + 2, 2, 2, 2, + 1, 1, 1, 1, + -1, -1, -1, -1, + -2, -2, -2, -2, + }, + }, + { + { 32767 }, + { + 32767, 32767, 32767, 32767, + -1, -1, -1, -1, + -32768, -32768, -32768, -32768, + -2, -2, -2, -2, + }, + { + 1, 1, 1, 1, + 0, 0, 0, 0, + -1, -1, -1, -1, + 0, 0, 0, 0, + }, + }, + { + { -32768 }, + { + -32768, -32768, -32768, -32768, + 1, 1, 1, 1, + 32767, 32767, 32767, 32767, + 2, 2, 2, 2, + }, + { + 1, 1, 1, 1, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + }, + }, +}; + +int32_t TEST_BINARY_DATA(int32_t, div)[][3][N] = +{ + { + { 1 }, + { + 2, 2, 2, 2, + 1, 1, 1, 1, + -1, -1, -1, -1, + -2, -2, -2, -2, + }, + { + 2, 2, 2, 2, + 1, 1, 1, 1, + -1, -1, -1, -1, + -2, -2, -2, -2, + }, + }, + { + { 2147483647 }, + { + 2147483647, 2147483647, 2147483647, 2147483647, + -1, -1, -1, -1, + -2147483648, -2147483648, -2147483648, -2147483648, + -2, -2, -2, -2, + }, + { + 1, 1, 1, 1, + 0, 0, 0, 0, + -1, -1, -1, -1, + 0, 0, 0, 0, + }, + }, + { + { -2147483648 }, + { + -2147483648, -2147483648, -2147483648, -2147483648, + 1, 1, 1, 1, + 2147483647, 2147483647, 2147483647, 2147483647, + 2, 2, 2, 2, + }, + { + 1, 1, 1, 1, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + }, + }, +}; + +int64_t TEST_BINARY_DATA(int64_t, div)[][3][N] = +{ + { + { 1 }, + { + 2, 2, 2, 2, + 1, 1, 1, 1, + -1, -1, -1, -1, + -2, -2, -2, -2, + }, + { + 2, 2, 2, 2, + 1, 1, 1, 1, + -1, -1, -1, -1, + -2, -2, -2, -2, + }, + }, + { + { 9223372036854775807ll }, + { + 9223372036854775807ll, 9223372036854775807ll, 9223372036854775807ll, 9223372036854775807ll, + -1, -1, -1, -1, + -9223372036854775808ull, -9223372036854775808ull, -9223372036854775808ull, -9223372036854775808ull, + -2, -2, -2, -2, + }, + { + 1, 1, 1, 1, + 0, 0, 0, 0, + -1, -1, -1, -1, + 0, 0, 0, 0, + }, + }, + { + { -9223372036854775808ull }, + { + -9223372036854775808ull, -9223372036854775808ull, -9223372036854775808ull, -9223372036854775808ull, + 1, 1, 1, 1, + 9223372036854775807ll, 9223372036854775807ll, 9223372036854775807ll, 9223372036854775807ll, + 2, 2, 2, 2, + }, + { + 1, 1, 1, 1, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + }, + }, +}; + #endif diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vdiv-run-1-i16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vdiv-run-1-i16.c new file mode 100644 index 0000000..64cf31c --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vdiv-run-1-i16.c @@ -0,0 +1,15 @@ +/* { dg-do run { target { riscv_v } } } */ +/* { dg-additional-options "-std=c99 --param=gpr2vr-cost=0" } */ + +#include "vx_binary.h" +#include "vx_binary_data.h" + +#define T int16_t +#define NAME div + +DEF_VX_BINARY_CASE_0_WRAP(T, /, NAME) + +#define TEST_DATA TEST_BINARY_DATA_WRAP(T, NAME) +#define TEST_RUN(T, NAME, out, in, x, n) RUN_VX_BINARY_CASE_0_WRAP(T, NAME, out, in, x, n) + +#include "vx_binary_run.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vdiv-run-1-i32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vdiv-run-1-i32.c new file mode 100644 index 0000000..2fe6623 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vdiv-run-1-i32.c @@ -0,0 +1,15 @@ +/* { dg-do run { target { riscv_v } } } */ +/* { dg-additional-options "-std=c99 --param=gpr2vr-cost=0" } */ + +#include "vx_binary.h" +#include "vx_binary_data.h" + +#define T int32_t +#define NAME div + +DEF_VX_BINARY_CASE_0_WRAP(T, /, NAME) + +#define TEST_DATA TEST_BINARY_DATA_WRAP(T, NAME) +#define TEST_RUN(T, NAME, out, in, x, n) RUN_VX_BINARY_CASE_0_WRAP(T, NAME, out, in, x, n) + +#include "vx_binary_run.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vdiv-run-1-i64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vdiv-run-1-i64.c new file mode 100644 index 0000000..03dbe03 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vdiv-run-1-i64.c @@ -0,0 +1,15 @@ +/* { dg-do run { target { riscv_v } } } */ +/* { dg-additional-options "-std=c99 --param=gpr2vr-cost=0" } */ + +#include "vx_binary.h" +#include "vx_binary_data.h" + +#define T int64_t +#define NAME div + +DEF_VX_BINARY_CASE_0_WRAP(T, /, NAME) + +#define TEST_DATA TEST_BINARY_DATA_WRAP(T, NAME) +#define TEST_RUN(T, NAME, out, in, x, n) RUN_VX_BINARY_CASE_0_WRAP(T, NAME, out, in, x, n) + +#include "vx_binary_run.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vdiv-run-1-i8.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vdiv-run-1-i8.c new file mode 100644 index 0000000..e54e5bc --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vdiv-run-1-i8.c @@ -0,0 +1,15 @@ +/* { dg-do run { target { riscv_v } } } */ +/* { dg-additional-options "-std=c99 --param=gpr2vr-cost=0" } */ + +#include "vx_binary.h" +#include "vx_binary_data.h" + +#define T int8_t +#define NAME div + +DEF_VX_BINARY_CASE_0_WRAP(T, /, NAME) + +#define TEST_DATA TEST_BINARY_DATA_WRAP(T, NAME) +#define TEST_RUN(T, NAME, out, in, x, n) RUN_VX_BINARY_CASE_0_WRAP(T, NAME, out, in, x, n) + +#include "vx_binary_run.h" diff --git a/gcc/testsuite/gfortran.dg/coarray_data_2.f90 b/gcc/testsuite/gfortran.dg/coarray_data_2.f90 new file mode 100644 index 0000000..bda57f3 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/coarray_data_2.f90 @@ -0,0 +1,14 @@ +! { dg-do compile } +! { dg-additional-options "-fcoarray=lib -Warray-temporaries" } +! +! PR fortran/99838 - ICE due to missing locus with data statement for coarray +! +! Contributed by Gerhard Steinmetz + +program p + type t + integer :: a + end type + type(t) :: x(3)[*] + data x%a /1, 2, 3/ ! { dg-warning "Creating array temporary" } +end diff --git a/gcc/testsuite/gfortran.dg/pr119856.f90 b/gcc/testsuite/gfortran.dg/pr119856.f90 new file mode 100644 index 0000000..60ada0a --- /dev/null +++ b/gcc/testsuite/gfortran.dg/pr119856.f90 @@ -0,0 +1,15 @@ +! { dg-do run } +! PR119856, the error should occur in both write statements. +program badfmt + implicit none + + character(10):: fmt = "(AI5)" ! Not a PARAMETER so not examined + ! at compile time + integer :: ioerr + ioerr = 0 + write (*, fmt, iostat=ioerr) 'value =', 42 + if (ioerr /= 5006) stop 10 +! + write (*, fmt, iostat=ioerr) 'value =', 43 + if (ioerr /= 5006) stop 13 +end program badfmt diff --git a/gcc/testsuite/gm2/pim/fail/testcharint.mod b/gcc/testsuite/gm2/pim/fail/testcharint.mod new file mode 100644 index 0000000..d403651 --- /dev/null +++ b/gcc/testsuite/gm2/pim/fail/testcharint.mod @@ -0,0 +1,8 @@ +MODULE testcharint ; (*!m2iso+gm2*) + +VAR + ch: CHAR ; + i : INTEGER ; +BEGIN + ch := i +END testcharint. diff --git a/gcc/testsuite/gm2/pim/fail/testindrx.mod b/gcc/testsuite/gm2/pim/fail/testindrx.mod new file mode 100644 index 0000000..2630ebd --- /dev/null +++ b/gcc/testsuite/gm2/pim/fail/testindrx.mod @@ -0,0 +1,8 @@ +MODULE testindrx ; (*!m2iso+gm2*) + +VAR + x: ARRAY [1..5] OF INTEGER ; + ch: CHAR ; +BEGIN + ch := x[1] +END testindrx. diff --git a/gcc/testsuite/gm2/pim/pass/ReturnType.mod b/gcc/testsuite/gm2/pim/pass/ReturnType.mod new file mode 100644 index 0000000..149bc85 --- /dev/null +++ b/gcc/testsuite/gm2/pim/pass/ReturnType.mod @@ -0,0 +1,17 @@ +MODULE ReturnType ; + +TYPE + bar = POINTER TO CARDINAL ; + + +PROCEDURE foo (VAR value: bar) : bar ; +BEGIN + RETURN value +END foo ; + +VAR + b: bar ; +BEGIN + b := NIL ; + b := foo (b) +END ReturnType. diff --git a/gcc/testsuite/gm2/pim/pass/ReturnType2.mod b/gcc/testsuite/gm2/pim/pass/ReturnType2.mod new file mode 100644 index 0000000..bab7f5b --- /dev/null +++ b/gcc/testsuite/gm2/pim/pass/ReturnType2.mod @@ -0,0 +1,19 @@ +MODULE ReturnType2 ; + +TYPE + bar = POINTER TO RECORD + field: CARDINAL ; + END ; + + +PROCEDURE foo (VAR value: bar) : bar ; +BEGIN + RETURN value +END foo ; + +VAR + b: bar ; +BEGIN + b := NIL ; + b := foo (b) +END ReturnType2. diff --git a/gcc/testsuite/gm2/pim/pass/testxindr.mod b/gcc/testsuite/gm2/pim/pass/testxindr.mod new file mode 100644 index 0000000..271f430 --- /dev/null +++ b/gcc/testsuite/gm2/pim/pass/testxindr.mod @@ -0,0 +1,17 @@ +MODULE testxindr ; (*!m2iso+gm2*) + +CONST + NulName = 0 ; + +TYPE + Name = CARDINAL ; + + ptr = POINTER TO RECORD + n: Name ; + END ; + +VAR + p: ptr ; +BEGIN + p^.n := NulName +END testxindr. diff --git a/gcc/testsuite/gm2/pim/pass/testxindr2.mod b/gcc/testsuite/gm2/pim/pass/testxindr2.mod new file mode 100644 index 0000000..b0776dc --- /dev/null +++ b/gcc/testsuite/gm2/pim/pass/testxindr2.mod @@ -0,0 +1,17 @@ +MODULE testxindr2 ; (*!m2iso+gm2*) + +CONST + NulName = 0 ; +TYPE + Name = CARDINAL ; + +PROCEDURE set (VAR n: Name) ; +BEGIN + n := NulName +END set ; + +VAR + n: Name ; +BEGIN + set (n) +END testxindr2. diff --git a/gcc/testsuite/gm2/pim/pass/testxindr3.mod b/gcc/testsuite/gm2/pim/pass/testxindr3.mod new file mode 100644 index 0000000..5625c3e --- /dev/null +++ b/gcc/testsuite/gm2/pim/pass/testxindr3.mod @@ -0,0 +1,15 @@ +MODULE testxindr3 ; (*!m2iso+gm2*) + +CONST + NulName = 0 ; + +PROCEDURE set (VAR n: CARDINAL) ; +BEGIN + n := NulName +END set ; + +VAR + n: CARDINAL ; +BEGIN + set (n) +END testxindr3. diff --git a/gcc/testsuite/gnat.dg/controlled9.adb b/gcc/testsuite/gnat.dg/controlled9.adb new file mode 100644 index 0000000..fb7acce --- /dev/null +++ b/gcc/testsuite/gnat.dg/controlled9.adb @@ -0,0 +1,10 @@ +-- { dg-do run } +-- { dg-options "-O1 -fstack-check" } +-- from PR middle-end/118939 + +with Controlled9_Pkg; +procedure Controlled9 is + S : constant Controlled9_Pkg.T_Access := new Controlled9_Pkg.T; +begin + null; +end Controlled9; diff --git a/gcc/testsuite/gnat.dg/controlled9_pkg.ads b/gcc/testsuite/gnat.dg/controlled9_pkg.ads new file mode 100644 index 0000000..d0e7c28 --- /dev/null +++ b/gcc/testsuite/gnat.dg/controlled9_pkg.ads @@ -0,0 +1,5 @@ +with Ada.Finalization; +package Controlled9_Pkg is + type T is new Ada.Finalization.Controlled with null record; + type T_Access is access all T; +end Controlled9_Pkg; diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp index 75d723c..dfffe3a 100644 --- a/gcc/testsuite/lib/target-supports.exp +++ b/gcc/testsuite/lib/target-supports.exp @@ -1098,6 +1098,16 @@ proc check_effective_target_tls {} { }] } +# Return 1 if we can link using TLS, 0 otherwise. + +proc check_effective_target_tls_link {} { + return [check_no_compiler_messages tls_link executable { + __thread int i; + int main (void) { return i; } + void g (int j) { i = j; } + }] +} + # Return 1 if *native* thread local storage (TLS) is supported, 0 otherwise. proc check_effective_target_tls_native {} { diff --git a/gcc/tree-inline.cc b/gcc/tree-inline.cc index 3289b4f..1a72e31 100644 --- a/gcc/tree-inline.cc +++ b/gcc/tree-inline.cc @@ -2866,7 +2866,6 @@ initialize_cfun (tree new_fndecl, tree callee_fndecl, profile_count count) cfun->nonlocal_goto_save_area = src_cfun->nonlocal_goto_save_area; cfun->function_end_locus = src_cfun->function_end_locus; cfun->curr_properties = src_cfun->curr_properties; - cfun->last_verified = src_cfun->last_verified; cfun->va_list_gpr_size = src_cfun->va_list_gpr_size; cfun->va_list_fpr_size = src_cfun->va_list_fpr_size; cfun->has_nonlocal_label = src_cfun->has_nonlocal_label; diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h index 7cb5a12..4139f6d 100644 --- a/gcc/tree-pass.h +++ b/gcc/tree-pass.h @@ -236,9 +236,9 @@ protected: (PROP_gimple_any | PROP_gimple_lcf | PROP_gimple_leh | PROP_gimple_lomp) /* To-do flags. */ +/* Note (1ul << 31) is reserved for TODO_verify_il. */ #define TODO_do_not_ggc_collect (1 << 1) #define TODO_cleanup_cfg (1 << 5) -#define TODO_verify_il (1 << 6) #define TODO_dump_symtab (1 << 7) #define TODO_remove_functions (1 << 8) @@ -308,6 +308,8 @@ protected: and stop pass manager. */ #define TODO_discard_function (1 << 23) +/* (1ul << 31) is reserved for TODO_verify_il. */ + /* Internally used in execute_function_todo(). */ #define TODO_update_ssa_any \ (TODO_update_ssa \ @@ -315,8 +317,6 @@ protected: | TODO_update_ssa_full_phi \ | TODO_update_ssa_only_virtuals) -#define TODO_verify_all TODO_verify_il - /* To-do flags for pending_TODOs. */ /* Tell the next scalar cleanup pass that there is diff --git a/gcc/tree-ssa-forwprop.cc b/gcc/tree-ssa-forwprop.cc index 81ea7d4..75901ec 100644 --- a/gcc/tree-ssa-forwprop.cc +++ b/gcc/tree-ssa-forwprop.cc @@ -205,7 +205,6 @@ struct _vec_perm_simplify_seq typedef struct _vec_perm_simplify_seq *vec_perm_simplify_seq; static bool forward_propagate_addr_expr (tree, tree, bool); -static void optimize_vector_load (gimple_stmt_iterator *); /* Set to true if we delete dead edges during the optimization. */ static bool cfg_changed; @@ -3387,6 +3386,7 @@ optimize_vector_load (gimple_stmt_iterator *gsi) gimple *stmt = gsi_stmt (*gsi); tree lhs = gimple_assign_lhs (stmt); tree rhs = gimple_assign_rhs1 (stmt); + tree vuse = gimple_vuse (stmt); /* Gather BIT_FIELD_REFs to rewrite, looking through VEC_UNPACK_{LO,HI}_EXPR. */ @@ -3495,6 +3495,7 @@ optimize_vector_load (gimple_stmt_iterator *gsi) gimple *new_stmt = gimple_build_assign (tem, new_rhs); location_t loc = gimple_location (use_stmt); gimple_set_location (new_stmt, loc); + gimple_set_vuse (new_stmt, vuse); gsi_insert_before (gsi, new_stmt, GSI_SAME_STMT); /* Perform scalar promotion. */ new_stmt = gimple_build_assign (gimple_assign_lhs (use_stmt), @@ -3514,6 +3515,7 @@ optimize_vector_load (gimple_stmt_iterator *gsi) new_rhs); location_t loc = gimple_location (use_stmt); gimple_set_location (new_stmt, loc); + gimple_set_vuse (new_stmt, vuse); gsi_insert_before (gsi, new_stmt, GSI_SAME_STMT); } gimple_stmt_iterator gsi2 = gsi_for_stmt (use_stmt); @@ -4167,7 +4169,7 @@ const pass_data pass_data_forwprop = 0, /* properties_provided */ 0, /* properties_destroyed */ 0, /* todo_flags_start */ - TODO_update_ssa, /* todo_flags_finish */ + 0, /* todo_flags_finish */ }; class pass_forwprop : public gimple_opt_pass @@ -4404,6 +4406,7 @@ pass_forwprop::execute (function *fun) component-wise loads. */ use_operand_p use_p; imm_use_iterator iter; + tree vuse = gimple_vuse (stmt); bool rewrite = true; FOR_EACH_IMM_USE_FAST (use_p, iter, lhs) { @@ -4443,6 +4446,7 @@ pass_forwprop::execute (function *fun) location_t loc = gimple_location (use_stmt); gimple_set_location (new_stmt, loc); + gimple_set_vuse (new_stmt, vuse); gimple_stmt_iterator gsi2 = gsi_for_stmt (use_stmt); unlink_stmt_vdef (use_stmt); gsi_remove (&gsi2, true); diff --git a/gcc/tree-switch-conversion.cc b/gcc/tree-switch-conversion.cc index bd4de96..d088287 100644 --- a/gcc/tree-switch-conversion.cc +++ b/gcc/tree-switch-conversion.cc @@ -1030,6 +1030,9 @@ switch_conversion::build_one_array (int num, tree arr_index_type, TREE_CONSTANT (decl) = 1; TREE_READONLY (decl) = 1; DECL_IGNORED_P (decl) = 1; + /* The decl is mergable since we don't take the address ever and + just reading from it. */ + DECL_MERGEABLE (decl) = 1; if (offloading_function_p (cfun->decl)) DECL_ATTRIBUTES (decl) = tree_cons (get_identifier ("omp declare target"), NULL_TREE, diff --git a/gcc/tree-vect-data-refs.cc b/gcc/tree-vect-data-refs.cc index f2deb75..1792ee4 100644 --- a/gcc/tree-vect-data-refs.cc +++ b/gcc/tree-vect-data-refs.cc @@ -3685,7 +3685,7 @@ vect_analyze_data_ref_accesses (vec_info *vinfo, /* For datarefs with big gap, it's better to split them into different groups. .i.e a[0], a[1], a[2], .. a[7], a[100], a[101],..., a[107] */ - if ((unsigned HOST_WIDE_INT)(init_b - init_prev) * tree_to_uhwi (szb) + if ((unsigned HOST_WIDE_INT)(init_b - init_prev) > MAX_BITSIZE_MODE_ANY_MODE / BITS_PER_UNIT) break; diff --git a/gcc/tree-vect-loop.cc b/gcc/tree-vect-loop.cc index 2d1a688..8c5761d 100644 --- a/gcc/tree-vect-loop.cc +++ b/gcc/tree-vect-loop.cc @@ -6016,7 +6016,8 @@ vect_create_epilog_for_reduction (loop_vec_info loop_vinfo, /* Create an induction variable. */ gimple_stmt_iterator incr_gsi; bool insert_after; - vect_iv_increment_position (loop_exit, &incr_gsi, &insert_after); + vect_iv_increment_position (LOOP_VINFO_IV_EXIT (loop_vinfo), + &incr_gsi, &insert_after); create_iv (series_vect, PLUS_EXPR, vec_step, NULL_TREE, loop, &incr_gsi, insert_after, &indx_before_incr, &indx_after_incr); diff --git a/gcc/tree-vrp.cc b/gcc/tree-vrp.cc index 5aeb1e0..cad1a24 100644 --- a/gcc/tree-vrp.cc +++ b/gcc/tree-vrp.cc @@ -1297,7 +1297,7 @@ const pass_data pass_data_early_vrp = 0, /* properties_provided */ 0, /* properties_destroyed */ 0, /* todo_flags_start */ - ( TODO_cleanup_cfg | TODO_update_ssa | TODO_verify_all ), + ( TODO_cleanup_cfg | TODO_update_ssa ), }; const pass_data pass_data_fast_vrp = @@ -1310,7 +1310,7 @@ const pass_data pass_data_fast_vrp = 0, /* properties_provided */ 0, /* properties_destroyed */ 0, /* todo_flags_start */ - ( TODO_cleanup_cfg | TODO_update_ssa | TODO_verify_all ), + ( TODO_cleanup_cfg | TODO_update_ssa ), }; diff --git a/include/ChangeLog b/include/ChangeLog index 5110716..886dab6 100644 --- a/include/ChangeLog +++ b/include/ChangeLog @@ -1,3 +1,8 @@ +2025-06-02 Tobias Burnus <tburnus@baylibre.com> + + PR libgomp/120444 + * cuda/cuda.h (cuMemsetD8, cuMemsetD8Async): Declare. + 2025-05-30 Julian Brown <julian@codesourcery.com> Tobias Burnus <tburnus@baylibre.com> diff --git a/include/cuda/cuda.h b/include/cuda/cuda.h index 5e4b7f1..6be1ac0 100644 --- a/include/cuda/cuda.h +++ b/include/cuda/cuda.h @@ -279,6 +279,9 @@ CUresult cuMemcpy3D (const CUDA_MEMCPY3D *); CUresult cuMemcpy3DAsync (const CUDA_MEMCPY3D *, CUstream); CUresult cuMemcpy3DPeer (const CUDA_MEMCPY3D_PEER *); CUresult cuMemcpy3DPeerAsync (const CUDA_MEMCPY3D_PEER *, CUstream); +#define cuMemsetD8 cuMemsetD8_v2 +CUresult cuMemsetD8 (CUdeviceptr, unsigned char, size_t); +CUresult cuMemsetD8Async (CUdeviceptr, unsigned char, size_t, CUstream); #define cuMemFree cuMemFree_v2 CUresult cuMemFree (CUdeviceptr); CUresult cuMemFreeHost (void *); diff --git a/libgcobol/ChangeLog b/libgcobol/ChangeLog index 83a826e..4293598 100644 --- a/libgcobol/ChangeLog +++ b/libgcobol/ChangeLog @@ -1,3 +1,8 @@ +2025-06-01 Robert Dubner <rdubner@symas.com> + + PR cobol/119524 + * libgcobol.cc (__gg__fprintf_stderr): New function. + 2025-05-20 Robert Dubner <rdubner@symas.com> James K. Lowden <jklowden@cobolworx.com> diff --git a/libgcobol/libgcobol.cc b/libgcobol/libgcobol.cc index 66405ba..3ab7463 100644 --- a/libgcobol/libgcobol.cc +++ b/libgcobol/libgcobol.cc @@ -49,6 +49,7 @@ #include <signal.h> #include <syslog.h> #include <unistd.h> +#include <stdarg.h> #if __has_include(<errno.h>) # include <errno.h> // for program_invocation_short_name #endif @@ -13151,3 +13152,16 @@ __gg__set_env_value(cblc_field_t *value, // And now, anticlimactically, set the variable: setenv(trimmed_env, trimmed_val, 1); } + +extern "C" +void +__gg__fprintf_stderr(const char *format_string, ...) + { + /* This routine allows the compiler to send stuff to stderr in a way + that is straightforward to use.. */ + va_list ap; + va_start(ap, format_string); + vfprintf(stderr, format_string, ap); + va_end(ap); + } + diff --git a/libgfortran/ChangeLog b/libgfortran/ChangeLog index 638c03e..1f658d5 100644 --- a/libgfortran/ChangeLog +++ b/libgfortran/ChangeLog @@ -1,3 +1,11 @@ +2025-06-01 Jerry DeLisle <jvdelisle@gcc.gnu.org> + + PR libfortran/119856 + * io/format.c (parse_format_list): Set the fmt->error + message for missing comma. + (parse_format): Do not cache the parsed format string + if a previous error ocurred. + 2025-05-13 Jakub Jelinek <jakub@redhat.com> PR libfortran/120196 diff --git a/libgfortran/io/format.c b/libgfortran/io/format.c index eef1d34..87e21a9 100644 --- a/libgfortran/io/format.c +++ b/libgfortran/io/format.c @@ -1235,9 +1235,9 @@ parse_format_list (st_parameter_dt *dtp, bool *seen_dd) default: /* Assume a missing comma with -std=legacy, GNU extension. */ - if (compile_options.warn_std == 0) - goto format_item_1; - format_error (dtp, tail, comma_missing); + if (compile_options.warn_std != 0) + fmt->error = comma_missing; + goto format_item_1; } /* Optional comma is a weird between state where we've just finished @@ -1252,7 +1252,7 @@ parse_format_list (st_parameter_dt *dtp, bool *seen_dd) case FMT_RPAREN: goto finished; - default: /* Assume that we have another format item */ + default: /* Assume that we have another format item */ fmt->saved_token = t; break; } @@ -1419,7 +1419,7 @@ parse_format (st_parameter_dt *dtp) else fmt->error = "Missing initial left parenthesis in format"; - if (format_cache_ok) + if (format_cache_ok && !fmt->error) save_parsed_format (dtp); else dtp->u.p.format_not_saved = 1; diff --git a/libgomp/ChangeLog b/libgomp/ChangeLog index 78bbf26..2c044a7 100644 --- a/libgomp/ChangeLog +++ b/libgomp/ChangeLog @@ -1,3 +1,29 @@ +2025-06-02 Tobias Burnus <tburnus@baylibre.com> + + PR libgomp/120444 + * libgomp-plugin.h (GOMP_OFFLOAD_memset): Declare. + * libgomp.h (struct gomp_device_descr): Add memset_func. + * libgomp.map (GOMP_6.0.1): Add omp_target_memset{,_async}. + * libgomp.texi (Device Memory Routines): Document them. + * omp.h.in (omp_target_memset, omp_target_memset_async): Declare. + * omp_lib.f90.in (omp_target_memset, omp_target_memset_async): + Add interfaces. + * omp_lib.h.in (omp_target_memset, omp_target_memset_async): Likewise. + * plugin/cuda-lib.def: Add cuMemsetD8. + * plugin/plugin-gcn.c (struct hsa_runtime_fn_info): Add + hsa_amd_memory_fill_fn. + (init_hsa_runtime_functions): DLSYM_OPT_FN load it. + (GOMP_OFFLOAD_memset): New. + * plugin/plugin-nvptx.c (GOMP_OFFLOAD_memset): New. + * target.c (omp_target_memset_int, omp_target_memset, + omp_target_memset_async_helper, omp_target_memset_async): New. + (gomp_load_plugin_for_device): Add DLSYM (memset). + * testsuite/libgomp.c-c++-common/omp_target_memset.c: New test. + * testsuite/libgomp.c-c++-common/omp_target_memset-2.c: New test. + * testsuite/libgomp.c-c++-common/omp_target_memset-3.c: New test. + * testsuite/libgomp.fortran/omp_target_memset.f90: New test. + * testsuite/libgomp.fortran/omp_target_memset-2.f90: New test. + 2025-05-30 Thomas Schwinge <tschwinge@baylibre.com> * testsuite/libgomp.c++/target-std__valarray-1.C: New. diff --git a/libgomp/libgomp-plugin.h b/libgomp/libgomp-plugin.h index 50c89fe..191106b 100644 --- a/libgomp/libgomp-plugin.h +++ b/libgomp/libgomp-plugin.h @@ -177,6 +177,7 @@ extern int GOMP_OFFLOAD_memcpy3d (int, int, size_t, size_t, size_t, void *, size_t, size_t, size_t, size_t, size_t, const void *, size_t, size_t, size_t, size_t, size_t); +extern bool GOMP_OFFLOAD_memset (int, void *, int, size_t); extern bool GOMP_OFFLOAD_can_run (void *); extern void GOMP_OFFLOAD_run (int, void *, void *, void **); extern void GOMP_OFFLOAD_async_run (int, void *, void *, void **, void *); diff --git a/libgomp/libgomp.h b/libgomp/libgomp.h index ed4e23a..a433983 100644 --- a/libgomp/libgomp.h +++ b/libgomp/libgomp.h @@ -1421,9 +1421,10 @@ struct gomp_device_descr __typeof (GOMP_OFFLOAD_free) *free_func; __typeof (GOMP_OFFLOAD_dev2host) *dev2host_func; __typeof (GOMP_OFFLOAD_host2dev) *host2dev_func; + __typeof (GOMP_OFFLOAD_dev2dev) *dev2dev_func; __typeof (GOMP_OFFLOAD_memcpy2d) *memcpy2d_func; __typeof (GOMP_OFFLOAD_memcpy3d) *memcpy3d_func; - __typeof (GOMP_OFFLOAD_dev2dev) *dev2dev_func; + __typeof (GOMP_OFFLOAD_memset) *memset_func; __typeof (GOMP_OFFLOAD_can_run) *can_run_func; __typeof (GOMP_OFFLOAD_run) *run_func; __typeof (GOMP_OFFLOAD_async_run) *async_run_func; diff --git a/libgomp/libgomp.map b/libgomp/libgomp.map index ad9787c..f6aee7c 100644 --- a/libgomp/libgomp.map +++ b/libgomp/libgomp.map @@ -453,6 +453,12 @@ GOMP_6.0 { omp_get_uid_from_device_8_; } GOMP_5.1.3; +GOMP_6.0.1 { + global: + omp_target_memset; + omp_target_memset_async; +} GOMP_6.0; + OACC_2.0 { global: acc_get_num_devices; diff --git a/libgomp/libgomp.texi b/libgomp/libgomp.texi index e6ebe22..8e487bc 100644 --- a/libgomp/libgomp.texi +++ b/libgomp/libgomp.texi @@ -603,7 +603,7 @@ to address of matching mapped list item per 5.1, Sect. 2.21.7.2 @tab N @tab @code{omp_get_device_teams_thread_limit}, and @code{omp_set_device_teams_thread_limit} routines @tab N @tab @item @code{omp_target_memset} and @code{omp_target_memset_async} routines - @tab N @tab + @tab Y @tab @item Fortran version of the interop runtime routines @tab Y @tab @item Routines for obtaining memory spaces/allocators for shared/device memory @tab N @tab @@ -1984,8 +1984,8 @@ pointers on devices. They have C linkage and do not throw exceptions. * omp_target_memcpy_async:: Copy data between devices asynchronously * omp_target_memcpy_rect:: Copy a subvolume of data between devices * omp_target_memcpy_rect_async:: Copy a subvolume of data between devices asynchronously -@c * omp_target_memset:: <fixme>/TR12 -@c * omp_target_memset_async:: <fixme>/TR12 +* omp_target_memset:: Set bytes in device memory +* omp_target_memset_async:: Set bytes in device memory asynchronously * omp_target_associate_ptr:: Associate a device pointer with a host pointer * omp_target_disassociate_ptr:: Remove device--host pointer association * omp_get_mapped_ptr:: Return device pointer to a host pointer @@ -2398,6 +2398,98 @@ the initial device. @end table +@node omp_target_memset +@subsection @code{omp_target_memset} -- Set bytes in device memory +@table @asis +@item @emph{Description}: +This routine fills memory on the device identified by device number +@var{device_num}. Starting from the device address @var{ptr}, the first +@var{count} bytes are set to the value @var{val}, converted to +@code{unsigned char}. If @var{count} is zero, the routine has no effect; +if @var{ptr} is @code{NULL}, the behavior is unspecified. The function +returns @var{ptr}. + +The @var{device_num} must be a conforming device number and @var{ptr} must be +a valid device pointer for that device. Running this routine in a +@code{target} region except on the initial device is not supported. + +@item @emph{C/C++} +@multitable @columnfractions .20 .80 +@item @emph{Prototype}: @tab @code{void *omp_target_memcpy(void *ptr,} +@item @tab @code{ int val,} +@item @tab @code{ size_t count,} +@item @tab @code{ int device_num)} +@end multitable + +@item @emph{Fortran}: +@multitable @columnfractions .20 .80 +@item @emph{Interface}: @tab @code{type(c_ptr) function omp_target_memset( &} +@item @tab @code{ ptr, val, count, device_num) bind(C)} +@item @tab @code{use, intrinsic :: iso_c_binding, only: c_ptr, c_size_t, c_int} +@item @tab @code{type(c_ptr), value :: ptr} +@item @tab @code{integer(c_size_t), value :: count} +@item @tab @code{integer(c_int), value :: val, device_num} +@end multitable + +@item @emph{See also}: +@ref{omp_target_memset_async} + +@item @emph{Reference}: +@uref{https://www.openmp.org, OpenMP specification v6.0}, Section 25.8.1 +@end table + + + +@node omp_target_memset_async +@subsection @code{omp_target_memset} -- Set bytes in device memory asynchronously +@table @asis +@item @emph{Description}: +This routine fills memory on the device identified by device number +@var{device_num}. Starting from the device address @var{ptr}, the first +@var{count} bytes are set to the value @var{val}, converted to +@code{unsigned char}. If @var{count} is zero, the routine has no effect; +if @var{ptr} is @code{NULL}, the behavior is unspecified. Task dependence +is expressed by passing an array of depend objects to @var{depobj_list}, where +the number of array elements is passed as @var{depobj_count}; if the count is +zero, the @var{depobj_list} argument is ignored. In C++ and Fortran, the +@var{depobj_list} argument can also be omitted in that case. The function +returns @var{ptr}. + +The @var{device_num} must be a conforming device number and @var{ptr} must be +a valid device pointer for that device. Running this routine in a +@code{target} region except on the initial device is not supported. + +@item @emph{C/C++} +@multitable @columnfractions .20 .80 +@item @emph{Prototype}: @tab @code{void *omp_target_memcpy_async(void *ptr,} +@item @tab @code{ int val,} +@item @tab @code{ size_t count,} +@item @tab @code{ int device_num,} +@item @tab @code{ int depobj_count,} +@item @tab @code{ omp_depend_t *depobj_list)} +@end multitable + +@item @emph{Fortran}: +@multitable @columnfractions .20 .80 +@item @emph{Interface}: @tab @code{type(c_ptr) function omp_target_memset_async( &} +@item @tab @code{ ptr, val, count, device_num, &} +@item @tab @code{ depobj_count, depobj_list) bind(C)} +@item @tab @code{use, intrinsic :: iso_c_binding, only: c_ptr, c_size_t, c_int} +@item @tab @code{type(c_ptr), value :: ptr} +@item @tab @code{integer(c_size_t), value :: count} +@item @tab @code{integer(c_int), value :: val, device_num, depobj_count} +@item @tab @code{integer(omp_depend_kind), optional :: depobj_list(*)} +@end multitable + + +@item @emph{See also}: +@ref{omp_target_memset} + +@item @emph{Reference}: +@uref{https://www.openmp.org, OpenMP specification v6.0}, Section 25.8.2 +@end table + + @node omp_target_associate_ptr @subsection @code{omp_target_associate_ptr} -- Associate a device pointer with a host pointer diff --git a/libgomp/omp.h.in b/libgomp/omp.h.in index 8d17db1..4f2bc46 100644 --- a/libgomp/omp.h.in +++ b/libgomp/omp.h.in @@ -347,6 +347,10 @@ extern int omp_target_memcpy_rect_async (void *, const void *, __SIZE_TYPE__, const __SIZE_TYPE__ *, int, int, int, omp_depend_t * __GOMP_DEFAULT_NULL) __GOMP_NOTHROW; +extern void *omp_target_memset (void *, int, __SIZE_TYPE__, int) __GOMP_NOTHROW; +extern void *omp_target_memset_async (void *, int, __SIZE_TYPE__, int, + int, omp_depend_t * __GOMP_DEFAULT_NULL) + __GOMP_NOTHROW; extern int omp_target_associate_ptr (const void *, const void *, __SIZE_TYPE__, __SIZE_TYPE__, int) __GOMP_NOTHROW; extern int omp_target_disassociate_ptr (const void *, int) __GOMP_NOTHROW; diff --git a/libgomp/omp_lib.f90.in b/libgomp/omp_lib.f90.in index cb6b95f..ce866c0 100644 --- a/libgomp/omp_lib.f90.in +++ b/libgomp/omp_lib.f90.in @@ -904,6 +904,29 @@ end interface interface + function omp_target_memset (ptr, val, count, device_num) bind(c) + use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_size_t + type(c_ptr) :: omp_target_memset + type(c_ptr), value :: ptr + integer(c_size_t), value :: count + integer(c_int), value :: val, device_num + end function omp_target_memset + end interface + + interface + function omp_target_memset_async (ptr, val, count, device_num, & + depobj_count, depobj_list) bind(c) + use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_size_t + import :: omp_depend_kind + type(c_ptr) :: omp_target_memset_async + type(c_ptr), value :: ptr + integer(c_size_t), value :: count + integer(c_int), value :: val, device_num, depobj_count + integer(omp_depend_kind), optional :: depobj_list(*) + end function omp_target_memset_async + end interface + + interface function omp_target_associate_ptr (host_ptr, device_ptr, size, & device_offset, device_num) bind(c) use, intrinsic :: iso_c_binding, only : c_ptr, c_size_t, c_int diff --git a/libgomp/omp_lib.h.in b/libgomp/omp_lib.h.in index f7af5ff..9047095 100644 --- a/libgomp/omp_lib.h.in +++ b/libgomp/omp_lib.h.in @@ -505,6 +505,31 @@ end interface interface + function omp_target_memset (ptr, val, count, device_num) bind(c) + use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_size_t + type(c_ptr) omp_target_memset + type(c_ptr), value :: ptr + integer(c_size_t), value :: count + integer(c_int), value :: val, device_num + end function omp_target_memset + end interface + + interface + function omp_target_memset_async (ptr, val, count, device_num, & + & depobj_count, depobj_list) & + & bind(c) + use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_size_t + import :: omp_depend_kind + type(c_ptr) :: omp_target_memset_async + type(c_ptr), value :: ptr + integer(c_size_t), value :: count + integer(c_int), value :: val, device_num, depobj_count + integer(omp_depend_kind), optional :: depobj_list(*) + end function omp_target_memset_async + end interface + + + interface function omp_target_associate_ptr (host_ptr, device_ptr, size, & & device_offset, device_num) & & bind(c) diff --git a/libgomp/plugin/cuda-lib.def b/libgomp/plugin/cuda-lib.def index eb562ac..7f4ddcc 100644 --- a/libgomp/plugin/cuda-lib.def +++ b/libgomp/plugin/cuda-lib.def @@ -42,6 +42,7 @@ CUDA_ONE_CALL (cuMemcpyHtoDAsync) CUDA_ONE_CALL (cuMemcpy2D) CUDA_ONE_CALL (cuMemcpy2DUnaligned) CUDA_ONE_CALL (cuMemcpy3D) +CUDA_ONE_CALL (cuMemsetD8) CUDA_ONE_CALL (cuMemFree) CUDA_ONE_CALL (cuMemFreeHost) CUDA_ONE_CALL (cuMemGetAddressRange) diff --git a/libgomp/plugin/plugin-gcn.c b/libgomp/plugin/plugin-gcn.c index 46203838..498b549 100644 --- a/libgomp/plugin/plugin-gcn.c +++ b/libgomp/plugin/plugin-gcn.c @@ -208,6 +208,8 @@ struct hsa_runtime_fn_info hsa_status_t (*hsa_code_object_deserialize_fn) (void *serialized_code_object, size_t serialized_code_object_size, const char *options, hsa_code_object_t *code_object); + hsa_status_t (*hsa_amd_memory_fill_fn)(void *ptr, uint32_t value, + size_t count); hsa_status_t (*hsa_amd_memory_lock_fn) (void *host_ptr, size_t size, hsa_agent_t *agents, int num_agent, void **agent_ptr); @@ -1456,6 +1458,7 @@ init_hsa_runtime_functions (void) DLSYM_FN (hsa_signal_load_acquire) DLSYM_FN (hsa_queue_destroy) DLSYM_FN (hsa_code_object_deserialize) + DLSYM_OPT_FN (hsa_amd_memory_fill) DLSYM_OPT_FN (hsa_amd_memory_lock) DLSYM_OPT_FN (hsa_amd_memory_unlock) DLSYM_OPT_FN (hsa_amd_memory_async_copy_rect) @@ -4435,6 +4438,83 @@ init_hip_runtime_functions (void) return true; } +bool +GOMP_OFFLOAD_memset (int ord, void *ptr, int val, size_t count) +{ + hsa_status_t status = HSA_STATUS_SUCCESS; + + /* A memset feature is only provided via hsa_amd_memory_fill; while it + is fast, it is an HSA extension and it has two requirements: The memory + must be aligned to multiples of 4 bytes - and, by construction, only + multiples of 4 bytes can be filled (uint32_t value argument). + + This means: Either not using that function or up to three function calls: + - copy 1 to 3 bytes to get alignment (hsa_memory_copy), if unaligned + - call hsa_amd_memory_fill + - copy remaining 1 to 3 bytes (hsa_memory_copy), if after alignment + count is not a multiple of 4 bytes. + + Having more than one function call is only profitable if there is + enough data to process; see below for the used heuristic values. */ + + uint8_t v8 = (uint8_t) val; + size_t before = (4 - (uintptr_t) ptr % 4) % 4; /* 0 to 3 bytes. */ + size_t tail = (count - before) % 4; /* 0 to 3 bytes. */ + + /* Heuristic */ + enum { + /* Prefer alloca to malloc up to ... */ + alloca_size = 256, /* bytes */ + /* Call hsa_amd_memory_fill also when two copy calls are required. */ + always_use_fill = 256*1024, /* bytes */ + /* Call hsa_amd_memory_fill also when on copy call is required. */ + use_fill_one_copy = (128+64)*1024 /* bytes */ + }; + + /* Do not call hsa_amd_memory_fill when any of the following conditions + is true. Note that it is always preferred if available and + before == tail == 0. */ + if (__builtin_expect (!hsa_fns.hsa_amd_memory_fill_fn, 0) + || (before && tail && count < always_use_fill) + || ((before || tail) && count < use_fill_one_copy)) + before = count; + + /* Copy call for alignment - or all data, if condition above is true. */ + if (before) + { + void *data; + if (before > alloca_size) + data = malloc (before * sizeof (uint8_t)); + else + data = alloca (before * sizeof (uint8_t)); + memset (data, val, before); + status = hsa_fns.hsa_memory_copy_fn (ptr, data, before); + if (before > alloca_size) + free (data); + if (data == 0 || status != HSA_STATUS_SUCCESS) + goto fail; + count -= before; + } + + if (count == 0) + return true; + + ptr += before; + + uint32_t values = v8 | (v8 << 8) | (v8 << 16) | (v8 << 24); + status = hsa_fns.hsa_amd_memory_fill_fn (ptr, values, count / 4); + if (tail && status == HSA_STATUS_SUCCESS) + { + ptr += count - tail; + status = hsa_fns.hsa_memory_copy_fn (ptr, &values, tail); + } + if (status == HSA_STATUS_SUCCESS) + return true; + +fail: + GOMP_PLUGIN_error ("memory set failed"); + return false; +} void GOMP_OFFLOAD_interop (struct interop_obj_t *obj, int ord, diff --git a/libgomp/plugin/plugin-nvptx.c b/libgomp/plugin/plugin-nvptx.c index a52d1ad..0ba445e 100644 --- a/libgomp/plugin/plugin-nvptx.c +++ b/libgomp/plugin/plugin-nvptx.c @@ -2298,6 +2298,15 @@ GOMP_OFFLOAD_memcpy3d (int dst_ord, int src_ord, size_t dim2_size, } bool +GOMP_OFFLOAD_memset (int ord, void *ptr, int val, size_t count) +{ + if (!nvptx_attach_host_thread_to_device (ord)) + return false; + CUDA_CALL (cuMemsetD8, (CUdeviceptr) ptr, (unsigned char) val, count); + return true; +} + +bool GOMP_OFFLOAD_openacc_async_host2dev (int ord, void *dst, const void *src, size_t n, struct goacc_asyncqueue *aq) { diff --git a/libgomp/target.c b/libgomp/target.c index fe94978..a2a4a72 100644 --- a/libgomp/target.c +++ b/libgomp/target.c @@ -5003,6 +5003,88 @@ omp_target_memcpy_rect_async (void *dst, const void *src, size_t element_size, return 0; } +static void +omp_target_memset_int (void *ptr, int val, size_t count, + struct gomp_device_descr *devicep) +{ + if (__builtin_expect (count == 0, 0)) + return; + if (devicep == NULL) + { + memset (ptr, val, count); + return; + } + + gomp_mutex_lock (&devicep->lock); + int ret = devicep->memset_func (devicep->target_id, ptr, val, count); + gomp_mutex_unlock (&devicep->lock); + if (!ret) + gomp_fatal ("omp_target_memset failed"); +} + +void* +omp_target_memset (void *ptr, int val, size_t count, int device_num) +{ + struct gomp_device_descr *devicep; + if (device_num == omp_initial_device + || device_num == gomp_get_num_devices () + || (devicep = resolve_device (device_num, false)) == NULL + || !(devicep->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400) + || devicep->capabilities & GOMP_OFFLOAD_CAP_SHARED_MEM) + devicep = NULL; + + omp_target_memset_int (ptr, val, count, devicep); + return ptr; +} + +typedef struct +{ + void *ptr; + size_t count; + struct gomp_device_descr *devicep; + int val; +} omp_target_memset_data; + +static void +omp_target_memset_async_helper (void *args) +{ + omp_target_memset_data *a = args; + omp_target_memset_int (a->ptr, a->val, a->count, a->devicep); +} + +void* +omp_target_memset_async (void *ptr, int val, size_t count, int device_num, + int depobj_count, omp_depend_t *depobj_list) +{ + void *depend[depobj_count + 5]; + struct gomp_device_descr *devicep; + unsigned flags = 0; + int i; + + if (device_num == omp_initial_device + || device_num == gomp_get_num_devices () + || (devicep = resolve_device (device_num, false)) == NULL + || !(devicep->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400) + || devicep->capabilities & GOMP_OFFLOAD_CAP_SHARED_MEM) + devicep = NULL; + + omp_target_memset_data s = {.ptr = ptr, .val = val, .count = count, + .devicep = devicep}; + if (depobj_count > 0 && depobj_list != NULL) + { + flags |= GOMP_TASK_FLAG_DEPEND; + depend[0] = 0; + depend[1] = (void *) (uintptr_t) depobj_count; + depend[2] = depend[3] = depend[4] = 0; + for (i = 0; i < depobj_count; ++i) + depend[i + 5] = &depobj_list[i]; + } + + GOMP_task (omp_target_memset_async_helper, &s, NULL, sizeof (s), + __alignof__ (s), true, flags, depend, 0, NULL); + return ptr; +} + int omp_target_associate_ptr (const void *host_ptr, const void *device_ptr, size_t size, size_t device_offset, int device_num) @@ -5568,6 +5650,7 @@ gomp_load_plugin_for_device (struct gomp_device_descr *device, DLSYM_OPT (async_run, async_run); DLSYM_OPT (can_run, can_run); DLSYM (dev2dev); + DLSYM (memset); } if (device->capabilities & GOMP_OFFLOAD_CAP_OPENACC_200) { diff --git a/libgomp/testsuite/libgomp.c-c++-common/omp_target_memset-2.c b/libgomp/testsuite/libgomp.c-c++-common/omp_target_memset-2.c new file mode 100644 index 0000000..b36d2f5 --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/omp_target_memset-2.c @@ -0,0 +1,62 @@ +// PR libgomp/120444 +// Async version + +#include <omp.h> + +int main() +{ + #pragma omp parallel for + for (int dev = omp_initial_device; dev <= omp_get_num_devices (); dev++) + { + char *ptr = (char *) omp_target_alloc (sizeof(int) * 1024, dev); + + omp_depend_t dep; + #pragma omp depobj(dep) depend(inout: ptr) + + /* Play also around with the alignment - as hsa_amd_memory_fill operates + on multiples of 4 bytes (uint32_t). */ + + for (int start = 0; start < 32; start++) + for (int tail = 0; tail < 32; tail++) + { + unsigned char val = '0' + start + tail; +#if __cplusplus + void *ptr2 = omp_target_memset_async (ptr + start, val, + 1024 - start - tail, dev, 0); +#else + void *ptr2 = omp_target_memset_async (ptr + start, val, + 1024 - start - tail, dev, 0, nullptr); +#endif + if (ptr + start != ptr2) + __builtin_abort (); + + #pragma omp taskwait + + #pragma omp target device(dev) is_device_ptr(ptr) depend(depobj: dep) nowait + for (int i = start; i < 1024 - start - tail; i++) + { + if (ptr[i] != val) + __builtin_abort (); + ptr[i] += 2; + } + + omp_target_memset_async (ptr + start, val + 3, + 1024 - start - tail, dev, 1, &dep); + + #pragma omp target device(dev) is_device_ptr(ptr) depend(depobj: dep) nowait + for (int i = start; i < 1024 - start - tail; i++) + { + if (ptr[i] != val + 3) + __builtin_abort (); + ptr[i] += 1; + } + + omp_target_memset_async (ptr + start, val - 3, + 1024 - start - tail, dev, 1, &dep); + + #pragma omp taskwait depend (depobj: dep) + } + #pragma omp depobj(dep) destroy + omp_target_free (ptr, dev); + } +} diff --git a/libgomp/testsuite/libgomp.c-c++-common/omp_target_memset-3.c b/libgomp/testsuite/libgomp.c-c++-common/omp_target_memset-3.c new file mode 100644 index 0000000..c0e4fa9 --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/omp_target_memset-3.c @@ -0,0 +1,80 @@ +#include <stddef.h> +#include <stdint.h> +#include <omp.h> + +#define MIN(x,y) ((x) < (y) ? x : y) + +enum { N = 524288 + 8 }; + +static void +init_val (int8_t *ptr, int val, size_t count) +{ + #pragma omp target is_device_ptr(ptr) firstprivate(val, count) + __builtin_memset (ptr, val, count); +} + +static void +check_val (int8_t *ptr, int val, size_t count) +{ + if (count == 0) + return; + #pragma omp target is_device_ptr(ptr) firstprivate(val, count) + for (size_t i = 0; i < count; i++) + if (ptr[i] != val) __builtin_abort (); +} + +static void +test_it (int8_t *ptr, int lshift, size_t count) +{ + if (N < count + lshift) __builtin_abort (); + if (lshift >= 4) __builtin_abort (); + ptr += lshift; + + init_val (ptr, 'z', MIN (count + 32, N - lshift)); + + omp_target_memset (ptr, '1', count, omp_get_default_device()); + + check_val (ptr, '1', count); + check_val (ptr + count, 'z', MIN (32, N - lshift - count)); +} + + +int main() +{ + size_t size; + int8_t *ptr = (int8_t *) omp_target_alloc (N + 3, omp_get_default_device()); + ptr += (4 - (uintptr_t) ptr % 4) % 4; + if ((uintptr_t) ptr % 4 != 0) __builtin_abort (); + + test_it (ptr, 0, 1); + test_it (ptr, 3, 1); + test_it (ptr, 0, 4); + test_it (ptr, 3, 4); + test_it (ptr, 0, 5); + test_it (ptr, 3, 5); + test_it (ptr, 0, 6); + test_it (ptr, 3, 6); + + for (int i = 1; i <= 9; i++) + { + switch (i) + { + case 1: size = 16; break; // = 2^4 bytes + case 2: size = 32; break; // = 2^5 bytes + case 3: size = 64; break; // = 2^7 bytes + case 4: size = 128; break; // = 2^7 bytes + case 5: size = 256; break; // = 2^8 bytes + case 6: size = 512; break; // = 2^9 bytes + case 7: size = 65536; break; // = 2^16 bytes + case 8: size = 262144; break; // = 2^18 bytes + case 9: size = 524288; break; // = 2^20 bytes + default: __builtin_abort (); + } + test_it (ptr, 0, size); + test_it (ptr, 3, size); + test_it (ptr, 0, size + 1); + test_it (ptr, 3, size + 1); + test_it (ptr, 3, size + 2); + } + omp_target_free (ptr, omp_get_default_device()); +} diff --git a/libgomp/testsuite/libgomp.c-c++-common/omp_target_memset.c b/libgomp/testsuite/libgomp.c-c++-common/omp_target_memset.c new file mode 100644 index 0000000..01909f8 --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/omp_target_memset.c @@ -0,0 +1,62 @@ +// PR libgomp/120444 + +#include <omp.h> + +int main() +{ + for (int dev = omp_initial_device; dev < omp_get_num_devices (); dev++) + { + char *ptr = (char *) omp_target_alloc (sizeof(int) * 1024, dev); + + /* Play also around with the alignment - as hsa_amd_memory_fill operates + on multiples of 4 bytes (uint32_t). */ + + for (int start = 0; start < 32; start++) + for (int tail = 0; tail < 32; tail++) + { + unsigned char val = '0' + start + tail; + void *ptr2 = omp_target_memset (ptr + start, val, + 1024 - start - tail, dev); + if (ptr + start != ptr2) + __builtin_abort (); + + #pragma omp target device(dev) is_device_ptr(ptr) + for (int i = start; i < 1024 - start - tail; i++) + if (ptr[i] != val) + __builtin_abort (); + + } + + /* Check 'small' values for correctness. */ + + for (int start = 0; start < 32; start++) + for (int size = 0; size <= 64 + 32; size++) + { + omp_target_memset (ptr, 'a' - 2, 1024, dev); + + unsigned char val = '0' + start + size % 32; + void *ptr2 = omp_target_memset (ptr + start, val, size, dev); + + if (ptr + start != ptr2) + __builtin_abort (); + + if (size == 0) + continue; + + #pragma omp target device(dev) is_device_ptr(ptr) + { + for (int i = 0; i < start; i++) + if (ptr[i] != 'a' - 2) + __builtin_abort (); + for (int i = start; i < start + size; i++) + if (ptr[i] != val) + __builtin_abort (); + for (int i = start + size + 1; i < 1024; i++) + if (ptr[i] != 'a' - 2) + __builtin_abort (); + } + } + + omp_target_free (ptr, dev); + } +} diff --git a/libgomp/testsuite/libgomp.fortran/omp_target_memset-2.f90 b/libgomp/testsuite/libgomp.fortran/omp_target_memset-2.f90 new file mode 100644 index 0000000..2641086 --- /dev/null +++ b/libgomp/testsuite/libgomp.fortran/omp_target_memset-2.f90 @@ -0,0 +1,67 @@ +! PR libgomp/120444 +! Async version + +use omp_lib +use iso_c_binding +implicit none (type, external) +integer(c_int) :: dev + +!$omp parallel do +do dev = omp_initial_device, omp_get_num_devices () +block + integer(c_int) :: i, val, start, tail + type(c_ptr) :: ptr, ptr2, tmpptr + integer(c_int8_t), pointer, contiguous :: fptr(:) + integer(c_intptr_t) :: intptr + integer(c_size_t), parameter :: count = 1024 + integer(omp_depend_kind) :: dep(1) + + ptr = omp_target_alloc (count, dev) + + !$omp depobj(dep(1)) depend(inout: ptr) + + ! Play also around with the alignment - as hsa_amd_memory_fill operates + ! on multiples of 4 bytes (c_int32_t) + + do start = 0, 31 + do tail = 0, 31 + val = iachar('0') + start + tail + + tmpptr = transfer (transfer (ptr, intptr) + start, tmpptr) + ptr2 = omp_target_memset_async (tmpptr, val, count - start - tail, dev, 0) + + if (.not. c_associated (tmpptr, ptr2)) stop 1 + + !$omp taskwait + + !$omp target device(dev) is_device_ptr(ptr) depend(depobj: dep(1)) nowait + do i = 1 + start, int(count, c_int) - start - tail + call c_f_pointer (ptr, fptr, [count]) + if (fptr(i) /= int (val, c_int8_t)) stop 2 + fptr(i) = fptr(i) + 2_c_int8_t + end do + !$omp end target + + ptr2 = omp_target_memset_async (tmpptr, val + 3, & + count - start - tail, dev, 1, dep) + + !$omp target device(dev) is_device_ptr(ptr) depend(depobj: dep(1)) nowait + do i = 1 + start, int(count, c_int) - start - tail + call c_f_pointer (ptr, fptr, [count]) + if (fptr(i) /= int (val + 3, c_int8_t)) stop 3 + fptr(i) = fptr(i) - 1_c_int8_t + end do + !$omp end target + + ptr2 = omp_target_memset_async (tmpptr, val - 3, & + count - start - tail, dev, 1, dep) + + !$omp taskwait depend (depobj: dep(1)) + end do + end do + + !$omp depobj(dep(1)) destroy + call omp_target_free (ptr, dev); +end block +end do +end diff --git a/libgomp/testsuite/libgomp.fortran/omp_target_memset.f90 b/libgomp/testsuite/libgomp.fortran/omp_target_memset.f90 new file mode 100644 index 0000000..1ee184a --- /dev/null +++ b/libgomp/testsuite/libgomp.fortran/omp_target_memset.f90 @@ -0,0 +1,39 @@ +! PR libgomp/120444 + +use omp_lib +use iso_c_binding +implicit none (type, external) + +integer(c_int) :: dev, i, val, start, tail +type(c_ptr) :: ptr, ptr2, tmpptr +integer(c_int8_t), pointer, contiguous :: fptr(:) +integer(c_intptr_t) :: intptr +integer(c_size_t), parameter :: count = 1024 + +do dev = omp_initial_device, omp_get_num_devices () + ptr = omp_target_alloc (count, dev) + + ! Play also around with the alignment - as hsa_amd_memory_fill operates + ! on multiples of 4 bytes (c_int32_t) + + do start = 0, 31 + do tail = 0, 31 + val = iachar('0') + start + tail + + tmpptr = transfer (transfer (ptr, intptr) + start, tmpptr) + ptr2 = omp_target_memset (tmpptr, val, count - start - tail, dev) + + if (.not. c_associated (tmpptr, ptr2)) stop 1 + + !$omp target device(dev) is_device_ptr(ptr) + do i = 1 + start, int(count, c_int) - start - tail + call c_f_pointer (ptr, fptr, [count]) + if (fptr(i) /= int (val, c_int8_t)) stop 2 + end do + !$omp end target + end do + end do + + call omp_target_free (ptr, dev); +end do +end diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 9df2d57..2a8963e 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,65 @@ +2025-06-02 Jonathan Wakely <jwakely@redhat.com> + + * include/bits/basic_string.h (basic_string::size): Remove space + before parameter list. + (basic_string::capacity): Likewise. + * include/bits/stl_deque.h (deque::size): Likewise. + * include/bits/stl_vector.h (vector::size, vector::capacity): + Likewise. + * include/bits/vector.tcc (vector::_M_realloc_insert): Likewise. + (vector::_M_realloc_append): Likewise. + +2025-06-02 Jonathan Wakely <jwakely@redhat.com> + + PR libstdc++/120386 + * include/bits/ranges_algo.h (__unique_copy_fn): Reorder + arguments for third case to match the first two cases. + * include/bits/stl_algo.h (__unique_copy): Replace three + overloads with two, depending only on the iterator category of + the input range. Dispatch to __unique_copy_1 for the + non-forward case. + (__unique_copy_1): New overloads for the case where the input + range uses non-forward iterators. + (unique_copy): Only pass the input range category to + __unique_copy. + * testsuite/25_algorithms/unique_copy/lwg2439.cc: New test. + +2025-06-02 Tomasz Kamiński <tkaminsk@redhat.com> + + * include/bits/funcwrap.h (__polyfunc::__pass_by_rref): Define. + (__polyfunc::__param_t): Update to use __pass_by_rref. + * include/bits/cpyfunc_impl.h:: Assert that are parameters type + are complete. + * include/bits/funcref_impl.h: Likewise. + * include/bits/mofunc_impl.h: Likewise. + * testsuite/20_util/copyable_function/call.cc: New test. + * testsuite/20_util/function_ref/call.cc: New test. + * testsuite/20_util/move_only_function/call.cc: New test. + * testsuite/20_util/copyable_function/conv.cc: New test. + * testsuite/20_util/function_ref/conv.cc: New test. + * testsuite/20_util/move_only_function/conv.cc: New test. + * testsuite/20_util/copyable_function/incomplete_neg.cc: New test. + * testsuite/20_util/function_ref/incomplete_neg.cc: New test. + * testsuite/20_util/move_only_function/incomplete_neg.cc: New test. + +2025-06-02 Jonathan Wakely <jwakely@redhat.com> + Tomasz Kamiński <tkaminsk@redhat.com> + + PR libstdc++/119152 + * include/bits/indirect.h (std::polymorphic, pmr::polymorphic) + [__glibcxx_polymorphic]: Define. + * include/bits/version.def (polymorphic): Define. + * include/bits/version.h: Regenerate. + * include/std/memory: Define __cpp_lib_polymorphic. + * testsuite/std/memory/polymorphic/copy.cc: New test. + * testsuite/std/memory/polymorphic/copy_alloc.cc: New test. + * testsuite/std/memory/polymorphic/ctor.cc: New test. + * testsuite/std/memory/polymorphic/ctor_poly.cc: New test. + * testsuite/std/memory/polymorphic/incomplete.cc: New test. + * testsuite/std/memory/polymorphic/invalid_neg.cc: New test. + * testsuite/std/memory/polymorphic/move.cc: New test. + * testsuite/std/memory/polymorphic/move_alloc.cc: New test. + 2025-05-30 Tomasz Kamiński <tkaminsk@redhat.com> * testsuite/std/time/format/empty_spec.cc: New test. diff --git a/libstdc++-v3/include/bits/atomic_timed_wait.h b/libstdc++-v3/include/bits/atomic_timed_wait.h index 230afbc..bd2e6bf 100644 --- a/libstdc++-v3/include/bits/atomic_timed_wait.h +++ b/libstdc++-v3/include/bits/atomic_timed_wait.h @@ -87,7 +87,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __wait_until_impl(const void* __addr, __wait_args_base& __args, const __wait_clock_t::duration& __atime); - // Returns {true, val} if wait ended before a timeout. template<typename _Clock, typename _Dur> __wait_result_type __wait_until(const void* __addr, __wait_args_base& __args, @@ -158,8 +157,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION bool __bare_wait = false) noexcept { __detail::__wait_args __args{ __addr, __old, __order, __bare_wait }; - auto __res = __detail::__wait_until(__addr, &__args, __atime); - return __res.first; // C++26 will also return last observed __val + auto __res = __detail::__wait_until(__addr, __args, __atime); + return !__res._M_timeout; // C++26 will also return last observed __val } template<typename _Tp, typename _ValFn, @@ -203,7 +202,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __atomic_wait_address_for_v(const __detail::__platform_wait_t* __addr, __detail::__platform_wait_t __old, int __order, - const chrono::time_point<_Rep, _Period>& __rtime, + const chrono::duration<_Rep, _Period>& __rtime, bool __bare_wait = false) noexcept { __detail::__wait_args __args{ __addr, __old, __order, __bare_wait }; diff --git a/libstdc++-v3/include/bits/basic_string.h b/libstdc++-v3/include/bits/basic_string.h index a087e63..7081049 100644 --- a/libstdc++-v3/include/bits/basic_string.h +++ b/libstdc++-v3/include/bits/basic_string.h @@ -1164,7 +1164,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 { size_type __sz = _M_string_length; if (__sz > max_size ()) - __builtin_unreachable (); + __builtin_unreachable(); return __sz; } @@ -1279,7 +1279,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 size_t __sz = _M_is_local() ? size_type(_S_local_capacity) : _M_allocated_capacity; if (__sz < _S_local_capacity || __sz > max_size ()) - __builtin_unreachable (); + __builtin_unreachable(); return __sz; } diff --git a/libstdc++-v3/include/bits/cpyfunc_impl.h b/libstdc++-v3/include/bits/cpyfunc_impl.h index bc44cd3e..f1918dd 100644 --- a/libstdc++-v3/include/bits/cpyfunc_impl.h +++ b/libstdc++-v3/include/bits/cpyfunc_impl.h @@ -64,6 +64,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _GLIBCXX_MOF_REF noexcept(_Noex)> : __polyfunc::_Cpy_base { + static_assert( + (std::__is_complete_or_unbounded(__type_identity<_ArgTypes>()) && ...), + "each parameter type must be a complete class"); + using _Base = __polyfunc::_Cpy_base; using _Invoker = __polyfunc::_Invoker<_Noex, _Res, _ArgTypes...>; using _Signature = _Invoker::_Signature; diff --git a/libstdc++-v3/include/bits/funcref_impl.h b/libstdc++-v3/include/bits/funcref_impl.h index 1e19866..44c9922 100644 --- a/libstdc++-v3/include/bits/funcref_impl.h +++ b/libstdc++-v3/include/bits/funcref_impl.h @@ -68,6 +68,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION class function_ref<_Res(_ArgTypes...) _GLIBCXX_MOF_CV noexcept(_Noex)> { + static_assert( + (std::__is_complete_or_unbounded(__type_identity<_ArgTypes>()) && ...), + "each parameter type must be a complete class"); + using _Invoker = __polyfunc::_Invoker<_Noex, _Res, _ArgTypes...>; using _Signature = _Invoker::_Signature; diff --git a/libstdc++-v3/include/bits/funcwrap.h b/libstdc++-v3/include/bits/funcwrap.h index cf261bc..9db4ab7 100644 --- a/libstdc++-v3/include/bits/funcwrap.h +++ b/libstdc++-v3/include/bits/funcwrap.h @@ -199,7 +199,25 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION }; template<typename _Tp> - using __param_t = __conditional_t<is_scalar_v<_Tp>, _Tp, _Tp&&>; + consteval bool + __pass_by_value() + { + // n.b. sizeof(Incomplete&) is ill-formed for incomplete types, + // so we check is_reference_v first. + if constexpr (is_reference_v<_Tp> || is_scalar_v<_Tp>) + return true; + else + // n.b. we already asserted that types are complete in wrappers, + // avoid triggering additional errors from this function. + if constexpr (std::__is_complete_or_unbounded(__type_identity<_Tp>())) + if constexpr (sizeof(_Tp) <= 2 * sizeof(void*)) + return is_trivially_move_constructible_v<_Tp> + && is_trivially_destructible_v<_Tp>; + return false; + } + + template<typename _Tp> + using __param_t = __conditional_t<__pass_by_value<_Tp>(), _Tp, _Tp&&>; template<bool _Noex, typename _Ret, typename... _Args> using _Invoker = _Base_invoker<_Noex, remove_cv_t<_Ret>, __param_t<_Args>...>; diff --git a/libstdc++-v3/include/bits/indirect.h b/libstdc++-v3/include/bits/indirect.h index 85908e2..e8000d7 100644 --- a/libstdc++-v3/include/bits/indirect.h +++ b/libstdc++-v3/include/bits/indirect.h @@ -452,7 +452,381 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { }; #endif // __glibcxx_indirect - _GLIBCXX_END_NAMESPACE_VERSION +#if __glibcxx_polymorphic // C++26 && HOSTED + template<typename _Tp, typename _Alloc = allocator<_Tp>> + class polymorphic; + + namespace pmr + { + template<typename _Tp> + using polymorphic = polymorphic<_Tp, polymorphic_allocator<_Tp>>; + } + + // [polymorphic], class template polymorphic + template<typename _Tp, typename _Alloc> + class polymorphic + { + static_assert(is_object_v<_Tp>); + static_assert(!is_array_v<_Tp>); + static_assert(!is_same_v<_Tp, in_place_t>); + static_assert(!__is_in_place_type_v<_Tp>); + static_assert(!is_const_v<_Tp> && !is_volatile_v<_Tp>); + + using _ATraits = allocator_traits<_Alloc>; + static_assert(is_same_v<_Tp, typename _ATraits::value_type>); + + // The owned object is embedded within a control block which knows the + // dynamic type and manages cloning and destroying the owned object. + struct _Obj + { + typename _ATraits::pointer _M_objp{}; // pointer to the owned object. + + // A pointer to this type, e.g. _Obj* + using pointer + = typename _ATraits::template rebind_traits<_Obj>::pointer; + + enum class _Op { _Dispose = 1, _Copy = 2, _Move = 3 }; + + constexpr virtual pointer + _M_manage(const _Alloc&, _Op, void* = nullptr) = 0; + }; + + template<typename _Up> + struct _Obj_impl : _Obj + { + using _MyTraits + = typename _ATraits::template rebind_traits<_Obj_impl>; + + using _Op = _Obj::_Op; + + union _Uninitialized { + constexpr _Uninitialized() { } + constexpr ~_Uninitialized() { } + _Up _M_objp; + }; + _Uninitialized _M_u; + + template<typename... _Args> + constexpr + _Obj_impl(typename _MyTraits::allocator_type& __a, + _Args&&... __args) + { + using _PtrTr = pointer_traits<typename _ATraits::pointer>; + _MyTraits::construct(__a, __builtin_addressof(_M_u._M_objp), + std::forward<_Args>(__args)...); + this->_M_objp = _PtrTr::pointer_to(_M_u._M_objp); + } + + constexpr virtual typename _Obj::pointer + _M_manage(const _Alloc& __a, _Op __op, void*) override + { + + switch (__op) + { + case _Op::_Move: + return _S_make_obj<_Up>(__a, std::move(_M_u._M_objp)); + case _Op::_Copy: + return _S_make_obj<_Up>(__a, + const_cast<const _Up&>(_M_u._M_objp)); + case _Op::_Dispose: + { + using _PtrTr = pointer_traits<typename _MyTraits::pointer>; + typename _MyTraits::allocator_type __a2(__a); + _MyTraits::destroy(__a2, std::__addressof(_M_u._M_objp)); + _MyTraits::deallocate(__a2, _PtrTr::pointer_to(*this), 1); + return nullptr; + } + } + __builtin_unreachable(); + } + }; + + // TODO: the standard permits a small-object optimization where the + // owned object is nested within the std::polymorphic not on the heap. + + public: + + using value_type = _Tp; + using allocator_type = _Alloc; + using pointer = typename allocator_traits<_Alloc>::pointer; + using const_pointer = typename allocator_traits<_Alloc>::const_pointer; + + constexpr explicit + polymorphic() requires is_default_constructible_v<_Alloc> + : polymorphic(in_place_type<_Tp>) + { } + + constexpr explicit + polymorphic(allocator_arg_t, const _Alloc& __a) + : polymorphic(allocator_arg, __a, in_place_type<_Tp>) + { } + + constexpr + polymorphic(const polymorphic& __other) + : polymorphic(allocator_arg, + _ATraits::select_on_container_copy_construction( + __other._M_alloc), + __other) + { } + + constexpr + polymorphic(allocator_arg_t, const _Alloc& __a, + const polymorphic& __other) + : _M_alloc(__a) + { + if (__other._M_objp) + _M_objp = __other._M_objp->_M_manage(__a, _Obj::_Op::_Copy); + else + _M_objp = nullptr; + } + + constexpr + polymorphic(polymorphic&& __other) noexcept + : _M_alloc(std::move(__other._M_alloc)), + _M_objp(std::__exchange(__other._M_objp, nullptr)) + { } + + constexpr + polymorphic(allocator_arg_t, const _Alloc& __a, polymorphic&& __other) + noexcept(_ATraits::is_always_equal::value) + : _M_alloc(__a), + _M_objp(std::__exchange(__other._M_objp, nullptr)) + { + if constexpr (!_ATraits::is_always_equal::value) + if (_M_objp && _M_alloc != __other._M_alloc) + { + // _M_alloc cannot free _M_objp, give it back to __other. + __other._M_objp = std::__exchange(_M_objp, nullptr); + // And create a new object that can be freed by _M_alloc. + _M_objp = __other._M_objp->_M_manage(__a, _Obj::_Op::_Move); + } + } + + template<typename _Up = _Tp, typename _UUp = remove_cvref_t<_Up>> + requires (!is_same_v<_UUp, polymorphic>) + && (!__is_in_place_type_v<_UUp>) + && derived_from<_UUp, _Tp> + && is_constructible_v<_UUp, _Up> + && is_copy_constructible_v<_UUp> + && is_default_constructible_v<_Alloc> + constexpr explicit + polymorphic(_Up&& __u) + : _M_objp(_M_make_obj<_UUp>(std::forward<_Up>(__u))) + { } + + template<typename _Up = _Tp, typename _UUp = remove_cvref_t<_Up>> + requires (!is_same_v<_UUp, polymorphic>) + && (!__is_in_place_type_v<_UUp>) + && derived_from<_UUp, _Tp> + && is_constructible_v<_UUp, _Up> + && is_copy_constructible_v<_UUp> + constexpr explicit + polymorphic(allocator_arg_t, const _Alloc& __a, _Up&& __u) + : _M_alloc(__a), _M_objp(_M_make_obj<_UUp>(std::forward<_Up>(__u))) + { } + + template<typename _Up, typename... _Ts> + requires is_same_v<remove_cvref_t<_Up>, _Up> + && derived_from<_Up, _Tp> + && is_constructible_v<_Up, _Ts...> + && is_copy_constructible_v<_Up> + && is_default_constructible_v<_Alloc> + constexpr explicit + polymorphic(in_place_type_t<_Up> __t, _Ts&&... __ts) + : _M_objp(_M_make_obj<_Up>(std::forward<_Ts>(__ts)...)) + { } + + template<typename _Up, typename... _Ts> + requires is_same_v<remove_cvref_t<_Up>, _Up> + && derived_from<_Up, _Tp> + && is_constructible_v<_Up, _Ts...> + && is_copy_constructible_v<_Up> + constexpr explicit + polymorphic(allocator_arg_t, const _Alloc& __a, + in_place_type_t<_Up>, _Ts&&... __ts) + : _M_alloc(__a), + _M_objp(_M_make_obj<_Up>(std::forward<_Ts>(__ts)...)) + { } + + template<typename _Up, typename _Ip, typename... _Us> + requires is_same_v<remove_cvref_t<_Up>, _Up> + && derived_from<_Up, _Tp> + && is_constructible_v<_Up, initializer_list<_Ip>&, _Us...> + && is_copy_constructible_v<_Up> + && is_default_constructible_v<_Alloc> + constexpr explicit + polymorphic(in_place_type_t<_Up>, initializer_list<_Ip> __il, + _Us&&... __us) + : _M_objp(_M_make_obj<_Up>(__il, std::forward<_Us>(__us)...)) + { } + + template<typename _Up, typename _Ip, typename... _Us> + requires is_same_v<remove_cvref_t<_Up>, _Up> + && derived_from<_Up, _Tp> + && is_constructible_v<_Up, initializer_list<_Ip>&, _Us...> + && is_copy_constructible_v<_Up> + constexpr explicit + polymorphic(allocator_arg_t, const _Alloc& __a, + in_place_type_t<_Up>, initializer_list<_Ip> __il, + _Us&&... __us) + : _M_alloc(__a), + _M_objp(_M_make_obj<_Up>(__il, std::forward<_Us>(__us)...)) + { } + + constexpr ~polymorphic() + { + static_assert(sizeof(_Tp) != 0, "must be a complete type"); + _M_reset(nullptr); + } + + constexpr polymorphic& + operator=(const polymorphic& __other) + { + static_assert(sizeof(_Tp) != 0, "must be a complete type"); + + if (__builtin_addressof(__other) == this) [[unlikely]] + return *this; + + constexpr bool __pocca + = _ATraits::propagate_on_container_copy_assignment::value; + + typename _Obj::pointer __ptr = nullptr; + if (__other._M_objp) + { + auto& __a = __pocca ? __other._M_alloc : _M_alloc; + __ptr = __other._M_objp->_M_manage(__a, _Obj::_Op::_Copy); + } + + _M_reset(__ptr); + + if constexpr (__pocca) + _M_alloc = __other._M_alloc; + + return *this; + } + + constexpr polymorphic& + operator=(polymorphic&& __other) + noexcept(_ATraits::propagate_on_container_move_assignment::value + || _ATraits::is_always_equal::value) + { + if (__builtin_addressof(__other) == this) [[unlikely]] + return *this; + + constexpr bool __pocma + = _ATraits::propagate_on_container_move_assignment::value; + + typename _Obj::pointer __ptr = nullptr; + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4251. Move assignment for indirect unnecessarily requires copy construction + if constexpr (_ATraits::is_always_equal::value || __pocma) + __ptr = std::__exchange(__other._M_objp, nullptr); + else if (_M_alloc == __other._M_alloc) + __ptr = std::__exchange(__other._M_objp, nullptr); + else if (__other._M_objp) + { + static_assert(sizeof(_Tp) != 0, "must be a complete type"); + __ptr = __other._M_objp->_M_manage(_M_alloc, _Obj::_Op::_Move); + } + + _M_reset(__ptr); + + if constexpr (__pocma) + _M_alloc = __other._M_alloc; + + return *this; + } + + constexpr const _Tp& + operator*() const noexcept + { + __glibcxx_assert(_M_objp != nullptr); + return *_M_objp->_M_objp; + } + + constexpr _Tp& + operator*() noexcept + { + __glibcxx_assert(_M_objp != nullptr); + return *_M_objp->_M_objp; + } + + constexpr const_pointer + operator->() const noexcept + { + __glibcxx_assert(_M_objp != nullptr); + return _M_objp ? _M_objp->_M_objp : const_pointer{}; + } + + constexpr pointer + operator->() noexcept + { + __glibcxx_assert(_M_objp != nullptr); + return _M_objp ? _M_objp->_M_objp : pointer{}; + } + + constexpr bool + valueless_after_move() const noexcept { return _M_objp == nullptr; } + + constexpr allocator_type + get_allocator() const noexcept { return _M_alloc; } + + constexpr void + swap(polymorphic& __other) + noexcept(_ATraits::propagate_on_container_swap::value + || _ATraits::is_always_equal::value) + { + using std::swap; + swap(_M_objp, __other._M_objp); + if constexpr (_ATraits::propagate_on_container_swap::value) + swap(_M_alloc, __other._M_alloc); + else if constexpr (!_ATraits::is_always_equal::value) + __glibcxx_assert(_M_alloc == __other._M_alloc); + } + + friend constexpr void + swap(polymorphic& __lhs, polymorphic& __rhs) + noexcept(_ATraits::propagate_on_container_swap::value + || _ATraits::is_always_equal::value) + { __lhs.swap(__rhs); } + + private: + template<typename _Up, typename... _Args> + static constexpr typename _Obj::pointer + _S_make_obj(const _Alloc& __a, _Args&&... __args) + { + __alloc_rebind<_Alloc, _Obj_impl<_Up>> __objalloc(__a); + _Scoped_allocation __sa(__objalloc, in_place, __objalloc, + std::forward<_Args>(__args)...); + auto __obj = __sa.release(); + // FIXME: We need to downcast from _Obj_impl<U>* to _Obj* but the + // the pointer_traits usage breaks in constexpr. PR c++/110714 + if constexpr (is_pointer_v<typename _Obj::pointer>) + return __obj; + else + return pointer_traits<typename _Obj::pointer>::pointer_to(*__obj); + } + + template<typename _Up, typename... _Args> + constexpr typename _Obj::pointer + _M_make_obj(_Args&&... __args) const + { return _S_make_obj<_Up>(_M_alloc, std::forward<_Args>(__args)...); } + + constexpr void + _M_reset(typename _Obj::pointer __ptr) noexcept + { + if (_M_objp) + _M_objp->_M_manage(_M_alloc, _Obj::_Op::_Dispose); + _M_objp = __ptr; + } + + [[no_unique_address]] _Alloc _M_alloc = _Alloc(); + typename _Obj::pointer _M_objp; + }; +#endif // __glibcxx_polymorphic + +_GLIBCXX_END_NAMESPACE_VERSION } // namespace #endif // C++26 __glibcxx_indirect || __glibcxx_polymorphic diff --git a/libstdc++-v3/include/bits/mofunc_impl.h b/libstdc++-v3/include/bits/mofunc_impl.h index 1ceb910..468e685 100644 --- a/libstdc++-v3/include/bits/mofunc_impl.h +++ b/libstdc++-v3/include/bits/mofunc_impl.h @@ -64,6 +64,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _GLIBCXX_MOF_REF noexcept(_Noex)> : __polyfunc::_Mo_base { + static_assert( + (std::__is_complete_or_unbounded(__type_identity<_ArgTypes>()) && ...), + "each parameter type must be a complete class"); + using _Base = __polyfunc::_Mo_base; using _Invoker = __polyfunc::_Invoker<_Noex, _Res, _ArgTypes...>; using _Signature = _Invoker::_Signature; diff --git a/libstdc++-v3/include/bits/ranges_algo.h b/libstdc++-v3/include/bits/ranges_algo.h index f36e7dd..7b14084 100644 --- a/libstdc++-v3/include/bits/ranges_algo.h +++ b/libstdc++-v3/include/bits/ranges_algo.h @@ -1218,6 +1218,9 @@ namespace ranges if (__first == __last) return {std::move(__first), std::move(__result)}; + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4269. unique_copy passes arguments to its predicate backwards + // TODO: perform a closer comparison with reference implementations if constexpr (forward_iterator<_Iter>) { @@ -1250,8 +1253,8 @@ namespace ranges while (++__first != __last) { if (!(bool)std::__invoke(__comp, - std::__invoke(__proj, *__first), - std::__invoke(__proj, __value))) + std::__invoke(__proj, __value), + std::__invoke(__proj, *__first))) { __value = *__first; *++__result = __value; diff --git a/libstdc++-v3/include/bits/stl_algo.h b/libstdc++-v3/include/bits/stl_algo.h index f5361ae..98c2249 100644 --- a/libstdc++-v3/include/bits/stl_algo.h +++ b/libstdc++-v3/include/bits/stl_algo.h @@ -918,52 +918,45 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __gnu_cxx::__ops::__iter_comp_iter(__binary_pred)); } - /** - * This is an uglified - * unique_copy(_InputIterator, _InputIterator, _OutputIterator, - * _BinaryPredicate) - * overloaded for forward iterators and output iterator as result. - */ + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4269. unique_copy passes arguments to its predicate backwards + + // Implementation of std::unique_copy for forward iterators. + // This case is easy, just compare *i with *(i-1). template<typename _ForwardIterator, typename _OutputIterator, typename _BinaryPredicate> _GLIBCXX20_CONSTEXPR _OutputIterator __unique_copy(_ForwardIterator __first, _ForwardIterator __last, _OutputIterator __result, _BinaryPredicate __binary_pred, - forward_iterator_tag, output_iterator_tag) + forward_iterator_tag) { - _ForwardIterator __next = __first; + _ForwardIterator __prev = __first; *__result = *__first; - while (++__next != __last) - if (!__binary_pred(__first, __next)) + while (++__first != __last) + if (!__binary_pred(__prev, __first)) { - __first = __next; *++__result = *__first; + __prev = __first; } return ++__result; } - /** - * This is an uglified - * unique_copy(_InputIterator, _InputIterator, _OutputIterator, - * _BinaryPredicate) - * overloaded for input iterators and output iterator as result. - */ + // Implementation of std::unique_copy for non-forward iterators, + // where we cannot compare with elements written to the output. template<typename _InputIterator, typename _OutputIterator, typename _BinaryPredicate> _GLIBCXX20_CONSTEXPR _OutputIterator - __unique_copy(_InputIterator __first, _InputIterator __last, - _OutputIterator __result, _BinaryPredicate __binary_pred, - input_iterator_tag, output_iterator_tag) + __unique_copy_1(_InputIterator __first, _InputIterator __last, + _OutputIterator __result, _BinaryPredicate __binary_pred, + __false_type) { - typename iterator_traits<_InputIterator>::value_type __value = *__first; - __decltype(__gnu_cxx::__ops::__iter_comp_val(__binary_pred)) - __rebound_pred - = __gnu_cxx::__ops::__iter_comp_val(__binary_pred); + typedef typename iterator_traits<_InputIterator>::value_type _Val; + _Val __value = *__first; *__result = __value; while (++__first != __last) - if (!__rebound_pred(__first, __value)) + if (!__binary_pred(std::__addressof(__value), __first)) { __value = *__first; *++__result = __value; @@ -971,19 +964,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return ++__result; } - /** - * This is an uglified - * unique_copy(_InputIterator, _InputIterator, _OutputIterator, - * _BinaryPredicate) - * overloaded for input iterators and forward iterator as result. - */ + // Implementation of std::unique_copy for non-forward iterators, + // where we can compare with the last element written to the output. template<typename _InputIterator, typename _ForwardIterator, typename _BinaryPredicate> - _GLIBCXX20_CONSTEXPR _ForwardIterator - __unique_copy(_InputIterator __first, _InputIterator __last, - _ForwardIterator __result, _BinaryPredicate __binary_pred, - input_iterator_tag, forward_iterator_tag) + __unique_copy_1(_InputIterator __first, _InputIterator __last, + _ForwardIterator __result, _BinaryPredicate __binary_pred, + __true_type) { *__result = *__first; while (++__first != __last) @@ -992,6 +980,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return ++__result; } + // Implementation of std::unique_copy for non-forward iterators. + // We cannot compare *i to *(i-1) so we need to either make a copy + // or compare with the last element written to the output range. + template<typename _InputIterator, typename _OutputIterator, + typename _BinaryPredicate> + _GLIBCXX20_CONSTEXPR + _OutputIterator + __unique_copy(_InputIterator __first, _InputIterator __last, + _OutputIterator __result, _BinaryPredicate __binary_pred, + input_iterator_tag) + { + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2439. unique_copy() sometimes can't fall back to reading its output + typedef iterator_traits<_InputIterator> _InItTraits; + typedef iterator_traits<_OutputIterator> _OutItTraits; + typedef typename _OutItTraits::iterator_category _Cat; + const bool __output_is_fwd = __is_base_of(forward_iterator_tag, _Cat); + const bool __same_type = __is_same(typename _OutItTraits::value_type, + typename _InItTraits::value_type); + typedef __truth_type<__output_is_fwd && __same_type> __cmp_with_output; + return std::__unique_copy_1(__first, __last, __result, __binary_pred, + typename __cmp_with_output::__type()); + } + + /** * This is an uglified reverse(_BidirectionalIterator, * _BidirectionalIterator) @@ -4456,8 +4469,7 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO return __result; return std::__unique_copy(__first, __last, __result, __gnu_cxx::__ops::__iter_equal_to_iter(), - std::__iterator_category(__first), - std::__iterator_category(__result)); + std::__iterator_category(__first)); } /** @@ -4499,8 +4511,7 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO return __result; return std::__unique_copy(__first, __last, __result, __gnu_cxx::__ops::__iter_comp_iter(__binary_pred), - std::__iterator_category(__first), - std::__iterator_category(__result)); + std::__iterator_category(__first)); } #if __cplusplus <= 201103L || _GLIBCXX_USE_DEPRECATED diff --git a/libstdc++-v3/include/bits/stl_deque.h b/libstdc++-v3/include/bits/stl_deque.h index 8d8ee57..7055641 100644 --- a/libstdc++-v3/include/bits/stl_deque.h +++ b/libstdc++-v3/include/bits/stl_deque.h @@ -1331,7 +1331,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER { size_type __sz = this->_M_impl._M_finish - this->_M_impl._M_start; if (__sz > max_size ()) - __builtin_unreachable (); + __builtin_unreachable(); return __sz; } diff --git a/libstdc++-v3/include/bits/stl_vector.h b/libstdc++-v3/include/bits/stl_vector.h index 625c1c9..f2c1bce 100644 --- a/libstdc++-v3/include/bits/stl_vector.h +++ b/libstdc++-v3/include/bits/stl_vector.h @@ -372,8 +372,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER _GLIBCXX20_CONSTEXPR ~_Vector_base() _GLIBCXX_NOEXCEPT { - _M_deallocate(_M_impl._M_start, - _M_impl._M_end_of_storage - _M_impl._M_start); + ptrdiff_t __n = _M_impl._M_end_of_storage - _M_impl._M_start; + if (__n < 0) + __builtin_unreachable(); + _M_deallocate(_M_impl._M_start, size_t(__n)); } public: @@ -1106,7 +1108,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER { ptrdiff_t __dif = this->_M_impl._M_finish - this->_M_impl._M_start; if (__dif < 0) - __builtin_unreachable (); + __builtin_unreachable(); return size_type(__dif); } @@ -1198,7 +1200,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER ptrdiff_t __dif = this->_M_impl._M_end_of_storage - this->_M_impl._M_start; if (__dif < 0) - __builtin_unreachable (); + __builtin_unreachable(); return size_type(__dif); } diff --git a/libstdc++-v3/include/bits/vector.tcc b/libstdc++-v3/include/bits/vector.tcc index e18f01a..70ead1d 100644 --- a/libstdc++-v3/include/bits/vector.tcc +++ b/libstdc++-v3/include/bits/vector.tcc @@ -466,7 +466,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER { const size_type __len = _M_check_len(1u, "vector::_M_realloc_insert"); if (__len <= 0) - __builtin_unreachable (); + __builtin_unreachable(); pointer __old_start = this->_M_impl._M_start; pointer __old_finish = this->_M_impl._M_finish; const size_type __elems_before = __position - begin(); @@ -573,10 +573,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER { const size_type __len = _M_check_len(1u, "vector::_M_realloc_append"); if (__len <= 0) - __builtin_unreachable (); + __builtin_unreachable(); pointer __old_start = this->_M_impl._M_start; pointer __old_finish = this->_M_impl._M_finish; - const size_type __elems = end() - begin(); + const size_type __elems = size(); pointer __new_start(this->_M_allocate(__len)); pointer __new_finish(__new_start); diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def index 9ab14a0..5efe4d1 100644 --- a/libstdc++-v3/include/bits/version.def +++ b/libstdc++-v3/include/bits/version.def @@ -1978,6 +1978,15 @@ ftms = { }; }; +ftms = { + name = polymorphic; + values = { + v = 202502; + cxxmin = 26; + hosted = yes; + }; +}; + // Standard test specifications. stds[97] = ">= 199711L"; stds[03] = ">= 199711L"; diff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/include/bits/version.h index 3358e84..5e905da 100644 --- a/libstdc++-v3/include/bits/version.h +++ b/libstdc++-v3/include/bits/version.h @@ -2213,4 +2213,14 @@ #endif /* !defined(__cpp_lib_indirect) && defined(__glibcxx_want_indirect) */ #undef __glibcxx_want_indirect +#if !defined(__cpp_lib_polymorphic) +# if (__cplusplus > 202302L) && _GLIBCXX_HOSTED +# define __glibcxx_polymorphic 202502L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_polymorphic) +# define __cpp_lib_polymorphic 202502L +# endif +# endif +#endif /* !defined(__cpp_lib_polymorphic) && defined(__glibcxx_want_polymorphic) */ +#undef __glibcxx_want_polymorphic + #undef __glibcxx_want_all diff --git a/libstdc++-v3/include/std/bit b/libstdc++-v3/include/std/bit index 5187c96..fd75edf 100644 --- a/libstdc++-v3/include/std/bit +++ b/libstdc++-v3/include/std/bit @@ -166,7 +166,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Variant for power of two _Nd which the compiler can // easily pattern match. constexpr unsigned __uNd = _Nd; - const unsigned __r = __s; + const auto __r = static_cast<unsigned>(__s); return (__x << (__r % __uNd)) | (__x >> ((-__r) % __uNd)); } const int __r = __s % _Nd; @@ -188,7 +188,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Variant for power of two _Nd which the compiler can // easily pattern match. constexpr unsigned __uNd = _Nd; - const unsigned __r = __s; + const auto __r = static_cast<unsigned>(__s); return (__x >> (__r % __uNd)) | (__x << ((-__r) % __uNd)); } const int __r = __s % _Nd; diff --git a/libstdc++-v3/include/std/memory b/libstdc++-v3/include/std/memory index d64e65c..1da03b3 100644 --- a/libstdc++-v3/include/std/memory +++ b/libstdc++-v3/include/std/memory @@ -113,6 +113,7 @@ #define __glibcxx_want_make_unique #define __glibcxx_want_out_ptr #define __glibcxx_want_parallel_algorithm +#define __glibcxx_want_polymorphic #define __glibcxx_want_ranges #define __glibcxx_want_raw_memory_algorithms #define __glibcxx_want_shared_ptr_arrays diff --git a/libstdc++-v3/include/std/stop_token b/libstdc++-v3/include/std/stop_token index 1225b3a..775ec6a 100644 --- a/libstdc++-v3/include/std/stop_token +++ b/libstdc++-v3/include/std/stop_token @@ -34,8 +34,7 @@ #define __glibcxx_want_jthread #include <bits/version.h> -#if __cplusplus > 201703L - +#ifdef __glibcxx_jthread // C++ >= 20 #include <atomic> #include <bits/std_thread.h> @@ -650,6 +649,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION stop_callback(stop_token, _Callback) -> stop_callback<_Callback>; _GLIBCXX_END_NAMESPACE_VERSION -} // namespace -#endif // __cplusplus > 201703L +} // namespace std +#endif // __glibcxx_jthread #endif // _GLIBCXX_STOP_TOKEN diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits index 6bf355d..c8907fe 100644 --- a/libstdc++-v3/include/std/type_traits +++ b/libstdc++-v3/include/std/type_traits @@ -1039,6 +1039,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Destructible and constructible type properties. +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_destructible) + /// is_destructible + template<typename _Tp> + struct is_destructible + : public __bool_constant<__is_destructible(_Tp)> + { }; +#else // In N3290 is_destructible does not say anything about function // types and abstract types, see LWG 2049. This implementation // describes function types as non-destructible and all complete @@ -1090,7 +1097,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}), "template argument must be a complete class or an unbounded array"); }; +#endif +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_nothrow_destructible) + /// is_nothrow_destructible + template<typename _Tp> + struct is_nothrow_destructible + : public __bool_constant<__is_nothrow_destructible(_Tp)> + { }; +#else /// @cond undocumented // is_nothrow_destructible requires that is_destructible is @@ -1144,6 +1159,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}), "template argument must be a complete class or an unbounded array"); }; +#endif /// @cond undocumented template<typename _Tp, typename... _Args> @@ -1451,6 +1467,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION "template argument must be a complete class or an unbounded array"); }; +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_trivially_destructible) + /// is_trivially_destructible + template<typename _Tp> + struct is_trivially_destructible + : public __bool_constant<__is_trivially_destructible(_Tp)> + { }; +#else /// is_trivially_destructible template<typename _Tp> struct is_trivially_destructible @@ -1460,7 +1483,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}), "template argument must be a complete class or an unbounded array"); }; - +#endif /// has_virtual_destructor template<typename _Tp> @@ -3581,8 +3604,13 @@ template <typename _Tp> inline constexpr bool is_move_assignable_v = __is_assignable(__add_lval_ref_t<_Tp>, __add_rval_ref_t<_Tp>); +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_destructible) +template <typename _Tp> + inline constexpr bool is_destructible_v = __is_destructible(_Tp); +#else template <typename _Tp> inline constexpr bool is_destructible_v = is_destructible<_Tp>::value; +#endif template <typename _Tp, typename... _Args> inline constexpr bool is_trivially_constructible_v @@ -3609,7 +3637,11 @@ template <typename _Tp> = __is_trivially_assignable(__add_lval_ref_t<_Tp>, __add_rval_ref_t<_Tp>); -#if __cpp_concepts +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_trivially_destructible) +template <typename _Tp> + inline constexpr bool is_trivially_destructible_v + = __is_trivially_destructible(_Tp); +#elif __cpp_concepts template <typename _Tp> inline constexpr bool is_trivially_destructible_v = false; @@ -3654,9 +3686,15 @@ template <typename _Tp> inline constexpr bool is_nothrow_move_assignable_v = __is_nothrow_assignable(__add_lval_ref_t<_Tp>, __add_rval_ref_t<_Tp>); +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_nothrow_destructible) +template <typename _Tp> + inline constexpr bool is_nothrow_destructible_v + = __is_nothrow_destructible(_Tp); +#else template <typename _Tp> inline constexpr bool is_nothrow_destructible_v = is_nothrow_destructible<_Tp>::value; +#endif template <typename _Tp> inline constexpr bool has_virtual_destructor_v diff --git a/libstdc++-v3/src/c++20/atomic.cc b/libstdc++-v3/src/c++20/atomic.cc index a3ec92a..4120e1a 100644 --- a/libstdc++-v3/src/c++20/atomic.cc +++ b/libstdc++-v3/src/c++20/atomic.cc @@ -397,17 +397,18 @@ __cond_wait_until(__condvar& __cv, mutex& __mx, } #endif // ! HAVE_PLATFORM_TIMED_WAIT -// Like __spin_impl, always returns _M_has_val == true. +// Unlike __spin_impl, does not always return _M_has_val == true. +// If the deadline has already passed then no fresh value is loaded. __wait_result_type __spin_until_impl(const __platform_wait_t* __addr, const __wait_args_base& __args, const __wait_clock_t::time_point& __deadline) { - auto __t0 = __wait_clock_t::now(); using namespace literals::chrono_literals; - __platform_wait_t __val{}; - auto __now = __wait_clock_t::now(); + __wait_result_type __res{}; + auto __t0 = __wait_clock_t::now(); + auto __now = __t0; for (; __now < __deadline; __now = __wait_clock_t::now()) { auto __elapsed = __now - __t0; @@ -422,16 +423,21 @@ __spin_until_impl(const __platform_wait_t* __addr, __thread_yield(); else { - auto __res = __detail::__spin_impl(__addr, __args); + __res = __detail::__spin_impl(__addr, __args); if (!__res._M_timeout) return __res; } - __atomic_load(__addr, &__val, __args._M_order); - if (__val != __args._M_old) - return { ._M_val = __val, ._M_has_val = true, ._M_timeout = false }; + __atomic_load(__addr, &__res._M_val, __args._M_order); + __res._M_has_val = true; + if (__res._M_val != __args._M_old) + { + __res._M_timeout = false; + return __res; + } } - return { ._M_val = __val, ._M_has_val = true, ._M_timeout = true }; + __res._M_timeout = true; + return __res; } } // namespace diff --git a/libstdc++-v3/src/c++23/std.cc.in b/libstdc++-v3/src/c++23/std.cc.in index ba46853..eddd3c8 100644 --- a/libstdc++-v3/src/c++23/std.cc.in +++ b/libstdc++-v3/src/c++23/std.cc.in @@ -511,7 +511,6 @@ export namespace std } // 22.7.2 <any> -#if __cpp_lib_any export namespace std { using std::any; @@ -520,7 +519,6 @@ export namespace std using std::make_any; using std::swap; } -#endif // 24.3.2 <array> export namespace std @@ -698,7 +696,6 @@ export namespace std } // 29.2 <chrono> -#if __cpp_lib_chrono export namespace std { namespace chrono @@ -852,7 +849,6 @@ export namespace std::inline literals::inline chrono_literals export namespace std::chrono { using namespace literals::chrono_literals; } -#endif // __cpp_lib_chrono // <codecvt>: deprecated C++17, removed C++26 export namespace std @@ -864,7 +860,6 @@ export namespace std } // 17.11.1 <compare> -#if __cpp_lib_three_way_comparison export namespace std { using std::common_comparison_category; @@ -890,7 +885,6 @@ export namespace std using std::strong_order; using std::weak_order; } -#endif // __cpp_lib_three_way_comparison // 28.4 <complex> export namespace std @@ -944,7 +938,6 @@ export namespace std::inline literals::inline complex_literals } // 18 <concepts> -#if __cpp_lib_concepts export namespace std { using std::assignable_from; @@ -983,7 +976,6 @@ export namespace std using std::totally_ordered; using std::totally_ordered_with; } -#endif // 33.7 <condition_variable> export namespace std diff --git a/libstdc++-v3/testsuite/20_util/copyable_function/call.cc b/libstdc++-v3/testsuite/20_util/copyable_function/call.cc index cf99757..0ac5348 100644 --- a/libstdc++-v3/testsuite/20_util/copyable_function/call.cc +++ b/libstdc++-v3/testsuite/20_util/copyable_function/call.cc @@ -204,13 +204,14 @@ test05() } struct Incomplete; +enum CompleteEnum : int; void test_params() { - std::copyable_function<void(Incomplete)> f1; - std::copyable_function<void(Incomplete&)> f2; - std::copyable_function<void(Incomplete&&)> f3; + std::copyable_function<void(Incomplete&)> f1; + std::copyable_function<void(Incomplete&&)> f2; + std::copyable_function<void(CompleteEnum)> f4; } int main() diff --git a/libstdc++-v3/testsuite/20_util/copyable_function/conv.cc b/libstdc++-v3/testsuite/20_util/copyable_function/conv.cc index e678e16..11c839b 100644 --- a/libstdc++-v3/testsuite/20_util/copyable_function/conv.cc +++ b/libstdc++-v3/testsuite/20_util/copyable_function/conv.cc @@ -2,6 +2,7 @@ // { dg-require-effective-target hosted } #include <functional> +#include <string_view> #include <testsuite_hooks.h> using std::copyable_function; @@ -15,6 +16,21 @@ static_assert( !std::is_constructible_v<std::copyable_function<void()&>, static_assert( !std::is_constructible_v<std::copyable_function<void() const>, std::copyable_function<void()>> ); +using FuncType = int(int); + +// Top level const qualifiers are ignored and decay is performed in parameters +// of function_types. +static_assert( std::is_same_v<std::copyable_function<void(int const)>, + std::copyable_function<void(int)>> ); +static_assert( std::is_same_v<std::copyable_function<void(int[2])>, + std::copyable_function<void(int*)>>); +static_assert( std::is_same_v<std::copyable_function<void(int[])>, + std::copyable_function<void(int*)>>); +static_assert( std::is_same_v<std::copyable_function<void(int const[5])>, + std::copyable_function<void(int const*)>>); +static_assert( std::is_same_v<std::copyable_function<void(FuncType)>, + std::copyable_function<void(FuncType*)>>); + // Non-trivial args, guarantess that type is not passed by copy struct CountedArg { @@ -240,6 +256,24 @@ test06() VERIFY( f2(c) == 2 ); } +void +test07() +{ + // Scalar types and small trivially move constructible types are passed + // by value to invoker. So int&& signature is not compatible for such types. + auto fi = [](CountedArg const& arg, int) noexcept { return arg.counter; }; + std::copyable_function<int(CountedArg, int) const noexcept> ci1(fi); + VERIFY( ci1(c, 0) == 1 ); + std::copyable_function<int(CountedArg, int&&) const noexcept> ci2(ci1); + VERIFY( ci2(c, 0) == 2 ); + + auto fs = [](CountedArg const& arg, std::string_view) noexcept { return arg.counter; }; + std::copyable_function<int(CountedArg, std::string_view) const noexcept> cs1(fs); + VERIFY( cs1(c, "") == 1 ); + std::copyable_function<int(CountedArg, std::string_view&&) const noexcept> cs2(cs1); + VERIFY( cs2(c, "") == 2 ); +} + int main() { test01(); @@ -248,4 +282,5 @@ int main() test04(); test05(); test06(); + test07(); } diff --git a/libstdc++-v3/testsuite/20_util/copyable_function/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/copyable_function/incomplete_neg.cc new file mode 100644 index 0000000..21ddde0 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/copyable_function/incomplete_neg.cc @@ -0,0 +1,18 @@ +// { dg-do compile { target c++26 } } + +#include <functional> + +struct IncompleteClass; + +using T1 = std::copyable_function<int(IncompleteClass)>::result_type; // { dg-error "here" } +using T2 = std::copyable_function<int(int, IncompleteClass)>::result_type; // { dg-error "here" } + +enum Enum { + x = [] { + // Enum enumeration is incomplete here + using T3 = std::copyable_function<int(Enum)>::result_type; // { dg-error "here" } + return T3(1); + }() +}; + +// { dg-error "static assertion failed" "" { target *-*-* } 0 } diff --git a/libstdc++-v3/testsuite/20_util/function_ref/call.cc b/libstdc++-v3/testsuite/20_util/function_ref/call.cc index a91c6b4..23253c3 100644 --- a/libstdc++-v3/testsuite/20_util/function_ref/call.cc +++ b/libstdc++-v3/testsuite/20_util/function_ref/call.cc @@ -164,16 +164,16 @@ test05() } struct Incomplete; +enum CompleteEnum : int; void test_params() { auto f = [](auto&&) {}; - // There is discussion if this is supported. - // std::function_ref<void(Incomplete)> f1(f); - std::function_ref<void(Incomplete&)> f2(f); - // See PR120259, this should be supported. - // std::function_ref<void(Incomplete&&)> f3(f); + std::function_ref<void(Incomplete&)> f1(f); + // See PR libstdc++/120259, this should be supported. + // std::function_ref<void(Incomplete&&)> f2(f); + std::function_ref<void(CompleteEnum)> f3(f); } int main() diff --git a/libstdc++-v3/testsuite/20_util/function_ref/conv.cc b/libstdc++-v3/testsuite/20_util/function_ref/conv.cc index 7dc7b8c..7606d26 100644 --- a/libstdc++-v3/testsuite/20_util/function_ref/conv.cc +++ b/libstdc++-v3/testsuite/20_util/function_ref/conv.cc @@ -2,6 +2,7 @@ // { dg-require-effective-target hosted } #include <functional> +#include <string_view> #include <testsuite_hooks.h> using std::function_ref; @@ -20,6 +21,21 @@ struct CountedArg }; CountedArg const c; +using FuncType = int(int); + +// Top level const qualifiers are ignored in function types, and decay +// is performed. +static_assert( std::is_same_v<std::function_ref<void(int const)>, + std::function_ref<void(int)>> ); +static_assert( std::is_same_v<std::function_ref<void(int[2])>, + std::function_ref<void(int*)>>); +static_assert( std::is_same_v<std::function_ref<void(int[])>, + std::function_ref<void(int*)>>); +static_assert( std::is_same_v<std::function_ref<void(int const[5])>, + std::function_ref<void(int const*)>>); +static_assert( std::is_same_v<std::function_ref<void(FuncType)>, + std::function_ref<void(FuncType*)>>); + // The C++26 [func.wrap.general] p2 does not currently cover funciton_ref, // so we make extra copies of arguments. @@ -244,6 +260,23 @@ test08() return true; }; +void +test09() +{ + // Scalar types and small trivially move constructible types are passed + // by value to invoker. So int&& signature is not compatible for such types. + auto fi = [](CountedArg const& arg, int) noexcept { return arg.counter; }; + std::function_ref<int(CountedArg, int) const noexcept> ri1(fi); + VERIFY( ri1(c, 0) == 1 ); + std::function_ref<int(CountedArg, int&&) const noexcept> ri2(ri1); + VERIFY( ri2(c, 0) == 2 ); + + auto fs = [](CountedArg const& arg, std::string_view) noexcept { return arg.counter; }; + std::function_ref<int(CountedArg, std::string_view) const noexcept> rs1(fs); + VERIFY( rs1(c, "") == 1 ); + std::function_ref<int(CountedArg, std::string_view&&) const noexcept> rs2(rs1); + VERIFY( rs2(c, "") == 2 ); +} int main() { @@ -254,6 +287,7 @@ int main() test05(); test06(); test07(); + test09(); static_assert( test08() ); } diff --git a/libstdc++-v3/testsuite/20_util/function_ref/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/function_ref/incomplete_neg.cc new file mode 100644 index 0000000..c8db1ee --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/function_ref/incomplete_neg.cc @@ -0,0 +1,18 @@ +// { dg-do compile { target c++26 } } + +#include <functional> + +struct IncompleteClass; + +int a1 = alignof(std::function_ref<int(IncompleteClass)>); // { dg-error "here" } +int a2 = alignof(std::function_ref<int(int, IncompleteClass)>); // { dg-error "here" } + +enum Enum { + x = [] { + // Enum enumeration is incomplete here + int a3 = alignof(std::function_ref<int(Enum)>); // { dg-error "here" } + return 1; + }() +}; + +// { dg-error "static assertion failed" "" { target *-*-* } 0 } diff --git a/libstdc++-v3/testsuite/20_util/move_only_function/call.cc b/libstdc++-v3/testsuite/20_util/move_only_function/call.cc index 217de37..72c8118 100644 --- a/libstdc++-v3/testsuite/20_util/move_only_function/call.cc +++ b/libstdc++-v3/testsuite/20_util/move_only_function/call.cc @@ -204,13 +204,14 @@ test05() } struct Incomplete; +enum CompleteEnum : int; void test_params() { - std::move_only_function<void(Incomplete)> f1; - std::move_only_function<void(Incomplete&)> f2; - std::move_only_function<void(Incomplete&&)> f3; + std::move_only_function<void(Incomplete&)> f1; + std::move_only_function<void(Incomplete&&)> f2; + std::move_only_function<void(CompleteEnum)> f4; } int main() diff --git a/libstdc++-v3/testsuite/20_util/move_only_function/conv.cc b/libstdc++-v3/testsuite/20_util/move_only_function/conv.cc index 3da5e9e..ef8bb37b 100644 --- a/libstdc++-v3/testsuite/20_util/move_only_function/conv.cc +++ b/libstdc++-v3/testsuite/20_util/move_only_function/conv.cc @@ -2,6 +2,7 @@ // { dg-require-effective-target hosted } #include <functional> +#include <string_view> #include <testsuite_hooks.h> using std::move_only_function; @@ -15,6 +16,21 @@ static_assert( !std::is_constructible_v<std::move_only_function<void()&>, static_assert( !std::is_constructible_v<std::move_only_function<void() const>, std::move_only_function<void()>> ); +using FuncType = int(int); + +// Top level const qualifiers are ignored in function types, and decay +// is performed. +static_assert( std::is_same_v<std::move_only_function<void(int const)>, + std::move_only_function<void(int)>> ); +static_assert( std::is_same_v<std::move_only_function<void(int[2])>, + std::move_only_function<void(int*)>>); +static_assert( std::is_same_v<std::move_only_function<void(int[])>, + std::move_only_function<void(int*)>>); +static_assert( std::is_same_v<std::move_only_function<void(int const[5])>, + std::move_only_function<void(int const*)>>); +static_assert( std::is_same_v<std::move_only_function<void(FuncType)>, + std::move_only_function<void(FuncType*)>>); + // Non-trivial args, guarantess that type is not passed by copy struct CountedArg { @@ -177,6 +193,24 @@ test06() VERIFY( m1(c) == 2 ); } +void +test07() +{ + // Scalar types and small trivially move constructible types are passed + // by value to invoker. So int&& signature is not compatible for such types. + auto fi = [](CountedArg const& arg, int) noexcept { return arg.counter; }; + std::move_only_function<int(CountedArg, int) const noexcept> mi1(fi); + VERIFY( mi1(c, 0) == 1 ); + std::move_only_function<int(CountedArg, int&&) const noexcept> mi2(std::move(mi1)); + VERIFY( mi2(c, 0) == 2 ); + + auto fs = [](CountedArg const& arg, std::string_view) noexcept { return arg.counter; }; + std::move_only_function<int(CountedArg, std::string_view) const noexcept> ms1(fs); + VERIFY( ms1(c, "") == 1 ); + std::move_only_function<int(CountedArg, std::string_view&&) const noexcept> ms2(std::move(ms1)); + VERIFY( ms2(c, "") == 2 ); +} + int main() { test01(); @@ -185,4 +219,5 @@ int main() test04(); test05(); test06(); + test07(); } diff --git a/libstdc++-v3/testsuite/20_util/move_only_function/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/move_only_function/incomplete_neg.cc new file mode 100644 index 0000000..d025c47 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/move_only_function/incomplete_neg.cc @@ -0,0 +1,18 @@ +// { dg-do compile { target c++23 } } + +#include <functional> + +struct IncompleteClass; + +using T1 = std::move_only_function<int(IncompleteClass)>::result_type; // { dg-error "here" } +using T2 = std::move_only_function<int(int, IncompleteClass)>::result_type; // { dg-error "here" } + +enum Enum { + x = [] { + // Enum enumeration is incomplete here + using T3 = std::move_only_function<int(Enum)>::result_type; // { dg-error "here" } + return T3(1); + }() +}; + +// { dg-error "static assertion failed" "" { target *-*-* } 0 } diff --git a/libstdc++-v3/testsuite/25_algorithms/unique_copy/lwg2439.cc b/libstdc++-v3/testsuite/25_algorithms/unique_copy/lwg2439.cc new file mode 100644 index 0000000..f2ec3e3 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/unique_copy/lwg2439.cc @@ -0,0 +1,127 @@ +// { dg-do run } + +#include <algorithm> +#include <testsuite_iterators.h> + +using namespace __gnu_test; + +int out[4]; +short out_shrt[4]; +short in[7] = { 1, 2, 2, 2, 3, 4, 4 }; + +template<typename T> +void +check_and_reset(T* p) +{ + VERIFY( p[0] == 1 ); + VERIFY( p[1] == 2 ); + VERIFY( p[2] == 3 ); + VERIFY( p[3] == 4 ); + std::fill_n(p, 4, 0); +} + +struct Eq +{ + bool operator()(short i, short j) const { return i == j; } + bool operator()(short, int) const { VERIFY(false); } + bool operator()(int, short) const { VERIFY(false); } +}; + +struct Eq2 +{ + bool operator()(const short& i, const short& j) const + { + // Both arguments should be elements of the 'in' array. + VERIFY( in+0 <= &i && &i < in+7 ); + VERIFY( in+0 <= &j && &j < in+7 ); + VERIFY( &i < &j ); + return i == j; + } + bool operator()(short, int) const { VERIFY(false); } + bool operator()(int, short) const { VERIFY(false); } +}; + +struct Eq3 +{ + bool operator()(const short& i, const short& j) const + { + // First argument should be element of the 'out' array. + // Second argument should be element of the 'in' array. + VERIFY( out_shrt+0 <= &i && &i < out_shrt+4 ); + VERIFY( in+0 <= &j && &j < in+7 ); + return i == j; + } + bool operator()(short, int) const { VERIFY(false); } + bool operator()(int, short) const { VERIFY(false); } +}; + +void +test_forward_source() +{ + // The input range uses forward iterators + test_container<short, forward_iterator_wrapper> inc(in); + test_container<int, output_iterator_wrapper> outc(out); + std::unique_copy(inc.begin(), inc.end(), outc.begin()); + check_and_reset(out); + + test_container<short, forward_iterator_wrapper> inc2(in); + test_container<int, output_iterator_wrapper> outc2(out); + std::unique_copy(inc2.begin(), inc2.end(), outc2.begin(), Eq2()); + check_and_reset(out); +} + +void +test_output_dest() +{ + // The input range uses input iterators. + // The output range uses output iterators. + test_container<short, input_iterator_wrapper> inc(in); + test_container<int, output_iterator_wrapper> outc(out); + std::unique_copy(inc.begin(), inc.end(), outc.begin()); + check_and_reset(out); + + test_container<short, input_iterator_wrapper> inc2(in); + test_container<int, output_iterator_wrapper> outc2(out); + std::unique_copy(inc2.begin(), inc2.end(), outc2.begin(), Eq()); + check_and_reset(out); +} + +void +test_forward_dest_diff_type() +{ + // The input range uses input iterators. + // The output range uses forward iterators, but with different value type. + test_container<short, input_iterator_wrapper> inc(in); + test_container<int, forward_iterator_wrapper> outc(out); + std::unique_copy(inc.begin(), inc.end(), outc.begin()); + check_and_reset(out); + + test_container<short, input_iterator_wrapper> inc2(in); + test_container<int, forward_iterator_wrapper> outc2(out); + std::unique_copy(inc2.begin(), inc2.end(), outc2.begin(), Eq()); + check_and_reset(out); +} + +void +test_forward_dest_same_type() +{ + // The input range uses input iterators. + // The output range uses forward iterators, with same value type. + test_container<short, input_iterator_wrapper> inc(in); + test_container<short, forward_iterator_wrapper> outc(out_shrt); + std::unique_copy(inc.begin(), inc.end(), outc.begin()); + check_and_reset(out_shrt); + + test_container<short, input_iterator_wrapper> inc2(in); + test_container<short, forward_iterator_wrapper> outc2(out_shrt); + std::unique_copy(inc2.begin(), inc2.end(), outc2.begin(), Eq3()); + check_and_reset(out_shrt); +} + +int main() +{ + test_forward_source(); + test_output_dest(); + test_forward_dest_diff_type(); + test_forward_dest_same_type(); +} diff --git a/libstdc++-v3/testsuite/std/memory/polymorphic/copy.cc b/libstdc++-v3/testsuite/std/memory/polymorphic/copy.cc new file mode 100644 index 0000000..bea05ac --- /dev/null +++ b/libstdc++-v3/testsuite/std/memory/polymorphic/copy.cc @@ -0,0 +1,157 @@ +// { dg-do run { target c++26 } } + +#include <memory> +#include <scoped_allocator> +#include <utility> +#include <vector> + +#include <testsuite_hooks.h> +#include <testsuite_allocator.h> + +struct Base { + friend constexpr + bool operator==(const Base& lhs, const Base& rhs) + { return lhs.eq(rhs); } + +private: + constexpr virtual bool + eq(const Base& other) const = 0; +}; + +struct Derived : Base +{ + constexpr Derived() + : x(0), y(0), z(0) + { } + + constexpr Derived(int a, int b, int c) + : x(a), y(b), z(c) + { } + +private: + constexpr bool + eq(const Base& other) const override + { + if (auto op = dynamic_cast<const Derived*>(&other)) + return this->x == op->x && this->y == op->y && this->z == op->z; + return false; + } + + int x; + int y; + int z; +}; + +using __gnu_test::tracker_allocator; +using Counter = __gnu_test::tracker_allocator_counter; +using Polymorhic = std::polymorphic<Base, tracker_allocator<Base>>; +const Polymorhic src(std::in_place_type<Derived>, 1, 2, 3); + +constexpr void +test_ctor() +{ + Counter::reset(); + Polymorhic i1(src); + VERIFY( *i1 == *src ); + VERIFY( &*i1 != &*src ); + VERIFY( Counter::get_allocation_count() >= sizeof(Derived) ); + VERIFY( Counter::get_deallocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 2 ); + VERIFY( Counter::get_destruct_count() == 0 ); + + Counter::reset(); + Polymorhic i2(std::allocator_arg, {}, src); + VERIFY( *i2 == *src ); + VERIFY( &*i2 != &*src ); + VERIFY( Counter::get_allocation_count() >= sizeof(Derived) ); + VERIFY( Counter::get_deallocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 2 ); + VERIFY( Counter::get_destruct_count() == 0 ); +} + +constexpr void +test_assign() +{ + Counter::reset(); + Polymorhic i1(std::in_place_type<Derived>); + const size_t holderSize = Counter::get_allocation_count(); + VERIFY( holderSize >= sizeof(Derived) ); + Counter::reset(); + + i1 = src; + VERIFY( *i1 == *src ); + VERIFY( &*i1 != &*src ); + VERIFY( Counter::get_allocation_count() == holderSize ); + VERIFY( Counter::get_deallocation_count() == holderSize ); + VERIFY( Counter::get_construct_count() == 2 ); + VERIFY( Counter::get_destruct_count() == 1 ); + + auto(std::move(i1)); + Counter::reset(); + + i1 = src; + VERIFY( *i1 == *src ); + VERIFY( &*i1 != &*src ); + VERIFY( Counter::get_allocation_count() == holderSize ); + VERIFY( Counter::get_deallocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 2 ); + VERIFY( Counter::get_destruct_count() == 0 ); +} + +constexpr void +test_valueless() +{ + Polymorhic e(std::in_place_type<Derived>); + auto(std::move(e)); + VERIFY( e.valueless_after_move() ); + + Counter::reset(); + Polymorhic i1(e); + VERIFY( i1.valueless_after_move() ); + VERIFY( Counter::get_allocation_count() == 0 ); + VERIFY( Counter::get_deallocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 0 ); + VERIFY( Counter::get_destruct_count() == 0 ); + + Polymorhic i2(std::allocator_arg, {}, e); + VERIFY( i2.valueless_after_move() ); + VERIFY( Counter::get_allocation_count() == 0 ); + VERIFY( Counter::get_deallocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 0 ); + VERIFY( Counter::get_destruct_count() == 0 ); + + Polymorhic i3(src); + Counter::reset(); + i3 = e; + VERIFY( i3.valueless_after_move() ); + VERIFY( Counter::get_allocation_count() == 0 ); + VERIFY( Counter::get_deallocation_count() >= sizeof(Derived) ); + VERIFY( Counter::get_construct_count() == 0 ); + VERIFY( Counter::get_destruct_count() == 1 ); + + Counter::reset(); + i3 = e; + VERIFY( i3.valueless_after_move() ); + VERIFY( Counter::get_allocation_count() == 0 ); + VERIFY( Counter::get_deallocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 0 ); + VERIFY( Counter::get_destruct_count() == 0 ); +} + +constexpr void +test_all() +{ + test_ctor(); + test_assign(); + test_valueless(); +} + +int main() +{ + test_all(); + + static_assert([] { + test_all(); + return true; + }); +} diff --git a/libstdc++-v3/testsuite/std/memory/polymorphic/copy_alloc.cc b/libstdc++-v3/testsuite/std/memory/polymorphic/copy_alloc.cc new file mode 100644 index 0000000..f41c32e --- /dev/null +++ b/libstdc++-v3/testsuite/std/memory/polymorphic/copy_alloc.cc @@ -0,0 +1,270 @@ +// { dg-do run { target c++26 } } + +#include <memory> +#include <scoped_allocator> +#include <utility> +#include <vector> + +#include <testsuite_hooks.h> +#include <testsuite_allocator.h> + +struct Base { + friend constexpr + bool operator==(const Base& lhs, const Base& rhs) + { return lhs.eq(rhs); } + + virtual constexpr int + get_alloc_personality() const + { return -1; } + +private: + constexpr virtual bool + eq(const Base& other) const = 0; +}; + +template<typename T, typename Allocator> +struct VecDerived : Base, std::vector<T, Allocator> +{ + using VecBase = std::vector<T, Allocator>; + + using VecBase::VecBase; + + constexpr int + get_alloc_personality() const override + { return this->get_allocator().get_personality(); } + +private: + + constexpr bool + eq(const Base& other) const override + { + if (auto op = dynamic_cast<const VecDerived*>(&other)) + return *static_cast<const VecBase*>(this) + == *static_cast<const VecBase*>(op); + return false; + } +}; + +using __gnu_test::propagating_allocator; +using __gnu_test::tracker_allocator; +using Counter = __gnu_test::tracker_allocator_counter; + +template<bool Propagate> +constexpr void +test_ctor() +{ + using PropAlloc = propagating_allocator<int, Propagate>; + using Vector = VecDerived<int, PropAlloc>; + using ScopedAlloc = std::scoped_allocator_adaptor< + propagating_allocator<Vector, Propagate, tracker_allocator<Vector>>, + PropAlloc>; + using Polymorphic = std::polymorphic<Vector, ScopedAlloc>; + + const Polymorphic src(std::allocator_arg, ScopedAlloc{11, 22}, + std::in_place_type<Vector>, {1, 2, 3}); + + Counter::reset(); + Polymorphic i1(src); + VERIFY( *i1 == *src ); + VERIFY( &*i1 != &*src ); + if (Propagate) + { + VERIFY( i1->get_alloc_personality() == 22 ); + VERIFY( i1.get_allocator().get_personality() == 11 ); + } + else + { + VERIFY( i1->get_alloc_personality() == 0 ); + VERIFY( i1.get_allocator().get_personality() == 0 ); + } + VERIFY( Counter::get_allocation_count() >= sizeof(Vector) ); + VERIFY( Counter::get_deallocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 2 ); + VERIFY( Counter::get_destruct_count() == 0 ); + + + Counter::reset(); + Polymorphic i2(std::allocator_arg, ScopedAlloc{33, 44}, src); + VERIFY( *i2 == *src ); + VERIFY( &*i2 != &*src ); + VERIFY( i2->get_alloc_personality() == 44 ); + VERIFY( i2.get_allocator().get_personality() == 33 ); + VERIFY( Counter::get_allocation_count() >= sizeof(Vector) ); + VERIFY( Counter::get_deallocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 2 ); + VERIFY( Counter::get_destruct_count() == 0 ); +} + +template<bool Propagate> +constexpr void +test_assign() +{ + using PropAlloc = propagating_allocator<int, Propagate>; + using Vector = VecDerived<int, PropAlloc>; + using ScopedAlloc = std::scoped_allocator_adaptor< + propagating_allocator<Vector, Propagate, tracker_allocator<Vector>>, + PropAlloc>; + using Polymorphic = std::polymorphic<Vector, ScopedAlloc>; + + const Polymorphic src(std::allocator_arg, ScopedAlloc{11, 22}, + std::in_place_type<Vector>, {1, 2, 3}); + + Counter::reset(); + Polymorphic i1(std::allocator_arg, ScopedAlloc{11, 22}, + std::in_place_type<Vector>); + const size_t holderSize = Counter::get_allocation_count(); + VERIFY( holderSize >= sizeof(Vector) ); + Counter::reset(); + + i1 = src; + VERIFY( *i1 == *src ); + VERIFY( &*i1 != &*src ); + VERIFY( i1->get_alloc_personality() == 22 ); + VERIFY( i1.get_allocator().get_personality() == 11 ); + VERIFY( Counter::get_allocation_count() == holderSize ); + VERIFY( Counter::get_deallocation_count() == holderSize ); + VERIFY( Counter::get_construct_count() == 2 ); + VERIFY( Counter::get_destruct_count() == 1 ); + + Polymorphic i2(std::allocator_arg, ScopedAlloc{33, 44}); + Counter::reset(); + + i2 = src; + VERIFY( *i2 == *src ); + VERIFY( &*i2 != &*src ); + if (Propagate) + { + VERIFY( i2->get_alloc_personality() == 22 ); + VERIFY( i2.get_allocator().get_personality() == 11 ); + } + else + { + VERIFY( i2->get_alloc_personality() == 44 ); + VERIFY( i2.get_allocator().get_personality() == 33 ); + } + VERIFY( Counter::get_allocation_count() == holderSize ); + VERIFY( Counter::get_deallocation_count() == holderSize ); + VERIFY( Counter::get_construct_count() == 2 ); + VERIFY( Counter::get_destruct_count() == 1 ); + + Polymorphic i3(std::allocator_arg, ScopedAlloc{11, 22}); + auto(std::move(i3)); + Counter::reset(); + + i3 = src; + VERIFY( *i3 == *src ); + VERIFY( &*i3 != &*src ); + VERIFY( i3->get_alloc_personality() == 22 ); + VERIFY( i3.get_allocator().get_personality() == 11 ); + VERIFY( Counter::get_allocation_count() == holderSize ); + VERIFY( Counter::get_deallocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 2 ); + VERIFY( Counter::get_destruct_count() == 0 ); + + Polymorphic i4(std::allocator_arg, ScopedAlloc{33, 44}); + auto(std::move(i4)); + Counter::reset(); + + i4 = src; + VERIFY( *i4 == *src ); + VERIFY( &*i4 != &*src ); + if (Propagate) + { + VERIFY( i4->get_alloc_personality() == 22 ); + VERIFY( i4.get_allocator().get_personality() == 11 ); + } + else + { + VERIFY( i4->get_alloc_personality() == 44 ); + VERIFY( i4.get_allocator().get_personality() == 33 ); + } + VERIFY( Counter::get_allocation_count() == holderSize ); + VERIFY( Counter::get_deallocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 2 ); + VERIFY( Counter::get_destruct_count() == 0 ); +} + +template<bool Propagate> +constexpr void +test_valueless() +{ + using PropAlloc = propagating_allocator<int, Propagate>; + using Vector = VecDerived<int, PropAlloc>; + using ScopedAlloc = std::scoped_allocator_adaptor< + propagating_allocator<Vector, Propagate, tracker_allocator<Vector>>, + PropAlloc>; + using Polymorphic = std::polymorphic<Vector, ScopedAlloc>; + + Polymorphic e(std::allocator_arg, ScopedAlloc{11, 22}, + std::in_place_type<Vector>); + auto(std::move(e)); + VERIFY( e.valueless_after_move() ); + + Counter::reset(); + Polymorphic i1(e); + VERIFY( i1.valueless_after_move() ); + if (Propagate) + VERIFY( i1.get_allocator().get_personality() == 11 ); + else + VERIFY( i1.get_allocator().get_personality() == 0 ); + VERIFY( Counter::get_allocation_count() == 0 ); + VERIFY( Counter::get_deallocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 0 ); + VERIFY( Counter::get_destruct_count() == 0 ); + + Counter::reset(); + Polymorphic i2(std::allocator_arg, ScopedAlloc{33, 44}, e); + VERIFY( i2.valueless_after_move() ); + VERIFY( i2.get_allocator().get_personality() == 33 ); + VERIFY( Counter::get_allocation_count() == 0 ); + VERIFY( Counter::get_deallocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 0 ); + VERIFY( Counter::get_destruct_count() == 0 ); + + Polymorphic i3(std::allocator_arg, ScopedAlloc{33, 44}); + Counter::reset(); + + i3 = e; + VERIFY( i3.valueless_after_move() ); + if (Propagate) + VERIFY( i3.get_allocator().get_personality() == 11 ); + else + VERIFY( i3.get_allocator().get_personality() == 33 ); + VERIFY( Counter::get_allocation_count() == 0 ); + VERIFY( Counter::get_deallocation_count() >= sizeof(Vector) ); + VERIFY( Counter::get_construct_count() == 0 ); + VERIFY( Counter::get_destruct_count() == 1 ); + + Counter::reset(); + i2 = e; + VERIFY( i2.valueless_after_move() ); + if (Propagate) + VERIFY( i2.get_allocator().get_personality() == 11 ); + else + VERIFY( i2.get_allocator().get_personality() == 33 ); + VERIFY( Counter::get_allocation_count() == 0 ); + VERIFY( Counter::get_deallocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 0 ); + VERIFY( Counter::get_destruct_count() == 0 ); +} + +template<bool Propagate> +constexpr void +test_all() +{ + test_ctor<Propagate>(); + test_assign<Propagate>(); + test_valueless<Propagate>(); +} + +int main() +{ + test_all<true>(); + test_all<false>(); + + static_assert([] { + test_all<true>(); + test_all<false>(); + return true; + }); +} diff --git a/libstdc++-v3/testsuite/std/memory/polymorphic/ctor.cc b/libstdc++-v3/testsuite/std/memory/polymorphic/ctor.cc new file mode 100644 index 0000000..bb4c947 --- /dev/null +++ b/libstdc++-v3/testsuite/std/memory/polymorphic/ctor.cc @@ -0,0 +1,190 @@ +// { dg-do run { target c++26 } } + +#include <memory> +#include <scoped_allocator> +#include <utility> +#include <vector> + +#ifndef __cpp_lib_polymorphic +# error __cpp_lib_polymorphic feature test macro missing in <memory> +#elif __cpp_lib_polymorphic != 202502 +# error __cpp_lib_polymorphic feature test macro has wrong value in <memory> +#endif + +#include <testsuite_hooks.h> +#include <testsuite_allocator.h> + +using __gnu_test::uneq_allocator; +using UneqAlloc = uneq_allocator<int>; +using ScopedAlloc = std::scoped_allocator_adaptor< + uneq_allocator<std::vector<int, UneqAlloc>>, + UneqAlloc>; + +struct Obj +{ + int i; + char c[2]; +}; + +constexpr void +test_default_ctor() +{ + using __gnu_test::default_init_allocator; + + std::polymorphic<Obj, default_init_allocator<Obj>> i1; + default_init_allocator<int> a{}; + + // The contained object and the allocator should be value-initialized. + VERIFY( i1->i == 0 ); + VERIFY( i1->c[0] == 0 ); + VERIFY( i1->c[1] == 0 ); + VERIFY( i1.get_allocator() == a ); + + a.state = 5; + // Allocator-extended default constructor: + std::polymorphic<Obj, default_init_allocator<Obj>> i2(std::allocator_arg, a); + VERIFY( i2.get_allocator() == a ); + + // Object is constructed using allocator-aware constructor. + std::polymorphic<std::vector<int, UneqAlloc>, ScopedAlloc> + i3(std::allocator_arg, ScopedAlloc(11, 22)); + VERIFY( i3->empty() ); + VERIFY( i3->get_allocator().get_personality() == 22 ); + VERIFY( i3.get_allocator().get_personality() == 11 ); +} + +constexpr void +test_forwarding_ctor() +{ + Obj obj{1, {'2', '3'}}; + auto verify = [](std::polymorphic<Obj> const& i) + { + VERIFY( i->i == 1 ); + VERIFY( i->c[0] == '2' ); + VERIFY( i->c[1] == '3' ); + }; + + std::polymorphic<Obj> i1(std::as_const(obj)); + verify(i1); + std::polymorphic<Obj> i2(std::move(std::as_const(obj))); + verify(i2); + std::polymorphic<Obj> i3(obj); + verify(i3); + std::polymorphic<Obj> i4(std::move(obj)); + verify(i4); + + std::polymorphic<Obj> i5({1, {'2', '3'}}); + verify(i5); + + std::vector<int, UneqAlloc> v{1, 2, 3, 4, 5}; + // Object is constructed using allocator-aware constructor. + std::polymorphic<std::vector<int, UneqAlloc>, ScopedAlloc> + i7(std::allocator_arg, ScopedAlloc(11, 22), v); + VERIFY( i7->size() == 5 ); + VERIFY( v.size() == 5 ); + VERIFY( i7->get_allocator().get_personality() == 22 ); + VERIFY( i7.get_allocator().get_personality() == 11 ); + + std::polymorphic<std::vector<int, UneqAlloc>, ScopedAlloc> + i8(std::allocator_arg, ScopedAlloc(11, 22), std::move(v)); + VERIFY( i8->size() == 5 ); + VERIFY( v.size() == 0 ); + VERIFY( i8->get_allocator().get_personality() == 22 ); + VERIFY( i8.get_allocator().get_personality() == 11 ); +} + +constexpr void +test_inplace_ctor() +{ + std::polymorphic<Obj> i1(std::in_place_type<Obj>); + VERIFY( i1->i == 0 ); + VERIFY( i1->c[0] == 0 ); + VERIFY( i1->c[1] == 0 ); + + std::polymorphic<Obj> i2(std::in_place_type<Obj>, 10); + VERIFY( i2->i == 10 ); + VERIFY( i2->c[0] == 0 ); + VERIFY( i2->c[1] == 0 ); + + std::polymorphic<Obj, uneq_allocator<Obj>> + i3(std::allocator_arg, 42, std::in_place_type<Obj>); + VERIFY( i3->i == 0 ); + VERIFY( i3->c[0] == 0 ); + VERIFY( i3->c[1] == 0 ); + VERIFY( i3.get_allocator().get_personality() == 42 ); + + std::polymorphic<Obj, uneq_allocator<Obj>> + i4(std::allocator_arg, 42, std::in_place_type<Obj>, 10); + VERIFY( i4->i == 10 ); + VERIFY( i4->c[0] == 0 ); + VERIFY( i4->c[1] == 0 ); + VERIFY( i4.get_allocator().get_personality() == 42 ); + + std::polymorphic<std::vector<int>> + i5(std::in_place_type<std::vector<int>>); + VERIFY( i5->size() == 0 ); + + std::polymorphic<std::vector<int>> + i6(std::in_place_type<std::vector<int>>, 5, 13); + VERIFY( i6->size() == 5 ); + VERIFY( i6->at(0) == 13 ); + + std::polymorphic<std::vector<int>> + i7(std::in_place_type<std::vector<int>>, {1, 2, 3, 4}); + VERIFY( i7->size() == 4 ); + VERIFY( i7->at(2) == 3 ); + + std::polymorphic<std::vector<int, UneqAlloc>> + i8(std::in_place_type<std::vector<int, UneqAlloc>>, UneqAlloc{42}); + VERIFY( i8->size() == 0 ); + VERIFY( i8->get_allocator().get_personality() == 42 ); + + std::polymorphic<std::vector<int, UneqAlloc>> + i9(std::in_place_type<std::vector<int, UneqAlloc>>, 5, 13, UneqAlloc{42}); + VERIFY( i9->size() == 5 ); + VERIFY( i9->at(0) == 13 ); + VERIFY( i9->get_allocator().get_personality() == 42 ); + + std::polymorphic<std::vector<int, UneqAlloc>> + i10(std::in_place_type<std::vector<int, UneqAlloc>>, {1, 2, 3, 4}, UneqAlloc{42}); + VERIFY( i10->size() == 4 ); + VERIFY( i10->at(2) == 3 ); + VERIFY( i10->get_allocator().get_personality() == 42 ); + + std::polymorphic<std::vector<int, UneqAlloc>, ScopedAlloc> + i14(std::allocator_arg, ScopedAlloc(11, 22), + std::in_place_type<std::vector<int, UneqAlloc>>); + VERIFY( i14->size() == 0 ); + VERIFY( i14->get_allocator().get_personality() == 22 ); + VERIFY( i14.get_allocator().get_personality() == 11 ); + + std::polymorphic<std::vector<int, UneqAlloc>, ScopedAlloc> + i15(std::allocator_arg, ScopedAlloc(11, 22), + std::in_place_type<std::vector<int, UneqAlloc>>, 5, 13); + VERIFY( i15->size() == 5 ); + VERIFY( i15->at(0) == 13 ); + VERIFY( i15->get_allocator().get_personality() == 22 ); + VERIFY( i15.get_allocator().get_personality() == 11 ); + + std::polymorphic<std::vector<int, UneqAlloc>, ScopedAlloc> + i16(std::allocator_arg, ScopedAlloc(11, 22), + std::in_place_type<std::vector<int, UneqAlloc>>, {1, 2, 3, 4}); + VERIFY( i16->size() == 4 ); + VERIFY( i16->at(2) == 3 ); + VERIFY( i16->get_allocator().get_personality() == 22 ); + VERIFY( i16.get_allocator().get_personality() == 11 ); +} + +int main() +{ + test_default_ctor(); + test_forwarding_ctor(); + test_inplace_ctor(); + + static_assert([] { + test_default_ctor(); + test_forwarding_ctor(); + test_inplace_ctor(); + return true; + }); +} diff --git a/libstdc++-v3/testsuite/std/memory/polymorphic/ctor_poly.cc b/libstdc++-v3/testsuite/std/memory/polymorphic/ctor_poly.cc new file mode 100644 index 0000000..03519a1 --- /dev/null +++ b/libstdc++-v3/testsuite/std/memory/polymorphic/ctor_poly.cc @@ -0,0 +1,220 @@ +// { dg-do run { target c++26 } } + +#include <memory> +#include <scoped_allocator> +#include <utility> +#include <vector> + +#ifndef __cpp_lib_polymorphic +# error __cpp_lib_polymorphic feature test macro missing in <memory> +#elif __cpp_lib_polymorphic != 202502 +# error __cpp_lib_polymorphic feature test macro has wrong value in <memory> +#endif + +#include <testsuite_hooks.h> +#include <testsuite_allocator.h> + +struct Base { + friend constexpr + bool operator==(const Base& lhs, const Base& rhs) + { return lhs.eq(rhs); } + + virtual constexpr int + get_personality() const + { return -1; } + +private: + constexpr virtual bool + eq(const Base& other) const + { return true; } +}; + +struct ObjDerived : Base +{ + constexpr ObjDerived() + : x(0), y(0), z(0) + { } + + constexpr ObjDerived(int a, int b, int c) + : x(a), y(b), z(c) + { } + + virtual constexpr int + get_personality() const + { return -2; } + +private: + constexpr bool + eq(const Base& other) const override + { + if (auto op = dynamic_cast<const ObjDerived*>(&other)) + return this->x == op->x && this->y == op->y && this->z == op->z; + return false; + } + + int x; + int y; + int z; +}; + +template<typename T, typename Allocator> +struct VecDerived : Base, std::vector<T, Allocator> +{ + using VecBase = std::vector<T, Allocator>; + + using VecBase::VecBase; + + constexpr int + get_personality() const override + { return this->get_allocator().get_personality(); } + +private: + + constexpr bool + eq(const Base& other) const override + { + if (auto op = dynamic_cast<const VecDerived*>(&other)) + return *static_cast<const VecBase*>(this) + == *static_cast<const VecBase*>(op); + return false; + } +}; + +using __gnu_test::uneq_allocator; +using UneqAlloc = uneq_allocator<int>; +using ScopedAlloc = std::scoped_allocator_adaptor< + uneq_allocator<Base>, + UneqAlloc>; + +constexpr void +test_default_ctor() +{ + using __gnu_test::default_init_allocator; + + std::polymorphic<Base, default_init_allocator<Base>> i1; + default_init_allocator<int> a{}; + + // The contained object and the allocator should be value-initialized. + VERIFY( *i1 == Base() ); + VERIFY( i1->get_personality() == -1 ); + VERIFY( i1.get_allocator() == a ); + + a.state = 5; + // Allocator-extended default constructor: + std::polymorphic<Base, default_init_allocator<Base>> i2(std::allocator_arg, a); + VERIFY( *i1 == Base() ); + VERIFY( i1->get_personality() == -1 ); +} + +constexpr void +test_forwarding_ctor() +{ + const ObjDerived src(1, 2, 3); + + std::polymorphic<Base> i1(src); + VERIFY( *i1 == src ); + VERIFY( i1->get_personality() == -2 ); + std::polymorphic<Base> i2(std::move(src)); + VERIFY( *i2 == src ); + VERIFY( i2->get_personality() == -2 ); + + ObjDerived obj = src; + std::polymorphic<Base> i3(obj); + VERIFY( *i3 == src ); + VERIFY( i3->get_personality() == -2 ); + std::polymorphic<Base> i4(std::move(obj)); + VERIFY( *i4 == src ); + VERIFY( i4->get_personality() == -2 ); + + const VecDerived<int, UneqAlloc> v{1, 2, 3, 4, 5}; + // Object is constructed using allocator-aware constructor. + std::polymorphic<Base, ScopedAlloc> + i5(std::allocator_arg, ScopedAlloc(11, 22), v); + VERIFY( *i5 == v ); + VERIFY( i5->get_personality() == 22 ); + VERIFY( i5.get_allocator().get_personality() == 11 ); + + std::polymorphic<Base, ScopedAlloc> + i6(std::allocator_arg, ScopedAlloc(11, 22), auto(v)); + VERIFY( *i6 == v ); + VERIFY( i6->get_personality() == 22 ); + VERIFY( i6.get_allocator().get_personality() == 11 ); +} + +constexpr void +test_inplace_ctor() +{ + std::polymorphic<Base> i1(std::in_place_type<ObjDerived>); + VERIFY( *i1 == ObjDerived() ); + VERIFY( i1->get_personality() == -2 ); + + std::polymorphic<Base> i2(std::in_place_type<ObjDerived>, 10, 20, 30); + VERIFY( *i2 == ObjDerived(10, 20, 30) ); + VERIFY( i2->get_personality() == -2 ); + + std::polymorphic<Base, uneq_allocator<Base>> + i3(std::allocator_arg, 42, std::in_place_type<ObjDerived>); + VERIFY( *i3 == ObjDerived() ); + VERIFY( i3->get_personality() == -2 ); + VERIFY( i3.get_allocator().get_personality() == 42 ); + + std::polymorphic<Base, uneq_allocator<Base>> + i4(std::allocator_arg, 42, std::in_place_type<ObjDerived>, 10, 20, 30); + VERIFY( *i4 == ObjDerived(10, 20, 30) ); + VERIFY( i4->get_personality() == -2 ); + VERIFY( i4.get_allocator().get_personality() == 42 ); + + const VecDerived<int, UneqAlloc> ze; + const VecDerived<int, UneqAlloc> fe(5, 13); + const VecDerived<int, UneqAlloc> il{1, 2, 3 ,4}; + + std::polymorphic<Base> + i5(std::in_place_type<VecDerived<int, UneqAlloc>>, UneqAlloc{42}); + VERIFY( *i5 == ze ); + VERIFY( i5->get_personality() == 42 ); + + std::polymorphic<Base> + i6(std::in_place_type<VecDerived<int, UneqAlloc>>, 5, 13, UneqAlloc{42}); + VERIFY( *i6 == fe ); + VERIFY( i6->get_personality() == 42 ); + + std::polymorphic<Base> + i7(std::in_place_type<VecDerived<int, UneqAlloc>>, {1, 2, 3, 4}, UneqAlloc{42}); + VERIFY( *i7 == il ); + VERIFY( i7->get_personality() == 42 ); + + std::polymorphic<Base, ScopedAlloc> + i8(std::allocator_arg, ScopedAlloc(11, 22), + std::in_place_type<VecDerived<int, UneqAlloc>>); + VERIFY( *i8 == ze ); + VERIFY( i8->get_personality() == 22 ); + VERIFY( i8.get_allocator().get_personality() == 11 ); + + std::polymorphic<Base, ScopedAlloc> + i9(std::allocator_arg, ScopedAlloc(11, 22), + std::in_place_type<VecDerived<int, UneqAlloc>>, 5, 13); + VERIFY( *i9 == fe ); + VERIFY( i9->get_personality() == 22 ); + VERIFY( i9.get_allocator().get_personality() == 11 ); + + std::polymorphic<Base, ScopedAlloc> + i10(std::allocator_arg, ScopedAlloc(11, 22), + std::in_place_type<VecDerived<int, UneqAlloc>>, {1, 2, 3, 4}); + VERIFY( *i10 == il ); + VERIFY( i10->get_personality() == 22 ); + VERIFY( i10.get_allocator().get_personality() == 11 ); +} + +int main() +{ + test_default_ctor(); + test_forwarding_ctor(); + test_inplace_ctor(); + + static_assert([] { + test_default_ctor(); + test_forwarding_ctor(); + test_inplace_ctor(); + return true; + }); +} diff --git a/libstdc++-v3/testsuite/std/memory/polymorphic/incomplete.cc b/libstdc++-v3/testsuite/std/memory/polymorphic/incomplete.cc new file mode 100644 index 0000000..e5dd78f --- /dev/null +++ b/libstdc++-v3/testsuite/std/memory/polymorphic/incomplete.cc @@ -0,0 +1,13 @@ +// { dg-do compile { target c++26 } } + +#include <memory> + +struct Incomplete; + +std::polymorphic<Incomplete>* +test_move(std::polymorphic<Incomplete>& i1, std::polymorphic<Incomplete>& i2) +{ + i1 = std::move(i2); + swap(i1, i2); + return new std::polymorphic<Incomplete>(std::move(i1)); +} diff --git a/libstdc++-v3/testsuite/std/memory/polymorphic/invalid_neg.cc b/libstdc++-v3/testsuite/std/memory/polymorphic/invalid_neg.cc new file mode 100644 index 0000000..a01af3f --- /dev/null +++ b/libstdc++-v3/testsuite/std/memory/polymorphic/invalid_neg.cc @@ -0,0 +1,28 @@ +// { dg-do compile { target c++26 } } + +#include <memory> + +// In every specialization polymorphic<T, Allocator>, if the type +// allocator_traits<Allocator>::value_type is not the same type as T, +// the program is ill-formed. +using T1 = std::polymorphic<int, std::allocator<long>>::value_type; // { dg-error "here" } + +// A program that instantiates the definition of the template +// polymorphic<T, Allocator> with a type for the T parameter that is +// a non-object type, an array type, in_place_t, +// a specialization of in_place_type_t, or a cv-qualified type is ill-formed. + +using T2 = std::polymorphic<int&>::value_type; // { dg-error "here" } + +using T3 = std::polymorphic<int[1]>::value_type; // { dg-error "here" } + +using T4 = std::polymorphic<std::in_place_t>::value_type; // { dg-error "here" } + +using T5 = std::polymorphic<std::in_place_type_t<int>>::value_type; // { dg-error "here" } + +using T6 = std::polymorphic<const int>::value_type; // { dg-error "here" } + +using T7 = std::polymorphic<volatile int>::value_type; // { dg-error "here" } + +// { dg-error "static assertion failed" "" { target *-*-* } 0 } +// { dg-prune-output "forming pointer to reference" } diff --git a/libstdc++-v3/testsuite/std/memory/polymorphic/move.cc b/libstdc++-v3/testsuite/std/memory/polymorphic/move.cc new file mode 100644 index 0000000..c802159 --- /dev/null +++ b/libstdc++-v3/testsuite/std/memory/polymorphic/move.cc @@ -0,0 +1,177 @@ +// { dg-do run { target c++26 } } + +#include <memory> +#include <scoped_allocator> +#include <utility> +#include <vector> +#include <optional> + +#include <testsuite_hooks.h> +#include <testsuite_allocator.h> + +struct Base { + friend constexpr + bool operator==(const Base& lhs, const Base& rhs) + { return lhs.eq(rhs); } + +private: + constexpr virtual bool + eq(const Base& other) const = 0; +}; + +struct Derived : Base +{ + constexpr Derived() + : x(0), y(0), z(0) + { } + + constexpr Derived(int a, int b, int c) + : x(a), y(b), z(c) + { } + +private: + constexpr bool + eq(const Base& other) const override + { + if (auto op = dynamic_cast<const Derived*>(&other)) + return this->x == op->x && this->y == op->y && this->z == op->z; + return false; + } + + int x; + int y; + int z; +}; + +using __gnu_test::tracker_allocator; +using Counter = __gnu_test::tracker_allocator_counter; +using Polymorphic = std::polymorphic<Base, tracker_allocator<Base>>; +const Polymorphic val(std::in_place_type<Derived>, 1, 2, 3); + +constexpr void +verifyNoAllocations() +{ + VERIFY( Counter::get_allocation_count() == 0 ); + VERIFY( Counter::get_deallocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 0 ); + VERIFY( Counter::get_destruct_count() == 0 ); +} + +constexpr void +test_ctor() +{ + std::optional<Polymorphic> src; + auto make = [&src] -> Polymorphic&& { + src.emplace(val); + Counter::reset(); + return std::move(*src); + }; + + Polymorphic i1(make()); + VERIFY( src->valueless_after_move() ); + VERIFY( *i1 == *val ); + verifyNoAllocations(); + + Polymorphic i2(std::allocator_arg, {}, make()); + VERIFY( src->valueless_after_move() ); + VERIFY( *i2 == *val ); + verifyNoAllocations(); +} + +constexpr void +test_assign() +{ + std::optional<Polymorphic> src; + auto make = [&src] -> Polymorphic&& { + src.emplace(val); + Counter::reset(); + return std::move(*src); + }; + + Polymorphic i1(std::in_place_type<Derived>); + + i1 = make(); + VERIFY( src->valueless_after_move() ); + VERIFY( *i1 == *val ); + VERIFY( Counter::get_allocation_count() == 0 ); + VERIFY( Counter::get_deallocation_count() >= sizeof(Derived) ); + VERIFY( Counter::get_construct_count() == 0 ); + VERIFY( Counter::get_destruct_count() == 1 ); + + auto(std::move(i1)); + i1 = make(); + VERIFY( *i1 == *val ); + VERIFY( src->valueless_after_move() ); + verifyNoAllocations(); +} + +constexpr void +test_swap() +{ + const Polymorphic val1(std::in_place_type<Derived>, 1, 2, 3); + const Polymorphic val2(std::in_place_type<Derived>, 2, 4, 6); + + Polymorphic i1(val1); + Polymorphic i2(val2); + Counter::reset(); + i1.swap(i2); + VERIFY( *i2 == *val1 ); + VERIFY( *i1 == *val2 ); + verifyNoAllocations(); + + auto(std::move(i1)); + + Counter::reset(); + i1.swap(i2); + VERIFY( *i1 == *val1 ); + VERIFY( i2.valueless_after_move() ); + verifyNoAllocations(); +} + +constexpr void +test_valueless() +{ + auto e = [] { + Polymorphic res(std::in_place_type<Derived>); + auto(std::move(res)); + Counter::reset(); + return res; + }; + + Polymorphic i1(e()); + VERIFY( i1.valueless_after_move() ); + verifyNoAllocations(); + + Polymorphic i2(std::allocator_arg, {}, e()); + VERIFY( i2.valueless_after_move() ); + verifyNoAllocations(); + + Polymorphic i3(val); + i3 = e(); + VERIFY( Counter::get_allocation_count() == 0 ); + VERIFY( Counter::get_deallocation_count() >= sizeof(Derived) ); + VERIFY( Counter::get_construct_count() == 0 ); + VERIFY( Counter::get_destruct_count() == 1 ); + + i3 = e(); + verifyNoAllocations(); +} + +constexpr void +test_all() +{ + test_ctor(); + test_assign(); + test_swap(); + test_valueless(); +} + +int main() +{ + test_all(); + + static_assert([] { + test_all(); + return true; + }); +} diff --git a/libstdc++-v3/testsuite/std/memory/polymorphic/move_alloc.cc b/libstdc++-v3/testsuite/std/memory/polymorphic/move_alloc.cc new file mode 100644 index 0000000..09afedb --- /dev/null +++ b/libstdc++-v3/testsuite/std/memory/polymorphic/move_alloc.cc @@ -0,0 +1,339 @@ +// { dg-do run { target c++26 } } + +#include <memory> +#include <scoped_allocator> +#include <utility> +#include <vector> +#include <optional> + +#include <testsuite_hooks.h> +#include <testsuite_allocator.h> + +struct Base { + friend constexpr + bool operator==(const Base& lhs, const Base& rhs) + { return lhs.eq(rhs); } + + virtual constexpr int + get_alloc_personality() const + { return -1; } + +private: + constexpr virtual bool + eq(const Base& other) const = 0; +}; + +template<typename T, typename Allocator> +struct VecDerived : Base, std::vector<T, Allocator> +{ + using VecBase = std::vector<T, Allocator>; + + using VecBase::VecBase; + + constexpr int + get_alloc_personality() const override + { return this->get_allocator().get_personality(); } + +private: + + constexpr bool + eq(const Base& other) const override + { + if (auto op = dynamic_cast<const VecDerived*>(&other)) + return *static_cast<const VecBase*>(this) + == *static_cast<const VecBase*>(op); + return false; + } +}; + +using __gnu_test::propagating_allocator; +using __gnu_test::tracker_allocator; +using Counter = __gnu_test::tracker_allocator_counter; + +constexpr void +verifyNoAllocations() +{ + VERIFY( Counter::get_allocation_count() == 0 ); + VERIFY( Counter::get_deallocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 0 ); + VERIFY( Counter::get_destruct_count() == 0 ); +} + +template<bool Propagate> +constexpr void +test_ctor() +{ + using PropAlloc = propagating_allocator<int, Propagate>; + using Vector = VecDerived<int, PropAlloc>; + using ScopedAlloc = std::scoped_allocator_adaptor< + propagating_allocator<Vector, Propagate, tracker_allocator<Vector>>, + PropAlloc>; + using Polymorphic = std::polymorphic<Vector, ScopedAlloc>; + + const Polymorphic val(std::in_place_type<Vector>, {1, 2, 3}); + std::optional<Polymorphic> src; + auto make = [&val, &src] -> Polymorphic&& { + src.emplace(std::allocator_arg, ScopedAlloc{11, 22}, val); + Counter::reset(); + return std::move(*src); + }; + + Polymorphic i1(make()); + VERIFY( src->valueless_after_move() ); + VERIFY( *i1 == *val ); + VERIFY( i1->get_alloc_personality() == 22 ); + VERIFY( i1.get_allocator().get_personality() == 11 ); + verifyNoAllocations(); + + Polymorphic i2(std::allocator_arg, ScopedAlloc{11, 22}, make()); + VERIFY( src->valueless_after_move() ); + VERIFY( *i2 == *val ); + VERIFY( i2->get_alloc_personality() == 22 ); + VERIFY( i2.get_allocator().get_personality() == 11 ); + verifyNoAllocations(); + + Polymorphic i3(std::allocator_arg, ScopedAlloc{33, 44}, make()); + // We move-from contained object + VERIFY( !src->valueless_after_move() ); + VERIFY( *i3 == *val ); + VERIFY( i3->get_alloc_personality() == 44 ); + VERIFY( i3.get_allocator().get_personality() == 33 ); + VERIFY( Counter::get_allocation_count() >= sizeof(Vector) ); + VERIFY( Counter::get_deallocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 2 ); + VERIFY( Counter::get_destruct_count() == 0 ); +} + +template<bool Propagate> +constexpr void +test_assign() +{ + using PropAlloc = propagating_allocator<int, Propagate>; + using Vector = VecDerived<int, PropAlloc>; + using ScopedAlloc = std::scoped_allocator_adaptor< + propagating_allocator<Vector, Propagate, tracker_allocator<Vector>>, + PropAlloc>; + using Polymorphic = std::polymorphic<Vector, ScopedAlloc>; + + const Polymorphic val(std::in_place_type<Vector>, {1, 2, 3}); + std::optional<Polymorphic> src; + auto make = [&val, &src] -> Polymorphic&& { + src.emplace(std::allocator_arg, ScopedAlloc{11, 22}, val); + Counter::reset(); + return std::move(*src); + }; + + Counter::reset(); + Polymorphic i1(std::allocator_arg, ScopedAlloc{11, 22}); + const std::size_t holderSize = Counter::get_allocation_count(); + VERIFY( holderSize >= sizeof(Vector) ); + + i1 = make(); + VERIFY( src->valueless_after_move() ); + VERIFY( *i1 == *val ); + VERIFY( i1->get_alloc_personality() == 22 ); + VERIFY( i1.get_allocator().get_personality() == 11 ); + VERIFY( Counter::get_allocation_count() == 0 ); + VERIFY( Counter::get_deallocation_count() == holderSize ); + VERIFY( Counter::get_construct_count() == 0 ); + VERIFY( Counter::get_destruct_count() == 1 ); + + Polymorphic i2(std::allocator_arg, ScopedAlloc{33, 44}); + + i2 = make(); + VERIFY( *i2 == *val ); + if (Propagate) + { + VERIFY( src->valueless_after_move() ); + VERIFY( i2->get_alloc_personality() == 22 ); + VERIFY( i2.get_allocator().get_personality() == 11 ); + VERIFY( Counter::get_allocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 0 ); + } + else + { + // We allocate new holder and move-from contained object + VERIFY( !src->valueless_after_move() ); + VERIFY( i2->get_alloc_personality() == 44 ); + VERIFY( i2.get_allocator().get_personality() == 33 ); + VERIFY( Counter::get_allocation_count() == holderSize ); + VERIFY( Counter::get_construct_count() == 2 ); + } + VERIFY( Counter::get_deallocation_count() == holderSize ); + VERIFY( Counter::get_destruct_count() == 1 ); + + Polymorphic i3(std::allocator_arg, ScopedAlloc{11, 22}, + std::in_place_type<Vector>); + auto(std::move(i3)); + + i3 = make(); + VERIFY( *i3 == *val ); + VERIFY( src->valueless_after_move() ); + VERIFY( i3->get_alloc_personality() == 22 ); + VERIFY( i3.get_allocator().get_personality() == 11 ); + verifyNoAllocations(); + + Polymorphic i4(std::allocator_arg, ScopedAlloc{33, 44}, + std::in_place_type<Vector>); + auto(std::move(i4)); + + i4 = make(); + VERIFY( *i4 == *val ); + if (Propagate) + { + VERIFY( src->valueless_after_move() ); + VERIFY( i4->get_alloc_personality() == 22 ); + VERIFY( i4.get_allocator().get_personality() == 11 ); + VERIFY( Counter::get_allocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 0 ); + } + else + { + // We allocate new holder and move-from contained object + VERIFY( !src->valueless_after_move() ); + VERIFY( i4->get_alloc_personality() == 44 ); + VERIFY( i4.get_allocator().get_personality() == 33 ); + VERIFY( Counter::get_allocation_count() == holderSize ); + VERIFY( Counter::get_construct_count() == 2 ); + } + VERIFY( Counter::get_deallocation_count() == 0 ); + VERIFY( Counter::get_destruct_count() == 0 ); +} + +template<bool Propagate> +constexpr void +test_swap() +{ + using PropAlloc = propagating_allocator<int, Propagate>; + using Vector = VecDerived<int, PropAlloc>; + using ScopedAlloc = std::scoped_allocator_adaptor< + propagating_allocator<Vector, Propagate, tracker_allocator<Vector>>, + PropAlloc>; + using Polymorphic = std::polymorphic<Vector, ScopedAlloc>; + + const Polymorphic val1(std::in_place_type<Vector>, {1, 2, 3}); + const Polymorphic val2(std::in_place_type<Vector>, {2, 4, 6}); + + Polymorphic i1(std::allocator_arg, ScopedAlloc{11, 22}, val1); + Polymorphic i2(std::allocator_arg, ScopedAlloc{11, 22}, val2); + Counter::reset(); + i1.swap(i2); + VERIFY( *i2 == *val1 ); + VERIFY( *i1 == *val2 ); + verifyNoAllocations(); + + auto(std::move(i1)); + + Counter::reset(); + i1.swap(i2); + VERIFY( *i1 == *val1 ); + VERIFY( i2.valueless_after_move() ); + verifyNoAllocations(); + + if (!Propagate) + return; + + Polymorphic i3(std::allocator_arg, ScopedAlloc{33, 44}, val2); + Counter::reset(); + i1.swap(i3); + VERIFY( *i1 == *val2 ); + VERIFY( i1->get_alloc_personality() == 44 ); + VERIFY( i1.get_allocator().get_personality() == 33 ); + VERIFY( *i3 == *val1 ); + VERIFY( i3->get_alloc_personality() == 22 ); + VERIFY( i3.get_allocator().get_personality() == 11 ); + verifyNoAllocations(); + + i1.swap(i2); + VERIFY( i1.valueless_after_move() ); + VERIFY( i1.get_allocator().get_personality() == 11 ); + VERIFY( *i2 == *val2 ); + VERIFY( i2->get_alloc_personality() == 44 ); + VERIFY( i2.get_allocator().get_personality() == 33 ); + verifyNoAllocations(); +} + +template<bool Propagate> +constexpr void +test_valueless() +{ + using PropAlloc = propagating_allocator<int, Propagate>; + using Vector = VecDerived<int, PropAlloc>; + using ScopedAlloc = std::scoped_allocator_adaptor< + propagating_allocator<Vector, Propagate, tracker_allocator<Vector>>, + PropAlloc>; + using Polymorphic = std::polymorphic<Vector, ScopedAlloc>; + + auto e = [] { + Polymorphic res(std::allocator_arg, ScopedAlloc{11, 22}, + std::in_place_type<Vector>); + auto(std::move(res)); + Counter::reset(); + return res; + }; + + Polymorphic i1(e()); + VERIFY( i1.valueless_after_move() ); + VERIFY( i1.get_allocator().get_personality() == 11 ); + verifyNoAllocations(); + + Polymorphic i2(std::allocator_arg, ScopedAlloc{33, 44}, e()); + VERIFY( i2.valueless_after_move() ); + VERIFY( i2.get_allocator().get_personality() == 33 ); + verifyNoAllocations(); + + Polymorphic i3(std::allocator_arg, ScopedAlloc{33, 44}); + + i3 = e(); + VERIFY( i3.valueless_after_move() ); + if (Propagate) + VERIFY( i3.get_allocator().get_personality() == 11 ); + else + VERIFY( i3.get_allocator().get_personality() == 33 ); + VERIFY( Counter::get_allocation_count() == 0 ); + VERIFY( Counter::get_deallocation_count() >= sizeof(Vector) ); + VERIFY( Counter::get_construct_count() == 0 ); + VERIFY( Counter::get_destruct_count() == 1 ); + + i2 = e(); + VERIFY( i2.valueless_after_move() ); + if (Propagate) + VERIFY( i2.get_allocator().get_personality() == 11 ); + else + VERIFY( i2.get_allocator().get_personality() == 33 ); + verifyNoAllocations(); + + i3.swap(i2); + VERIFY( i2.valueless_after_move() ); + VERIFY( i1.valueless_after_move() ); + verifyNoAllocations(); + + if (!Propagate) + return; + + Polymorphic i4(std::allocator_arg, ScopedAlloc{33, 44}, e()); + i4.swap(i1); + verifyNoAllocations(); +} + +template<bool Propagate> +constexpr void +test_all() +{ + test_ctor<Propagate>(); + test_assign<Propagate>(); + test_swap<Propagate>(); + test_valueless<Propagate>(); +} + +int main() +{ + test_all<true>(); + test_all<false>(); + + static_assert([] { + test_all<true>(); + test_all<false>(); + return true; + }); +} |