diff options
254 files changed, 9366 insertions, 1435 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 53a5cba..921d621 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,133 @@ +2025-06-03 Richard Biener <rguenther@suse.de> + + * gimple-fold.cc (create_tmp_reg_or_ssa_name): Always + create a SSA name. + +2025-06-03 Pan Li <pan2.li@intel.com> + + * config/riscv/riscv-v.cc (expand_vx_binary_vec_vec_dup): Add new + case for DIV op. + * config/riscv/riscv.cc (get_vector_binary_rtx_cost): Add new func + to get the cost of vector binary. + (riscv_rtx_costs): Add div rtx match and leverage above wrap to + get cost. + * config/riscv/vector-iterators.md: Add new op div to no_shift_vx_op. + +2025-06-03 Richard Biener <rguenther@suse.de> + + PR tree-optimization/120517 + * tree-vect-data-refs.cc (vect_analyze_data_ref_accesses): + Fix math in dataref group split. + +2025-06-03 Paul-Antoine Arras <parras@baylibre.com> + + * config/riscv/riscv-vector-costs.cc (costs::adjust_stmt_cost): Replace + FR2VR with get_fr2vr_cost (). + * config/riscv/riscv.cc (riscv_register_move_cost): Likewise. + (riscv_builtin_vectorization_cost): Likewise. + +2025-06-03 Paul-Antoine Arras <parras@baylibre.com> + + PR target/119100 + * config/riscv/autovec-opt.md (*<optab>_vf_<mode>): Add new pattern to + combine vec_duplicate + vfm{add,sub}.vv into vfm{add,sub}.vf. + * config/riscv/riscv-opts.h (FPR2VR_COST_UNPROVIDED): Define. + * config/riscv/riscv-protos.h (get_fr2vr_cost): Declare function. + * config/riscv/riscv.cc (riscv_rtx_costs): Add cost model for MULT with + VEC_DUPLICATE. + (get_fr2vr_cost): New function. + * config/riscv/riscv.opt: Add new option --param=fpr2vr-cost. + +2025-06-03 Andrew Pinski <quic_apinski@quicinc.com> + + PR tree-optimization/120451 + * tree-switch-conversion.cc (switch_conversion::build_one_array): Mark + the newly created decl as mergable. + +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. diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 42f5016..932c2dd 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20250601 +20250604 diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index f543372..cd96e82 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,8 @@ +2025-06-03 Martin Uecker <uecker@tugraz.at> + + PR c/120078 + * c.opt (Wjump-misses-init): Fix typo. + 2025-05-30 Julian Brown <julian@codesourcery.com> Tobias Burnus <tburnus@baylibre.com> 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..7f5b0b8 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,24 @@ +2025-06-03 Martin Uecker <uecker@tugraz.at> + + * c-typeck.cc (composite_type_internal,composite_type): Move + checking assertions. + +2025-06-03 Martin Uecker <uecker@tugraz.at> + + PR c/116892 + * c-decl.cc (finish_enum): Propagate TYPE_PACKED. + +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-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/calls.cc b/gcc/calls.cc index 164f3c5..e16190c 100644 --- a/gcc/calls.cc +++ b/gcc/calls.cc @@ -3736,19 +3736,16 @@ expand_call (tree exp, rtx target, int ignore) next_arg_reg, valreg, old_inhibit_defer_pop, call_fusage, flags, args_so_far); - if (flag_ipa_ra) + rtx_call_insn *last; + rtx datum = NULL_RTX; + if (fndecl != NULL_TREE) { - rtx_call_insn *last; - rtx datum = NULL_RTX; - if (fndecl != NULL_TREE) - { - datum = XEXP (DECL_RTL (fndecl), 0); - gcc_assert (datum != NULL_RTX - && GET_CODE (datum) == SYMBOL_REF); - } - last = last_call_insn (); - add_reg_note (last, REG_CALL_DECL, datum); + datum = XEXP (DECL_RTL (fndecl), 0); + gcc_assert (datum != NULL_RTX + && GET_CODE (datum) == SYMBOL_REF); } + last = last_call_insn (); + add_reg_note (last, REG_CALL_DECL, datum); /* If the call setup or the call itself overlaps with anything of the argument setup we probably clobbered our call address. @@ -4804,13 +4801,10 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, struct_value_size, call_cookie, valreg, old_inhibit_defer_pop + 1, call_fusage, flags, args_so_far); - if (flag_ipa_ra) - { - rtx datum = orgfun; - gcc_assert (GET_CODE (datum) == SYMBOL_REF); - rtx_call_insn *last = last_call_insn (); - add_reg_note (last, REG_CALL_DECL, datum); - } + rtx datum = orgfun; + gcc_assert (GET_CODE (datum) == SYMBOL_REF); + rtx_call_insn *last = last_call_insn (); + add_reg_note (last, REG_CALL_DECL, datum); /* Right-shift returned value if necessary. */ if (!pcc_struct_value 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/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/i386/i386.md b/gcc/config/i386/i386.md index b7a18d5..40b43cf 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -8719,6 +8719,34 @@ (set (match_dup 1) (minus:SWI (match_dup 1) (match_dup 0)))])]) +;; Under APX NDD, 'sub reg, mem, reg' is valid. +;; New format for +;; mov reg0, mem1 +;; sub reg0, mem2, reg0 +;; mov mem2, reg0 +;; to +;; mov reg0, mem1 +;; sub mem2, reg0 +(define_peephole2 + [(set (match_operand:SWI 0 "general_reg_operand") + (match_operand:SWI 1 "memory_operand")) + (parallel [(set (reg:CC FLAGS_REG) + (compare:CC (match_operand:SWI 2 "memory_operand") + (match_dup 0))) + (set (match_dup 0) + (minus:SWI (match_dup 2) (match_dup 0)))]) + (set (match_dup 2) (match_dup 0))] + "TARGET_APX_NDD + && (TARGET_READ_MODIFY_WRITE || optimize_insn_for_size_p ()) + && peep2_reg_dead_p (3, operands[0]) + && !reg_overlap_mentioned_p (operands[0], operands[1]) + && !reg_overlap_mentioned_p (operands[0], operands[2])" + [(set (match_dup 0) (match_dup 1)) + (parallel [(set (reg:CC FLAGS_REG) + (compare:CC (match_dup 2) (match_dup 0))) + (set (match_dup 2) + (minus:SWI (match_dup 2) (match_dup 0)))])]) + ;; decl %eax; cmpl $-1, %eax; jne .Lxx; can be optimized into ;; subl $1, %eax; jnc .Lxx; (define_peephole2 @@ -9166,6 +9194,118 @@ (match_dup 1)) (match_dup 0)))])]) +;; Under APX NDD, 'adc reg, mem, reg' is valid. +;; +;; New format for +;; mov reg0, mem1 +;; adc reg0, mem2, reg0 +;; mov mem1, reg0 +;; to +;; mov reg0, mem2 +;; adc mem1, reg0 +(define_peephole2 + [(set (match_operand:SWI48 0 "general_reg_operand") + (match_operand:SWI48 1 "memory_operand")) + (parallel [(set (reg:CCC FLAGS_REG) + (compare:CCC + (zero_extend:<DWI> + (plus:SWI48 + (plus:SWI48 + (match_operator:SWI48 5 "ix86_carry_flag_operator" + [(match_operand 3 "flags_reg_operand") + (const_int 0)]) + (match_operand:SWI48 2 "memory_operand")) + (match_dup 0))) + (plus:<DWI> + (match_operator:<DWI> 4 "ix86_carry_flag_operator" + [(match_dup 3) (const_int 0)]) + (zero_extend:<DWI> (match_dup 0))))) + (set (match_dup 0) + (plus:SWI48 (plus:SWI48 (match_op_dup 5 + [(match_dup 3) (const_int 0)]) + (match_dup 2)) + (match_dup 0)))]) + (set (match_dup 1) (match_dup 0))] + "TARGET_APX_NDD + && (TARGET_READ_MODIFY_WRITE || optimize_insn_for_size_p ()) + && peep2_reg_dead_p (3, operands[0]) + && !reg_overlap_mentioned_p (operands[0], operands[1]) + && !reg_overlap_mentioned_p (operands[0], operands[2])" + [(set (match_dup 0) (match_dup 2)) + (parallel [(set (reg:CCC FLAGS_REG) + (compare:CCC + (zero_extend:<DWI> + (plus:SWI48 + (plus:SWI48 + (match_op_dup 5 + [(match_dup 3) (const_int 0)]) + (match_dup 1)) + (match_dup 0))) + (plus:<DWI> + (match_op_dup 4 + [(match_dup 3) (const_int 0)]) + (zero_extend:<DWI> (match_dup 0))))) + (set (match_dup 1) + (plus:SWI48 (plus:SWI48 (match_op_dup 5 + [(match_dup 3) (const_int 0)]) + (match_dup 1)) + (match_dup 0)))])]) + +;; New format for +;; mov reg0, mem1 +;; adc reg0, mem2, reg0 +;; mov mem2, reg0 +;; to +;; mov reg0, mem1 +;; adc mem2, reg0 +(define_peephole2 + [(set (match_operand:SWI48 0 "general_reg_operand") + (match_operand:SWI48 1 "memory_operand")) + (parallel [(set (reg:CCC FLAGS_REG) + (compare:CCC + (zero_extend:<DWI> + (plus:SWI48 + (plus:SWI48 + (match_operator:SWI48 5 "ix86_carry_flag_operator" + [(match_operand 3 "flags_reg_operand") + (const_int 0)]) + (match_operand:SWI48 2 "memory_operand")) + (match_dup 0))) + (plus:<DWI> + (match_operator:<DWI> 4 "ix86_carry_flag_operator" + [(match_dup 3) (const_int 0)]) + (zero_extend:<DWI> (match_dup 0))))) + (set (match_dup 0) + (plus:SWI48 (plus:SWI48 (match_op_dup 5 + [(match_dup 3) (const_int 0)]) + (match_dup 2)) + (match_dup 0)))]) + (set (match_dup 2) (match_dup 0))] + "TARGET_APX_NDD + && (TARGET_READ_MODIFY_WRITE || optimize_insn_for_size_p ()) + && peep2_reg_dead_p (3, operands[0]) + && !reg_overlap_mentioned_p (operands[0], operands[1]) + && !reg_overlap_mentioned_p (operands[0], operands[2])" + [(set (match_dup 0) (match_dup 1)) + (parallel [(set (reg:CCC FLAGS_REG) + (compare:CCC + (zero_extend:<DWI> + (plus:SWI48 + (plus:SWI48 + (match_op_dup 5 + [(match_dup 3) (const_int 0)]) + (match_dup 2)) + (match_dup 0))) + (plus:<DWI> + (match_op_dup 4 + [(match_dup 3) (const_int 0)]) + (zero_extend:<DWI> (match_dup 0))))) + (set (match_dup 2) + (plus:SWI48 (plus:SWI48 (match_op_dup 5 + [(match_dup 3) (const_int 0)]) + (match_dup 2)) + (match_dup 0)))])]) + (define_peephole2 [(parallel [(set (reg:CCC FLAGS_REG) (compare:CCC @@ -9646,6 +9786,52 @@ [(match_dup 3) (const_int 0)])) (match_dup 0)))])]) +;; Under APX NDD, 'sbb reg, mem, reg' is valid. +;; +;; New format for +;; mov reg0, mem1 +;; sbb reg0, mem2, reg0 +;; mov mem2, reg0 +;; to +;; mov reg0, mem1 +;; sbb mem2, reg0 +(define_peephole2 + [(set (match_operand:SWI48 0 "general_reg_operand") + (match_operand:SWI48 1 "memory_operand")) + (parallel [(set (reg:CCC FLAGS_REG) + (compare:CCC + (zero_extend:<DWI> (match_operand:SWI48 2 "memory_operand")) + (plus:<DWI> + (match_operator:<DWI> 4 "ix86_carry_flag_operator" + [(match_operand 3 "flags_reg_operand") (const_int 0)]) + (zero_extend:<DWI> + (match_dup 0))))) + (set (match_dup 0) + (minus:SWI48 + (minus:SWI48 + (match_dup 2) + (match_operator:SWI48 5 "ix86_carry_flag_operator" + [(match_dup 3) (const_int 0)])) + (match_dup 0)))]) + (set (match_dup 2) (match_dup 0))] + "TARGET_APX_NDD + && (TARGET_READ_MODIFY_WRITE || optimize_insn_for_size_p ()) + && peep2_reg_dead_p (3, operands[0]) + && !reg_overlap_mentioned_p (operands[0], operands[1]) + && !reg_overlap_mentioned_p (operands[0], operands[2])" + [(set (match_dup 0) (match_dup 1)) + (parallel [(set (reg:CCC FLAGS_REG) + (compare:CCC + (zero_extend:<DWI> (match_dup 2)) + (plus:<DWI> (match_op_dup 4 + [(match_dup 3) (const_int 0)]) + (zero_extend:<DWI> (match_dup 0))))) + (set (match_dup 2) + (minus:SWI48 (minus:SWI48 (match_dup 2) + (match_op_dup 5 + [(match_dup 3) (const_int 0)])) + (match_dup 0)))])]) + (define_peephole2 [(set (match_operand:SWI48 6 "general_reg_operand") (match_operand:SWI48 7 "memory_operand")) @@ -28212,6 +28398,41 @@ const0_rtx); }) +;; For APX NDD PLUS/MINUS/LOGIC +;; Like cmpelim optimized pattern. +;; Reduce an extra mov instruction like +;; decl (%rdi), %eax +;; mov %eax, (%rdi) +;; to +;; decl (%rdi) +(define_peephole2 + [(parallel [(set (reg FLAGS_REG) + (compare (match_operator:SWI 2 "plusminuslogic_operator" + [(match_operand:SWI 0 "memory_operand") + (match_operand:SWI 1 "<nonmemory_operand>")]) + (const_int 0))) + (set (match_operand:SWI 3 "register_operand") (match_dup 2))]) + (set (match_dup 0) (match_dup 3))] + "TARGET_APX_NDD + && (TARGET_READ_MODIFY_WRITE || optimize_insn_for_size_p ()) + && peep2_reg_dead_p (2, operands[3]) + && !reg_overlap_mentioned_p (operands[3], operands[0]) + && ix86_match_ccmode (peep2_next_insn (0), + (GET_CODE (operands[2]) == PLUS + || GET_CODE (operands[2]) == MINUS) + ? CCGOCmode : CCNOmode)" + [(parallel [(set (match_dup 4) (match_dup 6)) + (set (match_dup 0) (match_dup 5))])] +{ + operands[4] = SET_DEST (XVECEXP (PATTERN (peep2_next_insn (0)), 0, 0)); + operands[5] + = gen_rtx_fmt_ee (GET_CODE (operands[2]), GET_MODE (operands[2]), + copy_rtx (operands[0]), operands[1]); + operands[6] + = gen_rtx_COMPARE (GET_MODE (operands[4]), copy_rtx (operands[5]), + const0_rtx); +}) + ;; Likewise for instances where we have a lea pattern. (define_peephole2 [(set (match_operand:SWI 0 "register_operand") @@ -28305,6 +28526,54 @@ const0_rtx); }) +;; For APX NDD XOR +;; Reduce 2 mov and 1 cmp instruction. +;; from +;; movq (%rdi), %rax +;; xorq %rsi, %rax, %rdx +;; movb %rdx, (%rdi) +;; cmpb %rsi, %rax +;; jne +;; to +;; xorb %rsi, (%rdi) +;; jne +(define_peephole2 + [(set (match_operand:SWI 0 "register_operand") + (match_operand:SWI 1 "memory_operand")) + (parallel [(set (match_operand:SWI 4 "register_operand") + (xor:SWI (match_operand:SWI 3 "register_operand") + (match_operand:SWI 2 "<nonmemory_operand>"))) + (clobber (reg:CC FLAGS_REG))]) + (set (match_dup 1) (match_dup 4)) + (set (reg:CCZ FLAGS_REG) + (compare:CCZ (match_operand:SWI 5 "register_operand") + (match_operand:SWI 6 "<nonmemory_operand>")))] + "TARGET_APX_NDD + && (TARGET_READ_MODIFY_WRITE || optimize_insn_for_size_p ()) + && REGNO (operands[3]) == REGNO (operands[0]) + && (rtx_equal_p (operands[0], operands[5]) + ? rtx_equal_p (operands[2], operands[6]) + : rtx_equal_p (operands[2], operands[5]) + && rtx_equal_p (operands[0], operands[6])) + && peep2_reg_dead_p (3, operands[4]) + && peep2_reg_dead_p (4, operands[0]) + && !reg_overlap_mentioned_p (operands[0], operands[1]) + && !reg_overlap_mentioned_p (operands[0], operands[2]) + && (<MODE>mode != QImode + || immediate_operand (operands[2], QImode) + || any_QIreg_operand (operands[2], QImode))" + [(parallel [(set (match_dup 7) (match_dup 9)) + (set (match_dup 1) (match_dup 8))])] +{ + operands[7] = SET_DEST (PATTERN (peep2_next_insn (3))); + operands[8] = gen_rtx_XOR (<MODE>mode, copy_rtx (operands[1]), + operands[2]); + operands[9] + = gen_rtx_COMPARE (GET_MODE (operands[7]), + copy_rtx (operands[8]), + const0_rtx); +}) + (define_peephole2 [(set (match_operand:SWI12 0 "register_operand") (match_operand:SWI12 1 "memory_operand")) @@ -28548,6 +28817,58 @@ const0_rtx); }) +;; For APX NDD XOR +;; Reduce 2 mov and 1 cmp instruction. +;; from +;; movb (%rdi), %al +;; xorl %esi, %eax, %edx +;; movb %dl, (%rdi) +;; cmpb %sil, %al +;; jne +;; to +;; xorl %sil, (%rdi) +;; jne +(define_peephole2 + [(set (match_operand:SWI12 0 "register_operand") + (match_operand:SWI12 1 "memory_operand")) + (parallel [(set (match_operand:SI 4 "register_operand") + (xor:SI (match_operand:SI 3 "register_operand") + (match_operand:SI 2 "<nonmemory_operand>"))) + (clobber (reg:CC FLAGS_REG))]) + (set (match_dup 1) (match_operand:SWI12 5 "register_operand")) + (set (reg:CCZ FLAGS_REG) + (compare:CCZ (match_operand:SWI12 6 "register_operand") + (match_operand:SWI12 7 "<nonmemory_operand>")))] + "TARGET_APX_NDD + && (TARGET_READ_MODIFY_WRITE || optimize_insn_for_size_p ()) + && REGNO (operands[3]) == REGNO (operands[0]) + && REGNO (operands[5]) == REGNO (operands[4]) + && (rtx_equal_p (operands[0], operands[6]) + ? (REG_P (operands[2]) + ? REG_P (operands[7]) && REGNO (operands[2]) == REGNO (operands[7]) + : rtx_equal_p (operands[2], operands[7])) + : (rtx_equal_p (operands[0], operands[7]) + && REG_P (operands[2]) + && REGNO (operands[2]) == REGNO (operands[6]))) + && peep2_reg_dead_p (3, operands[5]) + && peep2_reg_dead_p (4, operands[0]) + && !reg_overlap_mentioned_p (operands[0], operands[1]) + && !reg_overlap_mentioned_p (operands[0], operands[2]) + && (<MODE>mode != QImode + || immediate_operand (operands[2], SImode) + || any_QIreg_operand (operands[2], SImode))" + [(parallel [(set (match_dup 8) (match_dup 10)) + (set (match_dup 1) (match_dup 9))])] +{ + operands[8] = SET_DEST (PATTERN (peep2_next_insn (3))); + operands[9] = gen_rtx_XOR (<MODE>mode, copy_rtx (operands[1]), + gen_lowpart (<MODE>mode, operands[2])); + operands[10] + = gen_rtx_COMPARE (GET_MODE (operands[8]), + copy_rtx (operands[9]), + const0_rtx); +}) + ;; Attempt to optimize away memory stores of values the memory already ;; has. See PR79593. (define_peephole2 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/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..0e989e1 100644 --- a/gcc/config/riscv/riscv-ext.def +++ b/gcc/config/riscv/riscv-ext.def @@ -1611,6 +1611,19 @@ DEFINE_RISCV_EXT( /* EXTRA_EXTENSION_FLAGS */ 0) DEFINE_RISCV_EXT( + /* NAME */ shlcofideleg, + /* UPPERCASE_NAME */ SHLCOFIDELEG, + /* FULL_NAME */ "Delegating LCOFI interrupts to VS-mode", + /* DESC */ "", + /* URL */ , + /* DEP_EXTS */ ({"h"}), + /* SUPPORTED_VERSIONS */ ({{1, 0}}), + /* FLAG_GROUP */ sh, + /* BITMASK_GROUP_ID */ BITMASK_NOT_YET_ALLOCATED, + /* BITMASK_BIT_POSITION*/ BITMASK_NOT_YET_ALLOCATED, + /* EXTRA_EXTENSION_FLAGS */ 0) + +DEFINE_RISCV_EXT( /* NAME */ shtvala, /* UPPERCAE_NAME */ SHTVALA, /* FULL_NAME */ "The htval register provides all needed values", @@ -1676,6 +1689,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", @@ -1915,7 +1941,7 @@ DEFINE_RISCV_EXT( /* FULL_NAME */ "Hardware Updating of A/D Bits extension", /* DESC */ "", /* URL */ , - /* DEP_EXTS */ ({}), + /* DEP_EXTS */ ({"zicsr"}), /* SUPPORTED_VERSIONS */ ({{1, 0}}), /* FLAG_GROUP */ sv, /* BITMASK_GROUP_ID */ BITMASK_NOT_YET_ALLOCATED, @@ -1928,7 +1954,20 @@ DEFINE_RISCV_EXT( /* FULL_NAME */ "Cause exception when hardware updating of A/D bits is disabled", /* DESC */ "", /* URL */ , - /* DEP_EXTS */ ({}), + /* DEP_EXTS */ ({"zicsr"}), + /* SUPPORTED_VERSIONS */ ({{1, 0}}), + /* FLAG_GROUP */ sv, + /* BITMASK_GROUP_ID */ BITMASK_NOT_YET_ALLOCATED, + /* BITMASK_BIT_POSITION*/ BITMASK_NOT_YET_ALLOCATED, + /* EXTRA_EXTENSION_FLAGS */ 0) + +DEFINE_RISCV_EXT( + /* NAME */ svbare, + /* UPPERCAE_NAME */ SVBARE, + /* FULL_NAME */ "Satp mode bare is supported", + /* DESC */ "", + /* URL */ , + /* DEP_EXTS */ ({"zicsr"}), /* SUPPORTED_VERSIONS */ ({{1, 0}}), /* FLAG_GROUP */ sv, /* BITMASK_GROUP_ID */ BITMASK_NOT_YET_ALLOCATED, diff --git a/gcc/config/riscv/riscv-ext.opt b/gcc/config/riscv/riscv-ext.opt index 5e9c5f5..3e5cbb3 100644 --- a/gcc/config/riscv/riscv-ext.opt +++ b/gcc/config/riscv/riscv-ext.opt @@ -325,6 +325,8 @@ Mask(SHCOUNTERENW) Var(riscv_sh_subext) Mask(SHGATPA) Var(riscv_sh_subext) +Mask(SHLCOFIDELEG) Var(riscv_sh_subext) + Mask(SHTVALA) Var(riscv_sh_subext) Mask(SHVSTVALA) Var(riscv_sh_subext) @@ -335,6 +337,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) @@ -375,6 +379,8 @@ Mask(SVADU) Var(riscv_sv_subext) Mask(SVADE) Var(riscv_sv_subext) +Mask(SVBARE) Var(riscv_sv_subext) + Mask(XCVALU) Var(riscv_xcv_subext) Mask(XCVBI) Var(riscv_xcv_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..3254ec9 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 scalar2vr_cost will be appended if there one of the + op comes from the VEC_DUPLICATE. */ + +static int +get_vector_binary_rtx_cost (rtx x, int scalar2vr_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 (scalar2vr_cost + 1) * COSTS_N_INSNS (1); + else + return COSTS_N_INSNS (1); +} + /* Implement TARGET_RTX_COSTS. */ #define SINGLE_SHIFT_COST 1 @@ -3904,6 +3923,9 @@ 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 (); + int scalar2vr_cost = FLOAT_MODE_P (GET_MODE_INNER (mode)) + ? fr2vr_cost : gr2vr_cost; switch (outer_code) { @@ -3914,6 +3936,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 = XEXP (x, 1); + + switch (GET_CODE (op)) + { + case DIV: + *total = get_vector_binary_rtx_cost (op, scalar2vr_cost); + break; + default: + *total = COSTS_N_INSNS (1); + break; + } + } + break; case PLUS: case MINUS: case AND: @@ -3921,14 +3958,15 @@ riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN case XOR: case MULT: { + rtx op; 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) - *total = (gr2vr_cost + 1) * COSTS_N_INSNS (1); + if (GET_CODE (op = op_0) == MULT + || GET_CODE (op = op_1) == MULT) + *total = get_vector_binary_rtx_cost (op, scalar2vr_cost); else - *total = COSTS_N_INSNS (1); + *total = get_vector_binary_rtx_cost (x, scalar2vr_cost); } break; default: @@ -9781,7 +9819,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 +12685,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 +12765,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/cp/ChangeLog b/gcc/cp/ChangeLog index 3f05db3..524aa55 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,58 @@ +2025-06-03 Jason Merrill <jason@redhat.com> + + * name-lookup.h (operator|, operator|=): Define for WMB_Flags. + +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/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..3e6541a 100644 --- a/gcc/doc/riscv-ext.texi +++ b/gcc/doc/riscv-ext.texi @@ -474,6 +474,10 @@ @tab 1.0 @tab SvNNx4 mode supported for all modes supported by satp +@item shlcofideleg +@tab 1.0 +@tab Delegating LCOFI interrupts to VS-mode + @item shtvala @tab 1.0 @tab The htval register provides all needed values @@ -494,6 +498,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 @@ -574,6 +582,10 @@ @tab 1.0 @tab Cause exception when hardware updating of A/D bits is disabled +@item svbare +@tab 1.0 +@tab Satp mode bare is supported + @item xcvalu @tab 1.0 @tab Core-V miscellaneous ALU extension 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/emit-rtl.cc b/gcc/emit-rtl.cc index 3f453cd..50e3bfc 100644 --- a/gcc/emit-rtl.cc +++ b/gcc/emit-rtl.cc @@ -998,10 +998,11 @@ validate_subreg (machine_mode omode, machine_mode imode, && known_le (osize, isize)) return false; - /* The outer size must be ordered wrt the register size, otherwise - we wouldn't know at compile time how many registers the outer - mode occupies. */ - if (!ordered_p (osize, regsize)) + /* If ISIZE is greater than REGSIZE, the inner value is split into blocks + of size REGSIZE. The outer size must then be ordered wrt REGSIZE, + otherwise we wouldn't know at compile time how many blocks the + outer mode occupies. */ + if (maybe_gt (isize, regsize) && !ordered_p (osize, regsize)) return false; /* For normal pseudo registers, we want most of the same checks. Namely: diff --git a/gcc/ext-dce.cc b/gcc/ext-dce.cc index a034395..aa80c04 100644 --- a/gcc/ext-dce.cc +++ b/gcc/ext-dce.cc @@ -35,6 +35,7 @@ along with GCC; see the file COPYING3. If not see #include "print-rtl.h" #include "dbgcnt.h" #include "diagnostic-core.h" +#include "target.h" /* These should probably move into a C++ class. */ static vec<bitmap_head> livein; @@ -764,13 +765,25 @@ ext_dce_process_uses (rtx_insn *insn, rtx obj, We don't want to mark those bits live unnecessarily as that inhibits extension elimination in important cases such as those in Coremark. So we need that - outer code. */ + outer code. + + But if !TRULY_NOOP_TRUNCATION_MODES_P, the mode + change performed by Y would normally need to be a + TRUNCATE rather than a SUBREG. It is probably the + guarantee provided by SUBREG_PROMOTED_VAR_P that + allows the SUBREG in Y as an exception. We must + therefore preserve that guarantee and treat the + upper bits of the inner register as live + regardless of the outer code. See PR 120050. */ if (!REG_P (SUBREG_REG (y)) || (SUBREG_PROMOTED_VAR_P (y) && ((GET_CODE (SET_SRC (x)) == SIGN_EXTEND && SUBREG_PROMOTED_SIGNED_P (y)) || (GET_CODE (SET_SRC (x)) == ZERO_EXTEND - && SUBREG_PROMOTED_UNSIGNED_P (y))))) + && SUBREG_PROMOTED_UNSIGNED_P (y)) + || !TRULY_NOOP_TRUNCATION_MODES_P ( + GET_MODE (y), + GET_MODE (SUBREG_REG (y)))))) break; bit = subreg_lsb (y).to_constant (); 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/ChangeLog b/gcc/fortran/ChangeLog index e740ecc..395cd0a 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,9 @@ +2025-06-03 Harald Anlauf <anlauf@gmx.de> + + PR fortran/99838 + * data.cc (gfc_assign_data_value): For a new initializer use the + location from the constructor as fallback. + 2025-05-30 Harald Anlauf <anlauf@gmx.de> PR fortran/102599 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/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc index 8d9448e..74d4265 100644 --- a/gcc/fortran/trans-expr.cc +++ b/gcc/fortran/trans-expr.cc @@ -2782,9 +2782,11 @@ gfc_conv_substring (gfc_se * se, gfc_ref * ref, int kind, start.expr = gfc_evaluate_now (start.expr, &se->pre); /* Change the start of the string. */ - if ((TREE_CODE (TREE_TYPE (se->expr)) == ARRAY_TYPE - || TREE_CODE (TREE_TYPE (se->expr)) == INTEGER_TYPE) - && TYPE_STRING_FLAG (TREE_TYPE (se->expr))) + if (((TREE_CODE (TREE_TYPE (se->expr)) == ARRAY_TYPE + || TREE_CODE (TREE_TYPE (se->expr)) == INTEGER_TYPE) + && TYPE_STRING_FLAG (TREE_TYPE (se->expr))) + || (POINTER_TYPE_P (TREE_TYPE (se->expr)) + && TREE_CODE (TREE_TYPE (TREE_TYPE (se->expr))) != ARRAY_TYPE)) tmp = se->expr; else tmp = build_fold_indirect_ref_loc (input_location, @@ -2795,6 +2797,14 @@ gfc_conv_substring (gfc_se * se, gfc_ref * ref, int kind, tmp = gfc_build_array_ref (tmp, start.expr, NULL_TREE, true); se->expr = gfc_build_addr_expr (type, tmp); } + else if (POINTER_TYPE_P (TREE_TYPE (tmp))) + { + tree diff; + diff = fold_build2 (MINUS_EXPR, size_type_node, start.expr, + build_one_cst (size_type_node)); + se->expr + = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (tmp), tmp, diff); + } } /* Length = end + 1 - start. */ 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/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 5f13f6c..6b19a4d 100644 --- a/gcc/m2/ChangeLog +++ b/gcc/m2/ChangeLog @@ -1,5 +1,10 @@ 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. diff --git a/gcc/match.pd b/gcc/match.pd index bde9bd6..6565724 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -2177,6 +2177,18 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (view_convert (rshift (view_convert:ntype @0) @1)) (convert (rshift (convert:ntype @0) @1)))))) +#if GIMPLE + /* Fold ((x + y) >> 1 into IFN_AVG_FLOOR (x, y) if x and y are vectors in + which each element is known to have at least one leading zero bit. */ +(simplify + (rshift (plus:cs @0 @1) integer_onep) + (if (VECTOR_TYPE_P (type) + && direct_internal_fn_supported_p (IFN_AVG_FLOOR, type, OPTIMIZE_FOR_BOTH) + && wi::clz (get_nonzero_bits (@0)) > 0 + && wi::clz (get_nonzero_bits (@1)) > 0) + (IFN_AVG_FLOOR @0 @1))) +#endif + /* Try to fold (type) X op CST -> (type) (X op ((type-x) CST)) when profitable. For bitwise binary operations apply operand conversions to the diff --git a/gcc/range-op-float.cc b/gcc/range-op-float.cc index dafd9c0..ea344a4 100644 --- a/gcc/range-op-float.cc +++ b/gcc/range-op-float.cc @@ -51,8 +51,8 @@ along with GCC; see the file COPYING3. If not see bool range_operator::fold_range (frange &r, tree type, - const frange &op1, const frange &op2, - relation_trio trio) const + const frange &op1, const frange &op2, + relation_trio trio) const { if (empty_range_varying (r, type, op1, op2)) return true; @@ -112,20 +112,20 @@ range_operator::rv_fold (frange &r, tree type, bool range_operator::fold_range (irange &r ATTRIBUTE_UNUSED, - tree type ATTRIBUTE_UNUSED, - const frange &lh ATTRIBUTE_UNUSED, - const irange &rh ATTRIBUTE_UNUSED, - relation_trio) const + tree type ATTRIBUTE_UNUSED, + const frange &lh ATTRIBUTE_UNUSED, + const irange &rh ATTRIBUTE_UNUSED, + relation_trio) const { return false; } bool range_operator::fold_range (irange &r ATTRIBUTE_UNUSED, - tree type ATTRIBUTE_UNUSED, - const frange &lh ATTRIBUTE_UNUSED, - const frange &rh ATTRIBUTE_UNUSED, - relation_trio) const + tree type ATTRIBUTE_UNUSED, + const frange &lh ATTRIBUTE_UNUSED, + const frange &rh ATTRIBUTE_UNUSED, + relation_trio) const { return false; } @@ -142,10 +142,10 @@ range_operator::fold_range (frange &r ATTRIBUTE_UNUSED, bool range_operator::op1_range (frange &r ATTRIBUTE_UNUSED, - tree type ATTRIBUTE_UNUSED, - const frange &lhs ATTRIBUTE_UNUSED, - const frange &op2 ATTRIBUTE_UNUSED, - relation_trio) const + tree type ATTRIBUTE_UNUSED, + const frange &lhs ATTRIBUTE_UNUSED, + const frange &op2 ATTRIBUTE_UNUSED, + relation_trio) const { return false; } @@ -162,56 +162,56 @@ range_operator::op1_range (frange &r ATTRIBUTE_UNUSED, bool range_operator::op2_range (frange &r ATTRIBUTE_UNUSED, - tree type ATTRIBUTE_UNUSED, - const frange &lhs ATTRIBUTE_UNUSED, - const frange &op1 ATTRIBUTE_UNUSED, - relation_trio) const + tree type ATTRIBUTE_UNUSED, + const frange &lhs ATTRIBUTE_UNUSED, + const frange &op1 ATTRIBUTE_UNUSED, + relation_trio) const { return false; } bool range_operator::op2_range (frange &r ATTRIBUTE_UNUSED, - tree type ATTRIBUTE_UNUSED, - const irange &lhs ATTRIBUTE_UNUSED, - const frange &op1 ATTRIBUTE_UNUSED, - relation_trio) const + tree type ATTRIBUTE_UNUSED, + const irange &lhs ATTRIBUTE_UNUSED, + const frange &op1 ATTRIBUTE_UNUSED, + relation_trio) const { return false; } relation_kind range_operator::lhs_op1_relation (const frange &lhs ATTRIBUTE_UNUSED, - const frange &op1 ATTRIBUTE_UNUSED, - const frange &op2 ATTRIBUTE_UNUSED, - relation_kind) const + const frange &op1 ATTRIBUTE_UNUSED, + const frange &op2 ATTRIBUTE_UNUSED, + relation_kind) const { return VREL_VARYING; } relation_kind range_operator::lhs_op1_relation (const irange &lhs ATTRIBUTE_UNUSED, - const frange &op1 ATTRIBUTE_UNUSED, - const frange &op2 ATTRIBUTE_UNUSED, - relation_kind) const + const frange &op1 ATTRIBUTE_UNUSED, + const frange &op2 ATTRIBUTE_UNUSED, + relation_kind) const { return VREL_VARYING; } relation_kind range_operator::lhs_op2_relation (const irange &lhs ATTRIBUTE_UNUSED, - const frange &op1 ATTRIBUTE_UNUSED, - const frange &op2 ATTRIBUTE_UNUSED, - relation_kind) const + const frange &op1 ATTRIBUTE_UNUSED, + const frange &op2 ATTRIBUTE_UNUSED, + relation_kind) const { return VREL_VARYING; } relation_kind range_operator::lhs_op2_relation (const frange &lhs ATTRIBUTE_UNUSED, - const frange &op1 ATTRIBUTE_UNUSED, - const frange &op2 ATTRIBUTE_UNUSED, - relation_kind) const + const frange &op1 ATTRIBUTE_UNUSED, + const frange &op2 ATTRIBUTE_UNUSED, + relation_kind) const { return VREL_VARYING; } @@ -675,9 +675,9 @@ operator_equal::fold_range (irange &r, tree type, bool operator_equal::op1_range (frange &r, tree type, - const irange &lhs, - const frange &op2, - relation_trio trio) const + const irange &lhs, + const frange &op2, + relation_trio trio) const { relation_kind rel = trio.op1_op2 (); switch (get_bool_state (r, lhs, type)) @@ -1871,10 +1871,10 @@ public: bool foperator_unordered_gt::op1_range (frange &r, - tree type, - const irange &lhs, - const frange &op2, - relation_trio) const + tree type, + const irange &lhs, + const frange &op2, + relation_trio) const { switch (get_bool_state (r, lhs, type)) { @@ -2899,6 +2899,127 @@ private: } } fop_div; +bool +operator_cast::fold_range (frange &r, tree type, const frange &op1, + const frange &, relation_trio) const +{ + REAL_VALUE_TYPE lb, ub; + enum machine_mode mode = TYPE_MODE (type); + bool mode_composite = MODE_COMPOSITE_P (mode); + + if (empty_range_varying (r, type, op1, op1)) + return true; + if (!MODE_HAS_NANS (mode) && op1.maybe_isnan ()) + { + r.set_varying (type); + return true; + } + if (op1.known_isnan ()) + { + r.set_nan (type); + return true; + } + + const REAL_VALUE_TYPE &lh_lb = op1.lower_bound (); + const REAL_VALUE_TYPE &lh_ub = op1.upper_bound (); + real_convert (&lb, mode, &lh_lb); + real_convert (&ub, mode, &lh_ub); + + if (flag_rounding_math) + { + if (real_less (&lh_lb, &lb)) + { + if (mode_composite + && (real_isdenormal (&lb, mode) || real_iszero (&lb))) + { + // IBM extended denormals only have DFmode precision. + REAL_VALUE_TYPE tmp, tmp2; + real_convert (&tmp2, DFmode, &lh_lb); + real_nextafter (&tmp, REAL_MODE_FORMAT (DFmode), &tmp2, + &dconstninf); + real_convert (&lb, mode, &tmp); + } + else + frange_nextafter (mode, lb, dconstninf); + } + if (real_less (&ub, &lh_ub)) + { + if (mode_composite + && (real_isdenormal (&ub, mode) || real_iszero (&ub))) + { + // IBM extended denormals only have DFmode precision. + REAL_VALUE_TYPE tmp, tmp2; + real_convert (&tmp2, DFmode, &lh_ub); + real_nextafter (&tmp, REAL_MODE_FORMAT (DFmode), &tmp2, + &dconstinf); + real_convert (&ub, mode, &tmp); + } + else + frange_nextafter (mode, ub, dconstinf); + } + } + + r.set (type, lb, ub, op1.get_nan_state ()); + + if (flag_trapping_math + && MODE_HAS_INFINITIES (TYPE_MODE (type)) + && r.known_isinf () + && !op1.known_isinf ()) + { + REAL_VALUE_TYPE inf = r.lower_bound (); + if (real_isneg (&inf)) + { + REAL_VALUE_TYPE min = real_min_representable (type); + r.set (type, inf, min); + } + else + { + REAL_VALUE_TYPE max = real_max_representable (type); + r.set (type, max, inf); + } + } + + r.flush_denormals_to_zero (); + return true; +} + +// Implement fold for a cast from float to another float. +bool +operator_cast::op1_range (frange &r, tree type, const frange &lhs, + const frange &op2, relation_trio) const +{ + if (lhs.undefined_p ()) + return false; + tree lhs_type = lhs.type (); + enum machine_mode mode = TYPE_MODE (type); + enum machine_mode lhs_mode = TYPE_MODE (lhs_type); + frange wlhs; + bool rm; + if (REAL_MODE_FORMAT (mode)->ieee_bits + && REAL_MODE_FORMAT (lhs_mode)->ieee_bits + && (REAL_MODE_FORMAT (lhs_mode)->ieee_bits + >= REAL_MODE_FORMAT (mode)->ieee_bits) + && pow2p_hwi (REAL_MODE_FORMAT (mode)->ieee_bits)) + { + /* If the cast is widening from IEEE exchange mode to + wider exchange mode or extended mode, no need to extend + the range on reverse operation. */ + rm = false; + wlhs = lhs; + } + else + { + rm = true; + wlhs = float_widen_lhs_range (lhs_type, lhs); + } + auto save_flag_rounding_math = flag_rounding_math; + flag_rounding_math = rm; + bool ret = float_binary_op_range_finish (fold_range (r, type, wlhs, op2), + r, type, lhs); + flag_rounding_math = save_flag_rounding_math; + return ret; +} + // Implement fold for a cast from float to an int. bool operator_cast::fold_range (irange &, tree, const frange &, diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h index 3fb7bff..0edc06e 100644 --- a/gcc/range-op-mixed.h +++ b/gcc/range-op-mixed.h @@ -473,14 +473,15 @@ public: bool fold_range (prange &r, tree type, const irange &op1, const prange &op2, relation_trio rel = TRIO_VARYING) const final override; + bool fold_range (frange &r, tree type, + const frange &op1, const frange &op2, + relation_trio = TRIO_VARYING) const final override; bool fold_range (irange &r, tree type, - const frange &lh, - const irange &rh, - relation_trio = TRIO_VARYING) const; + const frange &op1, const irange &op2, + relation_trio = TRIO_VARYING) const final override; bool fold_range (frange &r, tree type, - const irange &lh, - const frange &rh, - relation_trio = TRIO_VARYING) const; + const irange &op1, const frange &op2, + relation_trio = TRIO_VARYING) const final override; bool op1_range (irange &r, tree type, const irange &lhs, const irange &op2, @@ -495,13 +496,14 @@ public: const irange &lhs, const prange &op2, relation_trio rel = TRIO_VARYING) const final override; bool op1_range (frange &r, tree type, - const irange &lhs, - const irange &op2, - relation_trio = TRIO_VARYING) const; + const frange &lhs, const frange &op2, + relation_trio = TRIO_VARYING) const final override; + bool op1_range (frange &r, tree type, + const irange &lhs, const irange &op2, + relation_trio = TRIO_VARYING) const final override; bool op1_range (irange &r, tree type, - const frange &lhs, - const frange &op2, - relation_trio = TRIO_VARYING) const; + const frange &lhs, const frange &op2, + relation_trio = TRIO_VARYING) const final override; relation_kind lhs_op1_relation (const irange &lhs, const irange &op1, const irange &op2, diff --git a/gcc/range-op.cc b/gcc/range-op.cc index e2b9c82..04128ee 100644 --- a/gcc/range-op.cc +++ b/gcc/range-op.cc @@ -778,21 +778,21 @@ range_operator::fold_range (irange &r, tree type, bool range_operator::fold_range (frange &, tree, const irange &, - const frange &, relation_trio) const + const frange &, relation_trio) const { return false; } bool range_operator::op1_range (irange &, tree, const frange &, - const frange &, relation_trio) const + const frange &, relation_trio) const { return false; } bool range_operator::op1_range (frange &, tree, const irange &, - const irange &, relation_trio) const + const irange &, relation_trio) const { return false; } @@ -855,10 +855,13 @@ range_operator::op1_op2_relation (const irange &lhs ATTRIBUTE_UNUSED, bool range_operator::op1_op2_relation_effect (irange &lhs_range ATTRIBUTE_UNUSED, - tree type ATTRIBUTE_UNUSED, - const irange &op1_range ATTRIBUTE_UNUSED, - const irange &op2_range ATTRIBUTE_UNUSED, - relation_kind rel ATTRIBUTE_UNUSED) const + tree type ATTRIBUTE_UNUSED, + const irange &op1_range + ATTRIBUTE_UNUSED, + const irange &op2_range + ATTRIBUTE_UNUSED, + relation_kind rel + ATTRIBUTE_UNUSED) const { return false; } @@ -874,7 +877,7 @@ range_operator::overflow_free_p (const irange &, const irange &, void range_operator::update_bitmask (irange &, const irange &, - const irange &) const + const irange &) const { } @@ -1815,7 +1818,7 @@ operator_plus::wi_fold (irange &r, tree type, static relation_kind plus_minus_ranges (irange &r_ov, irange &r_normal, const irange &offset, - bool add_p) + bool add_p) { relation_kind kind = VREL_VARYING; // For now, only deal with constant adds. This could be extended to ranges @@ -3349,9 +3352,9 @@ wi_optimize_signed_bitwise_op (irange &r, tree type, relation_kind operator_bitwise_and::lhs_op1_relation (const irange &lhs, - const irange &op1, - const irange &op2, - relation_kind) const + const irange &op1, + const irange &op2, + relation_kind) const { if (lhs.undefined_p () || op1.undefined_p () || op2.undefined_p ()) return VREL_VARYING; @@ -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 52064cd..185857d 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,197 @@ +2025-06-03 Harald Anlauf <anlauf@gmx.de> + + PR fortran/99838 + * gfortran.dg/coarray_data_2.f90: New test. + +2025-06-03 Martin Uecker <uecker@tugraz.at> + + PR c/120078 + * gcc.dg/Wjump-misses-init-3.c: New test. + +2025-06-03 Martin Uecker <uecker@tugraz.at> + + * gcc.dg/gnu23-tag-composite-6.c: Update. + +2025-06-03 Martin Uecker <uecker@tugraz.at> + + PR c/116892 + * gcc.dg/pr116892.c: New test. + +2025-06-03 Jason Merrill <jason@redhat.com> + + * g++.dg/modules/cpp-1.C + * g++.dg/modules/cpp-3.C + * g++.dg/modules/cpp-4.C: Specify -fno-modules. + +2025-06-03 Pan Li <pan2.li@intel.com> + + * gcc.target/riscv/rvv/autovec/binop/vdiv-rv32gcv-nofm.c: Adjust + the asm check for vdiv. + * gcc.target/riscv/rvv/autovec/binop/vdiv-rv32gcv.c: Ditto. + * gcc.target/riscv/rvv/autovec/binop/vdiv-rv64gcv-nofm.c: Ditto. + * gcc.target/riscv/rvv/autovec/binop/vdiv-rv64gcv.c: Ditto. + +2025-06-03 Pan Li <pan2.li@intel.com> + + * gcc.target/riscv/rvv/autovec/vx_vf/vx-4-i16.c: Add asm check + check for vdiv.vx combine. + * gcc.target/riscv/rvv/autovec/vx_vf/vx-4-i32.c: Ditto. + * gcc.target/riscv/rvv/autovec/vx_vf/vx-4-i64.c: Ditto. + * gcc.target/riscv/rvv/autovec/vx_vf/vx-4-i8.c: Ditto. + * gcc.target/riscv/rvv/autovec/vx_vf/vx-5-i16.c: Ditto. + * gcc.target/riscv/rvv/autovec/vx_vf/vx-5-i32.c: Ditto. + * gcc.target/riscv/rvv/autovec/vx_vf/vx-5-i64.c: Ditto. + * gcc.target/riscv/rvv/autovec/vx_vf/vx-5-i8.c: Ditto. + * gcc.target/riscv/rvv/autovec/vx_vf/vx-6-i16.c: Ditto. + * gcc.target/riscv/rvv/autovec/vx_vf/vx-6-i32.c: Ditto. + * gcc.target/riscv/rvv/autovec/vx_vf/vx-6-i64.c: Ditto. + * gcc.target/riscv/rvv/autovec/vx_vf/vx-6-i8.c: Ditto. + +2025-06-03 Pan Li <pan2.li@intel.com> + + * gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i16.c: Add asm check + for vdiv.vx combine. + * gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i32.c: Ditto. + * gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i64.c: Ditto. + * gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i8.c: Ditto. + * gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i16.c: Ditto. + * gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i32.c: Ditto. + * gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i64.c: Ditto. + * gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i8.c: Ditto. + * gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i16.c: Ditto. + * gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i32.c: Ditto. + * gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i64.c: Ditto. + * gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i8.c: Ditto. + * gcc.target/riscv/rvv/autovec/vx_vf/vx_binary_data.h: Add test + data for vdiv run test. + * gcc.target/riscv/rvv/autovec/vx_vf/vx_vdiv-run-1-i16.c: New test. + * gcc.target/riscv/rvv/autovec/vx_vf/vx_vdiv-run-1-i32.c: New test. + * gcc.target/riscv/rvv/autovec/vx_vf/vx_vdiv-run-1-i64.c: New test. + * gcc.target/riscv/rvv/autovec/vx_vf/vx_vdiv-run-1-i8.c: New test. + +2025-06-03 Paul-Antoine Arras <parras@baylibre.com> + + PR target/119100 + * gcc.target/riscv/rvv/autovec/vx_vf/vf-1-f16.c: New test. + * gcc.target/riscv/rvv/autovec/vx_vf/vf-1-f32.c: New test. + * gcc.target/riscv/rvv/autovec/vx_vf/vf-1-f64.c: New test. + * gcc.target/riscv/rvv/autovec/vx_vf/vf-2-f16.c: New test. + * gcc.target/riscv/rvv/autovec/vx_vf/vf-2-f32.c: New test. + * gcc.target/riscv/rvv/autovec/vx_vf/vf-2-f64.c: New test. + * gcc.target/riscv/rvv/autovec/vx_vf/vf-3-f16.c: New test. + * gcc.target/riscv/rvv/autovec/vx_vf/vf-3-f32.c: New test. + * gcc.target/riscv/rvv/autovec/vx_vf/vf-3-f64.c: New test. + * gcc.target/riscv/rvv/autovec/vx_vf/vf-4-f16.c: New test. + * gcc.target/riscv/rvv/autovec/vx_vf/vf-4-f32.c: New test. + * gcc.target/riscv/rvv/autovec/vx_vf/vf-4-f64.c: New test. + * gcc.target/riscv/rvv/autovec/vx_vf/vf_mulop.h: New test. + * gcc.target/riscv/rvv/autovec/vx_vf/vf_mulop_data.h: New test. + * gcc.target/riscv/rvv/autovec/vx_vf/vf_mulop_run.h: New test. + * gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmadd-run-1-f16.c: New test. + * gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmadd-run-1-f32.c: New test. + * gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmadd-run-1-f64.c: New test. + * gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmsub-run-1-f16.c: New test. + * gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmsub-run-1-f32.c: New test. + * gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmsub-run-1-f64.c: New test. + +2025-06-03 H.J. Lu <hjl.tools@gmail.com> + + PR target/103750 + * g++.target/i386/pr103750.C: New test. + +2025-06-03 Andrew Pinski <quic_apinski@quicinc.com> + + PR tree-optimization/116824 + * gcc.dg/tree-ssa/phiprop-2.c: New test. + +2025-06-03 Andrew Pinski <quic_apinski@quicinc.com> + + PR tree-optimization/120451 + * gcc.dg/tree-ssa/cswtch-6.c: New test. + +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 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/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/opt/pr66119.C b/gcc/testsuite/g++.dg/opt/pr66119.C index d1b1845..52362e4 100644 --- a/gcc/testsuite/g++.dg/opt/pr66119.C +++ b/gcc/testsuite/g++.dg/opt/pr66119.C @@ -3,7 +3,7 @@ the value of MOVE_RATIO now is. */ /* { dg-do compile { target { { i?86-*-* x86_64-*-* } && c++11 } } } */ -/* { dg-options "-O3 -mavx -fdump-tree-sra -march=slm -mtune=slm -fno-early-inlining" } */ +/* { dg-options "-O3 -mavx -fdump-tree-sra -fno-tree-forwprop -march=slm -mtune=slm -fno-early-inlining" } */ // { dg-skip-if "requires hosted libstdc++ for cstdlib malloc" { ! hostedlib } } #include <immintrin.h> 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.c-torture/execute/builtins/pr22237-1-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/pr22237-1-lib.c new file mode 100644 index 0000000..4403235 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/pr22237-1-lib.c @@ -0,0 +1,27 @@ +extern void abort (void); + +void * +memcpy (void *dst, const void *src, __SIZE_TYPE__ n) +{ + const char *srcp; + char *dstp; + + srcp = src; + dstp = dst; + + if (dst < src) + { + if (dst + n > src) + abort (); + } + else + { + if (src + n > dst) + abort (); + } + + while (n-- != 0) + *dstp++ = *srcp++; + + return dst; +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/pr22237-1.c b/gcc/testsuite/gcc.c-torture/execute/builtins/pr22237-1.c new file mode 100644 index 0000000..0a12b0f --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/pr22237-1.c @@ -0,0 +1,57 @@ +extern void abort (void); +extern void exit (int); +struct s { unsigned char a[256]; }; +union u { struct { struct s b; int c; } d; struct { int c; struct s b; } e; }; +static union u v; +static union u v0; +static struct s *p = &v.d.b; +static struct s *q = &v.e.b; + +struct outers +{ + struct s inner; +}; + +static inline struct s rp (void) { return *p; } +static inline struct s rq (void) { return *q; } +static void pq (void) +{ + struct outers o = {rq () }; + *p = o.inner; +} +static void qp (void) +{ + struct outers o = {rp () }; + *q = o.inner; +} + +static void +init (struct s *sp) +{ + int i; + for (i = 0; i < 256; i++) + sp->a[i] = i; +} + +static void +check (struct s *sp) +{ + int i; + for (i = 0; i < 256; i++) + if (sp->a[i] != i) + abort (); +} + +void +main_test (void) +{ + v = v0; + init (p); + qp (); + check (q); + v = v0; + init (q); + pq (); + check (p); + exit (0); +} 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/pr120447.c b/gcc/testsuite/gcc.dg/pr120447.c new file mode 100644 index 0000000..bd51f9b --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr120447.c @@ -0,0 +1,24 @@ +/* { dg-options "-Ofast" } */ +/* { dg-additional-options "-mcpu=neoverse-v2" { target aarch64*-*-* } } */ + +char g; +long h; +typedef struct { + void *data; +} i; +i* a; +void b(i *j, char *p2); +void c(char *d) { + d = d ? " and " : " or "; + b(a, d); +} +void b(i *j, char *p2) { + h = __builtin_strlen(p2); + while (g) + ; + int *k = j->data; + char *l = p2, *m = p2 + h; + l += 4; + while (l < m) + *k++ = *l++; +} diff --git a/gcc/testsuite/gcc.dg/pr120525.c b/gcc/testsuite/gcc.dg/pr120525.c new file mode 100644 index 0000000..5ab7a22 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr120525.c @@ -0,0 +1,22 @@ +/* { dg-do compile { target fpic } } */ +/* { dg-options "-O2 -fpic -g" } */ +/* { dg-additional-options "-m31" { target s390x-*-* } } */ + +typedef __SIZE_TYPE__ uintptr_t; +static __thread uintptr_t start_sp; +static inline uintptr_t +__thread_stack_pointer (void) +{ + return (uintptr_t) __builtin_frame_address (0); +} + +void +update_data (void) +{ + if (__builtin_expect ((!start_sp), 0)) + start_sp = __thread_stack_pointer (); + + uintptr_t sp = __thread_stack_pointer (); + if (__builtin_expect ((sp > start_sp), 0)) + start_sp = sp; +} diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20031106-6.c b/gcc/testsuite/gcc.dg/tree-ssa/20031106-6.c index 56d1887b..c7e0088 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/20031106-6.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/20031106-6.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ -/* { dg-options "-O1 -fno-tree-sra -fdump-tree-optimized" } */ +/* { dg-options "-O1 -fno-tree-sra -fdump-tree-optimized -fdump-tree-forwprop1-details" } */ + +/* PR tree-optimization/14295 */ extern void link_error (void); @@ -25,4 +27,6 @@ struct s foo (struct s r) /* There should be no references to any of "temp_struct*" temporaries. */ -/* { dg-final { scan-tree-dump-times "temp_struct" 0 "optimized" { xfail *-*-* } } } */ +/* { dg-final { scan-tree-dump-times "temp_struct" 0 "optimized" } } */ +/* Also check that forwprop pass did the copy prop. */ +/* { dg-final { scan-tree-dump-times "after previous" 3 "forwprop1" } } */ 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/tree-ssa/pr108358-a.c b/gcc/testsuite/gcc.dg/tree-ssa/pr108358-a.c new file mode 100644 index 0000000..342e1c1 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr108358-a.c @@ -0,0 +1,33 @@ +/* { dg-do compile } */ +/* { dg-options "-Os -fdump-tree-optimized" } */ + +/* PR tree-optimization/108358 */ + +struct a { + int b; + int c; + short d; + int e; + int f; +}; +struct g { + struct a f; + struct a h; +}; +int i; +void foo(); +void bar31_(void); +int main() { + struct g j, l = {2, 1, 6, 1, 1, 7, 5, 1, 0, 1}; + for (; i; ++i) + bar31_(); + j = l; + struct g m = j; + struct g k = m; + if (k.h.b) + ; + else + foo(); +} +/* The call to foo should be optimized away. */ +/* { dg-final { scan-tree-dump-not "foo " "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr114169-1.c b/gcc/testsuite/gcc.dg/tree-ssa/pr114169-1.c new file mode 100644 index 0000000..37766fb --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr114169-1.c @@ -0,0 +1,39 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-forwprop-details -fdump-tree-optimized" } */ + + +/* PR tree-optimization/114169 */ + +#include <stdint.h> + +struct S1 { + uint32_t f0; + uint8_t f1; + uint64_t f2; + uint64_t f3; + int32_t f4; +}; + +union U8 { + struct S1 f0; + int32_t f1; + int64_t f2; + uint8_t f3; + const int64_t f4; +}; + +/* --- GLOBAL VARIABLES --- */ +struct S1 g_16 = {4294967293UL,1UL,1UL,0xA9C1C73B017290B1LL,0x5ADF851FL}; +union U8 g_37 = {{1UL,1UL,0x2361AE7D51263067LL,0xEEFD7F9B64A47447LL,0L}}; +struct S1 g_50 = {0x0CFC2012L,1UL,0x43E1243B3BE7B8BBLL,0x03C5CEC10C1A6FE1LL,1L}; + + +/* --- FORWARD DECLARATIONS --- */ + +void func_32(union U8 e) { + e.f3 = e.f0.f4; + g_16 = e.f0 = g_50; +} +/* The union e should not make a difference here. */ +/* { dg-final { scan-tree-dump-times "after previous" 1 "forwprop1" } } */ +/* { dg-final { scan-tree-dump "g_16 = g_50;" "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr120231-1.c b/gcc/testsuite/gcc.dg/tree-ssa/pr120231-1.c new file mode 100644 index 0000000..c1ce44f --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr120231-1.c @@ -0,0 +1,67 @@ +/* PR tree-optimization/120231 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ +/* { dg-add-options float32 } */ +/* { dg-add-options float64 } */ +/* { dg-add-options float128 } */ +/* { dg-require-effective-target float32 } */ +/* { dg-require-effective-target float64 } */ +/* { dg-require-effective-target float128 } */ +/* { dg-final { scan-tree-dump-not "link_failure \\\(\\\);" "optimized" } } */ + +void link_failure (void); + +void +foo (_Float64 x) +{ + if (x >= -64.0f64 && x <= 0x1.p+140f64) + { + _Float32 z = x; + _Float128 w = z; + _Float128 v = x; + if (__builtin_isnan (z) + || __builtin_isnan (w) + || __builtin_isnan (v) + || z < -64.0f32 + || w < -64.0f128 + || __builtin_isinf (v) + || v < -64.0f128 + || v > 0x1.p+140f128) + link_failure (); + } +} + +void +bar (_Float64 x) +{ + _Float32 z = x; + if (z >= -64.0f32 && z <= 0x1.p+38f32) + { + if (__builtin_isnan (x) + || __builtin_isinf (x) + || x < -0x1.000001p+6f64 + || x > 0x1.000001p+38f64) + link_failure (); + } +} + +void +baz (_Float64 x) +{ + _Float128 w = x; + if (w >= -64.0f128 && w <= 0x1.p+1026f128) + { + if (__builtin_isnan (x) + || __builtin_isinf (x) + || x < -64.0f64) + link_failure (); + } + if (w >= 128.25f128 && w <= 0x1.p+1020f128) + { + if (__builtin_isnan (x) + || __builtin_isinf (x) + || x < 128.25f64 + || x > 0x1.p+1020f64) + link_failure (); + } +} diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr57361-1.c b/gcc/testsuite/gcc.dg/tree-ssa/pr57361-1.c new file mode 100644 index 0000000..dc4fadb --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr57361-1.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-O -fdump-tree-forwprop1-details" } */ + +struct A { int x; double y; }; +void f (struct A *a) { + *a = *a; +} + +/* xfailed until figuring out the best way to handle aliasing barriers. */ +/* { dg-final { scan-tree-dump "into a NOP" "forwprop1" { xfail *-*-* } } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr57361.c b/gcc/testsuite/gcc.dg/tree-ssa/pr57361.c index 81f27b3..7e273db 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/pr57361.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr57361.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O -fdump-tree-dse1-details" } */ +/* { dg-options "-O -fdump-tree-dse1-details -fno-tree-forwprop" } */ struct A { int x; double y; }; void f (struct A *a) { diff --git a/gcc/testsuite/gcc.target/aarch64/acle/uhadd_1.c b/gcc/testsuite/gcc.target/aarch64/acle/uhadd_1.c new file mode 100644 index 0000000..f1748a1 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/acle/uhadd_1.c @@ -0,0 +1,34 @@ +/* Test if SIMD fused unsigned halving adds are generated */ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_neon.h> + +#define FUSED_SIMD_UHADD(vectype, q, ts, mask) \ + vectype simd_uhadd ## q ## _ ## ts ## _1 (vectype a) \ + { \ + vectype v1 = vand ## q ## _ ## ts (a, vdup ## q ## _n_ ## ts (mask)); \ + vectype v2 = vdup ## q ## _n_ ## ts (mask); \ + return vshr ## q ## _n_ ## ts (vadd ## q ## _ ## ts (v1, v2), 1); \ + } \ + \ + vectype simd_uhadd ## q ## _ ## ts ## _2 (vectype a, vectype b) \ + { \ + vectype v1 = vand ## q ## _ ## ts (a, vdup ## q ## _n_ ## ts (mask)); \ + vectype v2 = vand ## q ## _ ## ts (b, vdup ## q ## _n_ ## ts (mask)); \ + return vshr ## q ## _n_ ## ts (vadd ## q ## _ ## ts (v1, v2), 1); \ + } + +FUSED_SIMD_UHADD (uint8x8_t, , u8, 0x7f) +FUSED_SIMD_UHADD (uint8x16_t, q, u8, 0x7f) +FUSED_SIMD_UHADD (uint16x4_t, , u16, 0x7fff) +FUSED_SIMD_UHADD (uint16x8_t, q, u16, 0x7fff) +FUSED_SIMD_UHADD (uint32x2_t, , u32, 0x7fffffff) +FUSED_SIMD_UHADD (uint32x4_t, q, u32, 0x7fffffff) + +/* { dg-final { scan-assembler-times {\tuhadd\tv[0-9]+\.8b,} 2 } } */ +/* { dg-final { scan-assembler-times {\tuhadd\tv[0-9]+\.16b,} 2 } } */ +/* { dg-final { scan-assembler-times {\tuhadd\tv[0-9]+\.4h,} 2 } } */ +/* { dg-final { scan-assembler-times {\tuhadd\tv[0-9]+\.8h,} 2 } } */ +/* { dg-final { scan-assembler-times {\tuhadd\tv[0-9]+\.2s,} 2 } } */ +/* { dg-final { scan-assembler-times {\tuhadd\tv[0-9]+\.4s,} 2 } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr49095-2.c b/gcc/testsuite/gcc.target/i386/pr49095-2.c new file mode 100644 index 0000000..25bc6b7 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr49095-2.c @@ -0,0 +1,73 @@ +/* PR rtl-optimization/49095 */ +/* { dg-do compile { target { ! ia32 } } } */ +/* { dg-options "-Os -fno-shrink-wrap -masm=att -mapxf" } */ + +void foo (void *); + +int * +f1 (int *x) +{ + if (!--*x) + foo (x); + return x; +} + +int +g1 (int x) +{ + if (!--x) + foo ((void *) 0); + return x; +} + +#define F(T, OP, OPN) \ +T * \ +f##T##OPN (T *x, T y) \ +{ \ + *x OP y; \ + if (!*x) \ + foo (x); \ + return x; \ +} \ + \ +T \ +g##T##OPN (T x, T y) \ +{ \ + x OP y; \ + if (!x) \ + foo ((void *) 0); \ + return x; \ +} \ + \ +T * \ +h##T##OPN (T *x) \ +{ \ + *x OP 24; \ + if (!*x) \ + foo (x); \ + return x; \ +} \ + \ +T \ +i##T##OPN (T x, T y) \ +{ \ + x OP 24; \ + if (!x) \ + foo ((void *) 0); \ + return x; \ +} + +#define G(T) \ +F (T, +=, plus) \ +F (T, -=, minus) \ +F (T, &=, and) \ +F (T, |=, or) \ +F (T, ^=, xor) + +G (char) +G (short) +G (int) +G (long) + +/* { dg-final { scan-assembler-not "test\[lq\]" } } */ +/* { dg-final { scan-assembler-not "\\(%\[re\]di\\), %" } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr79173-13.c b/gcc/testsuite/gcc.target/i386/pr79173-13.c new file mode 100644 index 0000000..7d5818b --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr79173-13.c @@ -0,0 +1,59 @@ +/* PR middle-end/79173 */ +/* { dg-do compile { target { ! ia32 } } } */ +/* { dg-options "-O2 -fno-stack-protector -masm=att -mapxf" } */ +/* { dg-final { scan-assembler-times "addq\t%r\[^\n\r]*, \\\(%rdi\\\)" 1 { target lp64 } } } */ +/* { dg-final { scan-assembler-times "adcq\t%r\[^\n\r]*, 8\\\(%rdi\\\)" 1 { target lp64 } } } */ +/* { dg-final { scan-assembler-times "adcq\t%r\[^\n\r]*, 16\\\(%rdi\\\)" 1 { target lp64 } } } */ +/* { dg-final { scan-assembler-times "adcq\t%r\[^\n\r]*, 24\\\(%rdi\\\)" 1 { target lp64 } } } */ +/* { dg-final { scan-assembler-times "subq\t%r\[^\n\r]*, \\\(%rdi\\\)" 1 { target lp64 } } } */ +/* { dg-final { scan-assembler-times "sbbq\t%r\[^\n\r]*, 8\\\(%rdi\\\)" 1 { target lp64 } } } */ +/* { dg-final { scan-assembler-times "sbbq\t%r\[^\n\r]*, 16\\\(%rdi\\\)" 1 { target lp64 } } } */ +/* { dg-final { scan-assembler-times "sbbq\t%r\[^\n\r]*, 24\\\(%rdi\\\)" 1 { target lp64 } } } */ +/* { dg-final { scan-assembler-times "addl\t%e\[^\n\r]*, \\\(%e\[^\n\r]*\\\)" 1 { target ia32 } } } */ +/* { dg-final { scan-assembler-times "adcl\t%e\[^\n\r]*, 4\\\(%e\[^\n\r]*\\\)" 1 { target ia32 } } } */ +/* { dg-final { scan-assembler-times "adcl\t%e\[^\n\r]*, 8\\\(%e\[^\n\r]*\\\)" 1 { target ia32 } } } */ +/* { dg-final { scan-assembler-times "adcl\t%e\[^\n\r]*, 12\\\(%e\[^\n\r]*\\\)" 1 { target ia32 } } } */ +/* { dg-final { scan-assembler-times "subl\t%e\[^\n\r]*, \\\(%e\[^\n\r]*\\\)" 1 { target ia32 } } } */ +/* { dg-final { scan-assembler-times "sbbl\t%e\[^\n\r]*, 4\\\(%e\[^\n\r]*\\\)" 1 { target ia32 } } } */ +/* { dg-final { scan-assembler-times "sbbl\t%e\[^\n\r]*, 8\\\(%e\[^\n\r]*\\\)" 1 { target ia32 } } } */ +/* { dg-final { scan-assembler-times "sbbl\t%e\[^\n\r]*, 12\\\(%e\[^\n\r]*\\\)" 1 { target ia32 } } } */ + +static unsigned long +uaddc (unsigned long x, unsigned long y, unsigned long carry_in, unsigned long *carry_out) +{ + unsigned long r; + unsigned long c1 = __builtin_add_overflow (x, y, &r); + unsigned long c2 = __builtin_add_overflow (r, carry_in, &r); + *carry_out = c1 + c2; + return r; +} + +static unsigned long +usubc (unsigned long x, unsigned long y, unsigned long carry_in, unsigned long *carry_out) +{ + unsigned long r; + unsigned long c1 = __builtin_sub_overflow (x, y, &r); + unsigned long c2 = __builtin_sub_overflow (r, carry_in, &r); + *carry_out = c1 + c2; + return r; +} + +void +foo (unsigned long *p, unsigned long *q) +{ + unsigned long c; + p[0] = uaddc (p[0], q[0], 0, &c); + p[1] = uaddc (p[1], q[1], c, &c); + p[2] = uaddc (p[2], q[2], c, &c); + p[3] = uaddc (p[3], q[3], c, &c); +} + +void +bar (unsigned long *p, unsigned long *q) +{ + unsigned long c; + p[0] = usubc (p[0], q[0], 0, &c); + p[1] = usubc (p[1], q[1], c, &c); + p[2] = usubc (p[2], q[2], c, &c); + p[3] = usubc (p[3], q[3], c, &c); +} diff --git a/gcc/testsuite/gcc.target/i386/pr79173-14.c b/gcc/testsuite/gcc.target/i386/pr79173-14.c new file mode 100644 index 0000000..de85051 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr79173-14.c @@ -0,0 +1,59 @@ +/* PR middle-end/79173 */ +/* { dg-do compile { target { ! ia32 } } } */ +/* { dg-options "-O2 -fno-stack-protector -masm=att -mapxf" } */ +/* { dg-final { scan-assembler-times "addq\t%r\[^\n\r]*, \\\(%rdi\\\)" 1 { target lp64 } } } */ +/* { dg-final { scan-assembler-times "adcq\t%r\[^\n\r]*, 8\\\(%rdi\\\)" 1 { target lp64 } } } */ +/* { dg-final { scan-assembler-times "adcq\t%r\[^\n\r]*, 16\\\(%rdi\\\)" 1 { target lp64 } } } */ +/* { dg-final { scan-assembler-times "adcq\t%r\[^\n\r]*, 24\\\(%rdi\\\)" 1 { target lp64 } } } */ +/* { dg-final { scan-assembler-times "subq\t%r\[^\n\r]*, \\\(%rdi\\\)" 1 { target lp64 } } } */ +/* { dg-final { scan-assembler-times "sbbq\t%r\[^\n\r]*, 8\\\(%rdi\\\)" 1 { target lp64 } } } */ +/* { dg-final { scan-assembler-times "sbbq\t%r\[^\n\r]*, 16\\\(%rdi\\\)" 1 { target lp64 } } } */ +/* { dg-final { scan-assembler-times "sbbq\t%r\[^\n\r]*, 24\\\(%rdi\\\)" 1 { target lp64 } } } */ +/* { dg-final { scan-assembler-times "addl\t%e\[^\n\r]*, \\\(%e\[^\n\r]*\\\)" 1 { target ia32 } } } */ +/* { dg-final { scan-assembler-times "adcl\t%e\[^\n\r]*, 4\\\(%e\[^\n\r]*\\\)" 1 { target ia32 } } } */ +/* { dg-final { scan-assembler-times "adcl\t%e\[^\n\r]*, 8\\\(%e\[^\n\r]*\\\)" 1 { target ia32 } } } */ +/* { dg-final { scan-assembler-times "adcl\t%e\[^\n\r]*, 12\\\(%e\[^\n\r]*\\\)" 1 { target ia32 } } } */ +/* { dg-final { scan-assembler-times "subl\t%e\[^\n\r]*, \\\(%e\[^\n\r]*\\\)" 1 { target ia32 } } } */ +/* { dg-final { scan-assembler-times "sbbl\t%e\[^\n\r]*, 4\\\(%e\[^\n\r]*\\\)" 1 { target ia32 } } } */ +/* { dg-final { scan-assembler-times "sbbl\t%e\[^\n\r]*, 8\\\(%e\[^\n\r]*\\\)" 1 { target ia32 } } } */ +/* { dg-final { scan-assembler-times "sbbl\t%e\[^\n\r]*, 12\\\(%e\[^\n\r]*\\\)" 1 { target ia32 } } } */ + +static unsigned long +uaddc (unsigned long x, unsigned long y, _Bool carry_in, _Bool *carry_out) +{ + unsigned long r; + _Bool c1 = __builtin_add_overflow (x, y, &r); + _Bool c2 = __builtin_add_overflow (r, carry_in, &r); + *carry_out = c1 | c2; + return r; +} + +static unsigned long +usubc (unsigned long x, unsigned long y, _Bool carry_in, _Bool *carry_out) +{ + unsigned long r; + _Bool c1 = __builtin_sub_overflow (x, y, &r); + _Bool c2 = __builtin_sub_overflow (r, carry_in, &r); + *carry_out = c1 | c2; + return r; +} + +void +foo (unsigned long *p, unsigned long *q) +{ + _Bool c; + p[0] = uaddc (p[0], q[0], 0, &c); + p[1] = uaddc (p[1], q[1], c, &c); + p[2] = uaddc (p[2], q[2], c, &c); + p[3] = uaddc (p[3], q[3], c, &c); +} + +void +bar (unsigned long *p, unsigned long *q) +{ + _Bool c; + p[0] = usubc (p[0], q[0], 0, &c); + p[1] = usubc (p[1], q[1], c, &c); + p[2] = usubc (p[2], q[2], c, &c); + p[3] = usubc (p[3], q[3], c, &c); +} diff --git a/gcc/testsuite/gcc.target/i386/pr79173-15.c b/gcc/testsuite/gcc.target/i386/pr79173-15.c new file mode 100644 index 0000000..c3017f7 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr79173-15.c @@ -0,0 +1,61 @@ +/* PR middle-end/79173 */ +/* { dg-do compile { target { ! ia32 } } } */ +/* { dg-options "-O2 -fno-stack-protector -masm=att -mapxf" } */ +/* { dg-final { scan-assembler-times "addq\t%r\[^\n\r]*, \\\(%rdi\\\)" 1 { target lp64 } } } */ +/* { dg-final { scan-assembler-times "adcq\t%r\[^\n\r]*, 8\\\(%rdi\\\)" 1 { target lp64 } } } */ +/* { dg-final { scan-assembler-times "adcq\t%r\[^\n\r]*, 16\\\(%rdi\\\)" 1 { target lp64 } } } */ +/* { dg-final { scan-assembler-times "adcq\t%r\[^\n\r]*, 24\\\(%rdi\\\)" 1 { target lp64 } } } */ +/* { dg-final { scan-assembler-times "subq\t%r\[^\n\r]*, \\\(%rdi\\\)" 1 { target lp64 } } } */ +/* { dg-final { scan-assembler-times "sbbq\t%r\[^\n\r]*, 8\\\(%rdi\\\)" 1 { target lp64 } } } */ +/* { dg-final { scan-assembler-times "sbbq\t%r\[^\n\r]*, 16\\\(%rdi\\\)" 1 { target lp64 } } } */ +/* { dg-final { scan-assembler-times "sbbq\t%r\[^\n\r]*, 24\\\(%rdi\\\)" 1 { target lp64 } } } */ +/* { dg-final { scan-assembler-times "addl\t%e\[^\n\r]*, \\\(%e\[^\n\r]*\\\)" 1 { target ia32 } } } */ +/* { dg-final { scan-assembler-times "adcl\t%e\[^\n\r]*, 4\\\(%e\[^\n\r]*\\\)" 1 { target ia32 } } } */ +/* { dg-final { scan-assembler-times "adcl\t%e\[^\n\r]*, 8\\\(%e\[^\n\r]*\\\)" 1 { target ia32 } } } */ +/* { dg-final { scan-assembler-times "adcl\t%e\[^\n\r]*, 12\\\(%e\[^\n\r]*\\\)" 1 { target ia32 } } } */ +/* { dg-final { scan-assembler-times "subl\t%e\[^\n\r]*, \\\(%e\[^\n\r]*\\\)" 1 { target ia32 } } } */ +/* { dg-final { scan-assembler-times "sbbl\t%e\[^\n\r]*, 4\\\(%e\[^\n\r]*\\\)" 1 { target ia32 } } } */ +/* { dg-final { scan-assembler-times "sbbl\t%e\[^\n\r]*, 8\\\(%e\[^\n\r]*\\\)" 1 { target ia32 } } } */ +/* { dg-final { scan-assembler-times "sbbl\t%e\[^\n\r]*, 12\\\(%e\[^\n\r]*\\\)" 1 { target ia32 } } } */ + +static unsigned long +uaddc (unsigned long x, unsigned long y, unsigned long carry_in, unsigned long *carry_out) +{ + unsigned long r; + unsigned long c1 = __builtin_add_overflow (x, y, &r); + unsigned long c2 = __builtin_add_overflow (r, carry_in, &r); + *carry_out = c1 + c2; + return r; +} + +static unsigned long +usubc (unsigned long x, unsigned long y, unsigned long carry_in, unsigned long *carry_out) +{ + unsigned long r; + unsigned long c1 = __builtin_sub_overflow (x, y, &r); + unsigned long c2 = __builtin_sub_overflow (r, carry_in, &r); + *carry_out = c1 + c2; + return r; +} + +unsigned long +foo (unsigned long *p, unsigned long *q) +{ + unsigned long c; + p[0] = uaddc (p[0], q[0], 0, &c); + p[1] = uaddc (p[1], q[1], c, &c); + p[2] = uaddc (p[2], q[2], c, &c); + p[3] = uaddc (p[3], q[3], c, &c); + return c; +} + +unsigned long +bar (unsigned long *p, unsigned long *q) +{ + unsigned long c; + p[0] = usubc (p[0], q[0], 0, &c); + p[1] = usubc (p[1], q[1], c, &c); + p[2] = usubc (p[2], q[2], c, &c); + p[3] = usubc (p[3], q[3], c, &c); + return c; +} diff --git a/gcc/testsuite/gcc.target/i386/pr79173-16.c b/gcc/testsuite/gcc.target/i386/pr79173-16.c new file mode 100644 index 0000000..91062fb --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr79173-16.c @@ -0,0 +1,61 @@ +/* PR middle-end/79173 */ +/* { dg-do compile { target { ! ia32 } } } */ +/* { dg-options "-O2 -fno-stack-protector -masm=att -mapxf" } */ +/* { dg-final { scan-assembler-times "addq\t%r\[^\n\r]*, \\\(%rdi\\\)" 1 { target lp64 } } } */ +/* { dg-final { scan-assembler-times "adcq\t%r\[^\n\r]*, 8\\\(%rdi\\\)" 1 { target lp64 } } } */ +/* { dg-final { scan-assembler-times "adcq\t%r\[^\n\r]*, 16\\\(%rdi\\\)" 1 { target lp64 } } } */ +/* { dg-final { scan-assembler-times "adcq\t%r\[^\n\r]*, 24\\\(%rdi\\\)" 1 { target lp64 } } } */ +/* { dg-final { scan-assembler-times "subq\t%r\[^\n\r]*, \\\(%rdi\\\)" 1 { target lp64 } } } */ +/* { dg-final { scan-assembler-times "sbbq\t%r\[^\n\r]*, 8\\\(%rdi\\\)" 1 { target lp64 } } } */ +/* { dg-final { scan-assembler-times "sbbq\t%r\[^\n\r]*, 16\\\(%rdi\\\)" 1 { target lp64 } } } */ +/* { dg-final { scan-assembler-times "sbbq\t%r\[^\n\r]*, 24\\\(%rdi\\\)" 1 { target lp64 } } } */ +/* { dg-final { scan-assembler-times "addl\t%e\[^\n\r]*, \\\(%e\[^\n\r]*\\\)" 1 { target ia32 } } } */ +/* { dg-final { scan-assembler-times "adcl\t%e\[^\n\r]*, 4\\\(%e\[^\n\r]*\\\)" 1 { target ia32 } } } */ +/* { dg-final { scan-assembler-times "adcl\t%e\[^\n\r]*, 8\\\(%e\[^\n\r]*\\\)" 1 { target ia32 } } } */ +/* { dg-final { scan-assembler-times "adcl\t%e\[^\n\r]*, 12\\\(%e\[^\n\r]*\\\)" 1 { target ia32 } } } */ +/* { dg-final { scan-assembler-times "subl\t%e\[^\n\r]*, \\\(%e\[^\n\r]*\\\)" 1 { target ia32 } } } */ +/* { dg-final { scan-assembler-times "sbbl\t%e\[^\n\r]*, 4\\\(%e\[^\n\r]*\\\)" 1 { target ia32 } } } */ +/* { dg-final { scan-assembler-times "sbbl\t%e\[^\n\r]*, 8\\\(%e\[^\n\r]*\\\)" 1 { target ia32 } } } */ +/* { dg-final { scan-assembler-times "sbbl\t%e\[^\n\r]*, 12\\\(%e\[^\n\r]*\\\)" 1 { target ia32 } } } */ + +static unsigned long +uaddc (unsigned long x, unsigned long y, _Bool carry_in, _Bool *carry_out) +{ + unsigned long r; + _Bool c1 = __builtin_add_overflow (x, y, &r); + _Bool c2 = __builtin_add_overflow (r, carry_in, &r); + *carry_out = c1 ^ c2; + return r; +} + +static unsigned long +usubc (unsigned long x, unsigned long y, _Bool carry_in, _Bool *carry_out) +{ + unsigned long r; + _Bool c1 = __builtin_sub_overflow (x, y, &r); + _Bool c2 = __builtin_sub_overflow (r, carry_in, &r); + *carry_out = c1 ^ c2; + return r; +} + +_Bool +foo (unsigned long *p, unsigned long *q) +{ + _Bool c; + p[0] = uaddc (p[0], q[0], 0, &c); + p[1] = uaddc (p[1], q[1], c, &c); + p[2] = uaddc (p[2], q[2], c, &c); + p[3] = uaddc (p[3], q[3], c, &c); + return c; +} + +_Bool +bar (unsigned long *p, unsigned long *q) +{ + _Bool c; + p[0] = usubc (p[0], q[0], 0, &c); + p[1] = usubc (p[1], q[1], c, &c); + p[2] = usubc (p[2], q[2], c, &c); + p[3] = usubc (p[3], q[3], c, &c); + return c; +} diff --git a/gcc/testsuite/gcc.target/i386/pr79173-17.c b/gcc/testsuite/gcc.target/i386/pr79173-17.c new file mode 100644 index 0000000..e27f4b9 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr79173-17.c @@ -0,0 +1,32 @@ +/* PR middle-end/79173 */ +/* { dg-do compile { target { ! ia32 } } } */ +/* { dg-options "-O2 -fno-stack-protector -masm=att -mapxf" } */ +/* { dg-final { scan-assembler-times "addq\t%r\[^\n\r]*, \\\(%rdi\\\)" 1 { target lp64 } } } */ +/* { dg-final { scan-assembler-times "adcq\t%r\[^\n\r]*, 8\\\(%rdi\\\)" 1 { target lp64 } } } */ +/* { dg-final { scan-assembler-times "adcq\t%r\[^\n\r]*, 16\\\(%rdi\\\)" 1 { target lp64 } } } */ +/* { dg-final { scan-assembler-times "adcq\t%r\[^\n\r]*, 24\\\(%rdi\\\)" 1 { target lp64 } } } */ +/* { dg-final { scan-assembler-times "addl\t%e\[^\n\r]*, \\\(%e\[^\n\r]*\\\)" 1 { target ia32 } } } */ +/* { dg-final { scan-assembler-times "adcl\t%e\[^\n\r]*, 4\\\(%e\[^\n\r]*\\\)" 1 { target ia32 } } } */ +/* { dg-final { scan-assembler-times "adcl\t%e\[^\n\r]*, 8\\\(%e\[^\n\r]*\\\)" 1 { target ia32 } } } */ +/* { dg-final { scan-assembler-times "adcl\t%e\[^\n\r]*, 12\\\(%e\[^\n\r]*\\\)" 1 { target ia32 } } } */ + +static unsigned long +uaddc (unsigned long x, unsigned long y, unsigned long carry_in, unsigned long *carry_out) +{ + unsigned long r = x + y; + unsigned long c1 = r < x; + r += carry_in; + unsigned long c2 = r < carry_in; + *carry_out = c1 + c2; + return r; +} + +void +foo (unsigned long *p, unsigned long *q) +{ + unsigned long c; + p[0] = uaddc (p[0], q[0], 0, &c); + p[1] = uaddc (p[1], q[1], c, &c); + p[2] = uaddc (p[2], q[2], c, &c); + p[3] = uaddc (p[3], q[3], c, &c); +} diff --git a/gcc/testsuite/gcc.target/i386/pr79173-18.c b/gcc/testsuite/gcc.target/i386/pr79173-18.c new file mode 100644 index 0000000..2728ae7 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr79173-18.c @@ -0,0 +1,33 @@ +/* PR middle-end/79173 */ +/* { dg-do compile { target { ! ia32 } } } */ +/* { dg-options "-O2 -fno-stack-protector -masm=att -mapxf" } */ +/* { dg-final { scan-assembler-times "addq\t%r\[^\n\r]*, \\\(%rdi\\\)" 1 { target lp64 } } } */ +/* { dg-final { scan-assembler-times "adcq\t%r\[^\n\r]*, 8\\\(%rdi\\\)" 1 { target lp64 } } } */ +/* { dg-final { scan-assembler-times "adcq\t%r\[^\n\r]*, 16\\\(%rdi\\\)" 1 { target lp64 } } } */ +/* { dg-final { scan-assembler-times "adcq\t%r\[^\n\r]*, 24\\\(%rdi\\\)" 1 { target lp64 } } } */ +/* { dg-final { scan-assembler-times "addl\t%e\[^\n\r]*, \\\(%e\[^\n\r]*\\\)" 1 { target ia32 } } } */ +/* { dg-final { scan-assembler-times "adcl\t%e\[^\n\r]*, 4\\\(%e\[^\n\r]*\\\)" 1 { target ia32 } } } */ +/* { dg-final { scan-assembler-times "adcl\t%e\[^\n\r]*, 8\\\(%e\[^\n\r]*\\\)" 1 { target ia32 } } } */ +/* { dg-final { scan-assembler-times "adcl\t%e\[^\n\r]*, 12\\\(%e\[^\n\r]*\\\)" 1 { target ia32 } } } */ + +static unsigned long +uaddc (unsigned long x, unsigned long y, unsigned long carry_in, unsigned long *carry_out) +{ + unsigned long r = x + y; + unsigned long c1 = r < x; + r += carry_in; + unsigned long c2 = r < carry_in; + *carry_out = c1 + c2; + return r; +} + +unsigned long +foo (unsigned long *p, unsigned long *q) +{ + unsigned long c; + p[0] = uaddc (p[0], q[0], 0, &c); + p[1] = uaddc (p[1], q[1], c, &c); + p[2] = uaddc (p[2], q[2], c, &c); + p[3] = uaddc (p[3], q[3], c, &c); + return c; +} 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/arch-60.c b/gcc/testsuite/gcc.target/riscv/arch-60.c new file mode 100644 index 0000000..ea599f2 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/arch-60.c @@ -0,0 +1,5 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64i_svbare -mabi=lp64" } */ +int foo() +{ +} diff --git a/gcc/testsuite/gcc.target/riscv/arch-shlocofideleg.c b/gcc/testsuite/gcc.target/riscv/arch-shlocofideleg.c new file mode 100644 index 0000000..de9f9fc --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/arch-shlocofideleg.c @@ -0,0 +1,5 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64i_shlcofideleg -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/gfortran.dg/save_8.f90 b/gcc/testsuite/gfortran.dg/save_8.f90 new file mode 100644 index 0000000..8e9198c --- /dev/null +++ b/gcc/testsuite/gfortran.dg/save_8.f90 @@ -0,0 +1,13 @@ +!{ dg-do run } + +! Check PR120483 is fixed. +! Contributed by Thomas Koenig <tkoenig@gcc.gnu.org> +! and Peter Güntert <peter@guentert.com> + +program save_8 + implicit none + character(len=:), allocatable, save :: s1 + s1 = 'ABC' + if (s1(3:3) /= 'C') stop 1 +end program save_8 + 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-ssa-ccp.cc b/gcc/tree-ssa-ccp.cc index 8d2cbb3..3e0c75c 100644 --- a/gcc/tree-ssa-ccp.cc +++ b/gcc/tree-ssa-ccp.cc @@ -298,7 +298,7 @@ get_default_value (tree var) { val.lattice_val = VARYING; val.mask = -1; - if (flag_tree_bit_ccp) + if (flag_tree_bit_ccp && !VECTOR_TYPE_P (TREE_TYPE (var))) { wide_int nonzero_bits = get_nonzero_bits (var); tree value; @@ -2491,11 +2491,11 @@ evaluate_stmt (gimple *stmt) is_constant = (val.lattice_val == CONSTANT); } + tree lhs = gimple_get_lhs (stmt); if (flag_tree_bit_ccp + && lhs && TREE_CODE (lhs) == SSA_NAME && !VECTOR_TYPE_P (TREE_TYPE (lhs)) && ((is_constant && TREE_CODE (val.value) == INTEGER_CST) - || !is_constant) - && gimple_get_lhs (stmt) - && TREE_CODE (gimple_get_lhs (stmt)) == SSA_NAME) + || !is_constant)) { tree lhs = gimple_get_lhs (stmt); wide_int nonzero_bits = get_nonzero_bits (lhs); diff --git a/gcc/tree-ssa-forwprop.cc b/gcc/tree-ssa-forwprop.cc index 81ea7d4..27197bb 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; @@ -1344,6 +1343,88 @@ optimize_memcpy_to_memset (gimple_stmt_iterator *gsip, tree dest, tree src, tree } return true; } +/* Optimizes + a = c; + b = a; + into + a = c; + b = c; + GSIP is the second statement and SRC is the common + between the statements. +*/ +static bool +optimize_agr_copyprop (gimple_stmt_iterator *gsip) +{ + gimple *stmt = gsi_stmt (*gsip); + if (gimple_has_volatile_ops (stmt)) + return false; + + tree dest = gimple_assign_lhs (stmt); + tree src = gimple_assign_rhs1 (stmt); + /* If the statement is `src = src;` then ignore it. */ + if (operand_equal_p (dest, src, 0)) + return false; + + tree vuse = gimple_vuse (stmt); + /* If the vuse is the default definition, then there is no store beforehand. */ + if (SSA_NAME_IS_DEFAULT_DEF (vuse)) + return false; + gimple *defstmt = SSA_NAME_DEF_STMT (vuse); + if (!gimple_assign_load_p (defstmt) + || !gimple_store_p (defstmt)) + return false; + if (gimple_has_volatile_ops (defstmt)) + return false; + + tree dest2 = gimple_assign_lhs (defstmt); + tree src2 = gimple_assign_rhs1 (defstmt); + + /* If the original store is `src2 = src2;` skip over it. */ + if (operand_equal_p (src2, dest2, 0)) + return false; + if (!operand_equal_p (src, dest2, 0)) + return false; + + + /* For 2 memory refences and using a temporary to do the copy, + don't remove the temporary as the 2 memory references might overlap. + Note t does not need to be decl as it could be field. + See PR 22237 for full details. + E.g. + t = *a; + *b = t; + Cannot be convert into + t = *a; + *b = *a; + Though the following is allowed to be done: + t = *a; + *a = t; + And convert it into: + t = *a; + *a = *a; + */ + if (!operand_equal_p (src2, dest, 0) + && !DECL_P (dest) && !DECL_P (src2)) + return false; + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Simplified\n "); + print_gimple_stmt (dump_file, stmt, 0, dump_flags); + fprintf (dump_file, "after previous\n "); + print_gimple_stmt (dump_file, defstmt, 0, dump_flags); + } + gimple_assign_set_rhs_from_tree (gsip, unshare_expr (src2)); + update_stmt (stmt); + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "into\n "); + print_gimple_stmt (dump_file, stmt, 0, dump_flags); + } + statistics_counter_event (cfun, "copy prop for aggregate", 1); + return true; +} /* *GSI_P is a GIMPLE_CALL to a builtin function. Optimize @@ -3387,6 +3468,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 +3577,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 +3597,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 +4251,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 +4488,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 +4528,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); @@ -4720,6 +4806,11 @@ pass_forwprop::execute (function *fun) changed = true; break; } + if (optimize_agr_copyprop (&gsi)) + { + changed = true; + break; + } } if (TREE_CODE_CLASS (code) == tcc_comparison) diff --git a/gcc/tree-ssanames.cc b/gcc/tree-ssanames.cc index fd2abfe..b6ca880 100644 --- a/gcc/tree-ssanames.cc +++ b/gcc/tree-ssanames.cc @@ -508,6 +508,14 @@ get_nonzero_bits_1 (const_tree name) /* Use element_precision instead of TYPE_PRECISION so complex and vector types get a non-zero precision. */ unsigned int precision = element_precision (TREE_TYPE (name)); + + if (VECTOR_TYPE_P (TREE_TYPE (name))) + { + tree elem = uniform_vector_p (name); + if (elem) + return get_nonzero_bits_1 (elem); + } + if (TREE_CODE (name) != SSA_NAME) return wi::shwi (-1, precision); 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/var-tracking.cc b/gcc/var-tracking.cc index d70ed02..8732c3b 100644 --- a/gcc/var-tracking.cc +++ b/gcc/var-tracking.cc @@ -6273,7 +6273,7 @@ prepare_call_arguments (basic_block bb, rtx_insn *insn) if (SYMBOL_REF_DECL (symbol)) fndecl = SYMBOL_REF_DECL (symbol); } - if (fndecl == NULL_TREE) + if (fndecl == NULL_TREE && MEM_P (XEXP (call, 0))) fndecl = MEM_EXPR (XEXP (call, 0)); if (fndecl && TREE_CODE (TREE_TYPE (fndecl)) != FUNCTION_TYPE 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/charmaps.cc b/libgcobol/charmaps.cc index 2cdcfc0..eb82609 100644 --- a/libgcobol/charmaps.cc +++ b/libgcobol/charmaps.cc @@ -435,7 +435,7 @@ __gg__raw_to_ascii(char **dest, size_t *dest_size, const char *in, size_t length size_t code_point; // Pull the next code_point from the UTF-8 stream - long unicode_point = extract_next_code_point((const unsigned char *)in, + long unicode_point = extract_next_code_point(reinterpret_cast<const unsigned char *>(in), length, position ); @@ -497,7 +497,7 @@ __gg__raw_to_ebcdic(char **dest, size_t *dest_size, const char *in, size_t lengt } // Pull the next code_point from the UTF-8 stream - long unicode_point = extract_next_code_point( (const unsigned char *)in, + long unicode_point = extract_next_code_point( reinterpret_cast<const unsigned char *>(in), length, position ); // Check for that unicode code point in the subset of characters we @@ -722,7 +722,8 @@ char *__gg__ebcdic_to_console(char **dest, const size_t length) { static size_t ebcdic_size = MINIMUM_ALLOCATION_SIZE; - static char *ebcdic = (char *)malloc(ebcdic_size); + static char *ebcdic = static_cast<char *>(malloc(ebcdic_size)); + if(!ebcdic)abort(); __gg__realloc_if_necessary(&ebcdic, &ebcdic_size, length); memcpy(ebcdic, str, length); @@ -757,7 +758,7 @@ void __gg__console_to_ascii(char * const str, size_t length) size_t code_point; // Pull the next code_point from the UTF-8 stream long unicode_point - = extract_next_code_point( (const unsigned char *)str, + = extract_next_code_point( reinterpret_cast<const unsigned char *>(str), length, position ); if( unicode_point == -1 ) @@ -797,7 +798,7 @@ __gg__console_to_ebcdic(char * const str, size_t length) size_t code_point; // Pull the next code_point from the UTF-8 stream long unicode_point - = extract_next_code_point( (const unsigned char *)str, + = extract_next_code_point( reinterpret_cast<const unsigned char *>(str), length, position ); if( unicode_point == -1 ) diff --git a/libgcobol/common-defs.h b/libgcobol/common-defs.h index 2aecc8f..764d9f8 100644 --- a/libgcobol/common-defs.h +++ b/libgcobol/common-defs.h @@ -464,16 +464,20 @@ struct cbl_declarative_t { uint32_t nfile, files[files_max]; cbl_file_mode_t mode; + // cppcheck-suppress noExplicitConstructor cbl_declarative_t( cbl_file_mode_t mode = file_mode_none_e ) - : section(0), global(false) + : section(0) + , global(false) , type(ec_none_e) , nfile(0) , mode(mode) { std::fill(files, files + COUNT_OF(files), 0); } + // cppcheck-suppress noExplicitConstructor cbl_declarative_t( ec_type_t type ) - : section(0), global(false) + : section(0) + , global(false) , type(type) , nfile(0) , mode(file_mode_none_e) @@ -533,9 +537,9 @@ struct cbl_declarative_t { return section < that.section; } - // TRUE if there are no files to match, or the provided file is in the list. - bool match_file( size_t file ) const { - static const auto pend = files + nfile; + // TRUE if there are no files to match, or the provided file is in the list. + bool match_file( size_t file ) const { + static const auto pend = files + nfile; // cppcheck-suppress constVariablePointer return nfile == 0 || pend != std::find(files, files + nfile, file); } diff --git a/libgcobol/gfileio.cc b/libgcobol/gfileio.cc index 806f4a9..c091021 100644 --- a/libgcobol/gfileio.cc +++ b/libgcobol/gfileio.cc @@ -28,6 +28,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +// cppcheck-suppress-file postfixOperator + #include <err.h> #include <fcntl.h> #include <unistd.h> @@ -105,6 +107,11 @@ */ +/* cppcheck has its opinions about ++iterator being superior to iterator++. + however, can't abide by the prefix notation; it just looks dumb to me. + And I have to believe that in the year of our Lord 2025 that the + optimizing algorithms in modern compilers have sorted this out by now. */ + extern "C" void __gg__handle_error(const char *function, const char *msg) @@ -191,11 +198,12 @@ handle_errno(cblc_file_t *file, const char *function, const char *msg) static char * -get_filename( cblc_file_t *file, +get_filename( const cblc_file_t *file, int is_quoted) { static size_t fname_size = MINIMUM_ALLOCATION_SIZE; - static char *fname = (char *)malloc(MINIMUM_ALLOCATION_SIZE); + static char *fname = static_cast<char *>(malloc(MINIMUM_ALLOCATION_SIZE)); + massert(fname); fname = internal_to_console(&fname, &fname_size, file->filename, @@ -205,14 +213,15 @@ get_filename( cblc_file_t *file, { // We have been given something that might be the name of an // environment variable that contains the filename: - char *p_from_environment = getenv(fname); + const char *p_from_environment = getenv(fname); if( p_from_environment ) { if( strlen(p_from_environment)+1 > fname_size ) { fname_size = strlen(p_from_environment)+1; free(fname); - fname = (char *)malloc(fname_size); + fname = static_cast<char *>(malloc(fname_size)); + massert(fname); } strcpy(fname, p_from_environment); } @@ -272,7 +281,7 @@ __gg__set_user_status(cblc_field_t *ustatus, cblc_file_t *file) } static long -max_value(cblc_field_t *key) +max_value(const cblc_field_t *key) { long retval; if( key->digits ) @@ -537,7 +546,8 @@ relative_file_delete_varying(cblc_file_t *file, bool is_random) size_t payload_length; - unsigned char *stash = (unsigned char *)malloc(file->default_record->capacity); + unsigned char *stash = static_cast<unsigned char *>(malloc(file->default_record->capacity)); + massert(stash); memcpy(stash, file->default_record->data, file->default_record->capacity); long starting_pos = ftell(file->file_pointer); @@ -654,7 +664,8 @@ relative_file_delete(cblc_file_t *file, bool is_random) char record_marker; - unsigned char *stash = (unsigned char *)malloc(file->default_record->capacity); + unsigned char *stash = static_cast<unsigned char *>(malloc(file->default_record->capacity)); + massert(stash); memcpy(stash, file->default_record->data, file->default_record->capacity); long starting_pos = ftell(file->file_pointer); @@ -829,7 +840,7 @@ read_an_indexed_record( cblc_file_t *file, goto done; } - record_length = ach[0]<<8; + record_length = static_cast<long>(ach[0])<<8; record_length += ach[1]; if(ach[2] != 0) { @@ -906,7 +917,7 @@ position_state_preserve(cblc_file_t *file, position_state_t &state) } static void -position_state_restore(cblc_file_t *file, position_state_t &state) +position_state_restore(cblc_file_t *file, const position_state_t &state) { file->recent_key = state.recent_key; fseek(file->file_pointer, state.starting_position, SEEK_SET); @@ -973,7 +984,8 @@ indexed_file_delete(cblc_file_t *file, bool is_random) // and the record area itself are unchanged by the delete operation. // So, we save the current record area: - stash = (unsigned char *)malloc(file->record_area_max); + stash = static_cast<unsigned char *>(malloc(file->record_area_max)); + massert(stash); memcpy(stash, file->default_record->data, file->record_area_max); // And the position state of our file @@ -1051,8 +1063,6 @@ indexed_file_delete(cblc_file_t *file, bool is_random) // we find one, we check to see if the keys match. If the keys don't // match, then we have to remove the existing one from the index. - std::vector<unsigned char> the_key - = file_indexed_make_key(file, key_number); bool deleting = true; while(deleting) { @@ -1069,6 +1079,7 @@ indexed_file_delete(cblc_file_t *file, bool is_random) deleting = true; break; } + it++; } } @@ -1234,7 +1245,7 @@ indexed_file_start( cblc_file_t *file, file->io_status = FsErrno; } } - else if( result < 0 ) + else // if( result < 0 ) { // The index is less than the key. if( relop == lt_op @@ -1656,7 +1667,7 @@ sequential_file_rewrite( cblc_file_t *file, size_t length ) if( file->record_area_min != file->record_area_max ) { - unsigned char preamble[4] = + const unsigned char preamble[4] = { (unsigned char)(bytes_to_write>>8), (unsigned char)(bytes_to_write), @@ -1688,7 +1699,6 @@ done: fseek(file->file_pointer, starting_position, SEEK_SET); handle_ferror(file, __func__, "fseek() error"); file->prior_op = file_op_rewrite; - file->prior_op = file_op_rewrite; establish_status(file, starting_position); } @@ -2210,7 +2220,7 @@ __io__file_rewrite(cblc_file_t *file, size_t length, bool is_random) static void relative_file_write_varying(cblc_file_t *file, - unsigned char *location, + const unsigned char *location, size_t length, bool is_random) { @@ -2359,7 +2369,7 @@ done: static void relative_file_write(cblc_file_t *file, - unsigned char *location, + const unsigned char *location, size_t length, bool is_random) { @@ -2374,7 +2384,7 @@ relative_file_write(cblc_file_t *file, file->io_status = FsErrno; long necessary_file_size; - unsigned char achPostamble[] = {internal_cr, internal_newline}; + const unsigned char achPostamble[] = {internal_cr, internal_newline}; relative_file_parameters rfp; @@ -2493,7 +2503,7 @@ done: static void sequential_file_write(cblc_file_t *file, - unsigned char *location, + const unsigned char *location, size_t length, int after, int lines) @@ -2609,7 +2619,7 @@ sequential_file_write(cblc_file_t *file, { // Because of the min/max mismatch, we require a preamble: // The first two bytes are the big-endian character count - unsigned char preamble[4] = + const unsigned char preamble[4] = { (unsigned char)(characters_to_write>>8), (unsigned char)(characters_to_write), @@ -2681,7 +2691,7 @@ done: static void indexed_file_write( cblc_file_t *file, - unsigned char *location, + const unsigned char *location, size_t length, bool is_random) { @@ -2752,13 +2762,13 @@ indexed_file_write( cblc_file_t *file, // We are allowed to do the write, but only if there will be no key // violations as a result: - for(size_t key_number=1; - key_number<file->supplemental->indexes.size(); - key_number++) + for(size_t keynum=1; + keynum<file->supplemental->indexes.size(); + keynum++) { - if( file->supplemental->uniques[key_number] ) + if( file->supplemental->uniques[keynum] ) { - long record_position = file_indexed_first_position(file, key_number); + long record_position = file_indexed_first_position(file, keynum); if( record_position != -1 ) { // No can do, because we already have a unique key with that value @@ -2849,7 +2859,7 @@ done: static void __io__file_write( cblc_file_t *file, - unsigned char *location, + const unsigned char *location, size_t length, int after, int lines, @@ -2983,7 +2993,7 @@ line_sequential_file_read( cblc_file_t *file) { break; } - if( ch == file->delimiter || ch == EOF ) + if( ch == EOF ) { hit_eof = true; clearerr(file->file_pointer); @@ -3647,6 +3657,7 @@ indexed_file_read( cblc_file_t *file, goto done; } + // cppcheck-suppress derefInvalidIteratorRedundantCheck fpos = file_index->current_iterator->second; if( file_index->current_iterator == file_index->key_to_position.end() ) @@ -3728,6 +3739,7 @@ indexed_file_read( cblc_file_t *file, // We are ready to proceed + // cppcheck-suppress derefInvalidIteratorRedundantCheck fpos = file_index->current_iterator->second; if( file_index->current_iterator == file_index->key_to_position.end() ) { @@ -3922,7 +3934,6 @@ file_indexed_open(cblc_file_t *file) { if( file->key_numbers[index] != current_key_number ) { - file_index_t file_index; file->supplemental->indexes.push_back(file_index); current_key_number = file->key_numbers[index]; file->supplemental->uniques.push_back(file->uniques[index]); @@ -3952,7 +3963,8 @@ file_indexed_open(cblc_file_t *file) // We need to open the file for reading, and build the // maps for each index: static size_t fname_size = MINIMUM_ALLOCATION_SIZE; - static char *fname = (char *)malloc(fname_size); + static char *fname = static_cast<char *>(malloc(fname_size)); + massert(fname); internal_to_console(&fname, &fname_size, @@ -3969,7 +3981,8 @@ file_indexed_open(cblc_file_t *file) } // Stash the existing record area: - stash = (unsigned char *)malloc(file->record_area_max); + stash = static_cast<unsigned char *>(malloc(file->record_area_max)); + massert(stash); memcpy( stash, file->default_record->data, file->record_area_max); @@ -4111,7 +4124,8 @@ __gg__file_reopen(cblc_file_t *file, int mode_char) } static size_t fname_size = MINIMUM_ALLOCATION_SIZE; - static char *fname = (char *)malloc(fname_size); + static char *fname = static_cast<char *>(malloc(fname_size)); + massert(fname) internal_to_console(&fname, &fname_size, file->filename, @@ -4465,7 +4479,7 @@ public: typedef void (read_t)( cblc_file_t *file, int where ); typedef void (write_t)( cblc_file_t *file, - unsigned char *location, + const unsigned char *location, size_t length, int after, int lines, diff --git a/libgcobol/gmath.cc b/libgcobol/gmath.cc index e51cf9f..8a9880b 100644 --- a/libgcobol/gmath.cc +++ b/libgcobol/gmath.cc @@ -88,7 +88,8 @@ conditional_stash( cblc_field_t *destination, // This is slightly more complex, because in the event of a // SIZE ERROR. we need to leave the original value untouched - unsigned char *stash = (unsigned char *)malloc(destination_s); + unsigned char *stash = static_cast<unsigned char *>(malloc(destination_s)); + massert(stash); memcpy(stash, destination->data+destination_o, destination_s); __gg__int128_to_qualified_field(destination, @@ -132,7 +133,9 @@ conditional_stash( cblc_field_t *destination, { // This is slightly more complex, because in the event of a // SIZE ERROR. we need to leave the original value untouched - unsigned char *stash = (unsigned char *)malloc(destination_s); + assert(destination_s); + unsigned char *stash = static_cast<unsigned char *>(malloc(destination_s)); + massert(stash); memcpy(stash, destination->data+destination_o, destination_s); __gg__float128_to_qualified_field(destination, destination_o, @@ -256,20 +259,20 @@ __gg__pow( cbl_arith_format_t, size_t, size_t, size_t, - cbl_round_t *rounded, + const cbl_round_t *rounded, int on_error_flag, int *compute_error ) { - cblc_field_t **A = __gg__treeplet_1f; - size_t *A_o = __gg__treeplet_1o; - size_t *A_s = __gg__treeplet_1s; - cblc_field_t **B = __gg__treeplet_2f; - size_t *B_o = __gg__treeplet_2o; - size_t *B_s = __gg__treeplet_2s; - cblc_field_t **C = __gg__treeplet_3f; - size_t *C_o = __gg__treeplet_3o; - size_t *C_s = __gg__treeplet_3s; + cblc_field_t **A = __gg__treeplet_1f; + const size_t *A_o = __gg__treeplet_1o; + const size_t *A_s = __gg__treeplet_1s; + cblc_field_t **B = __gg__treeplet_2f; + const size_t *B_o = __gg__treeplet_2o; + const size_t *B_s = __gg__treeplet_2s; + cblc_field_t **C = __gg__treeplet_3f; + const size_t *C_o = __gg__treeplet_3o; + const size_t *C_s = __gg__treeplet_3s; GCOB_FP128 avalue = __gg__float128_from_qualified_field(A[0], A_o[0], A_s[0]); GCOB_FP128 bvalue = __gg__float128_from_qualified_field(B[0], B_o[0], B_s[0]); @@ -368,8 +371,8 @@ multiply_int256_by_int64(int256 &product, const uint64_t multiplier) for(int i=0; i<4; i++) { uint128 temp = (uint128)product.i64[i] * multiplier; - product.i64[i] = *(uint64_t *)(&temp); - overflows[i+1] = *(uint64_t *)((uint8_t *)(&temp) + 8); + product.i64[i] = *PTRCAST(uint64_t, &temp); + overflows[i+1] = *PTRCAST(uint64_t, PTRCAST(uint8_t, &temp) + 8); } for(int i=1; i<4; i++) @@ -386,7 +389,7 @@ multiply_int256_by_int64(int256 &product, const uint64_t multiplier) } static int -add_int256_to_int256(int256 &sum, const int256 addend) +add_int256_to_int256(int256 &sum, const int256 &addend) { uint128 overflows[3] = {}; for(int i=0; i<2; i++) @@ -451,10 +454,11 @@ divide_int256_by_int64(int256 &val, uint64_t divisor) for( int i=3; i>=0; i-- ) { // Left shift temp 64 bits: - *(uint64_t *)(((uint8_t *)&temp)+8) = *(uint64_t *)(((uint8_t *)&temp)+0); + *PTRCAST(uint64_t, ((PTRCAST(uint8_t, &temp))+8)) + = *PTRCAST(uint64_t, ((PTRCAST(uint8_t, &temp))+0)); // Put the high digit of val into the bottom of temp - *(uint64_t *)(((uint8_t *)&temp)+0) = val.i64[i]; + *PTRCAST(uint64_t, ((PTRCAST(uint8_t, &temp))+0)) = val.i64[i]; // Divide that combinary by divisor to get the new digits val.i64[i] = temp / divisor; @@ -469,7 +473,8 @@ squeeze_int256(int256 &val, int &rdigits) { int overflow = 0; // It has been decreed that at this juncture the result must fit into - // MAX_FIXED_POINT_DIGITS. If the result does not, we have an OVERFLOW error. + // MAX_FIXED_POINT_DIGITS. If the result does not, we have an OVERFLOW + // error. int is_negative = val.data[31] & 0x80; if( is_negative ) @@ -477,9 +482,9 @@ squeeze_int256(int256 &val, int &rdigits) negate_int256(val); } - // As long as there are some decimal places left, we hold our nose and right- - // shift a too-large value rightward by decimal digits. In other words, we - // truncate the fractional part to make room for the integer part: + // As long as there are some decimal places left, we hold our nose and + // right-shift a too-large value rightward by decimal digits. In other + // words, we truncate the fractional part to make room for the integer part: while(rdigits > 0 && val.i128[1] ) { divide_int256_by_int64(val, 10UL); @@ -504,7 +509,7 @@ squeeze_int256(int256 &val, int &rdigits) // These sixteen bytes comprise the binary value of 10^38 static const uint8_t C1038[] = {0x00, 0x00, 0x00, 0x00, 0x40, 0x22, 0x8a, 0x09, 0x7a, 0xc4, 0x86, 0x5a, 0xa8, 0x4c, 0x3b, 0x4b}; - static const uint128 biggest = *(uint128 *)C1038; + static const uint128 biggest = *reinterpret_cast<const uint128 *>(C1038); // If we still have some rdigits to throw away, we can keep shrinking // the value: @@ -540,7 +545,7 @@ squeeze_int256(int256 &val, int &rdigits) static void get_int256_from_qualified_field(int256 &var, int &rdigits, - cblc_field_t *field, + const cblc_field_t *field, size_t field_o, size_t field_s) { @@ -571,7 +576,7 @@ __gg__add_fixed_phase1( cbl_arith_format_t , size_t nA, size_t , size_t , - cbl_round_t *, + const cbl_round_t *, int , int *compute_error ) @@ -580,9 +585,9 @@ __gg__add_fixed_phase1( cbl_arith_format_t , // The result goes into the temporary phase1_result. - cblc_field_t **A = __gg__treeplet_1f; - size_t *A_o = __gg__treeplet_1o; - size_t *A_s = __gg__treeplet_1s; + cblc_field_t **A = __gg__treeplet_1f; + const size_t *A_o = __gg__treeplet_1o; + const size_t *A_s = __gg__treeplet_1s; // Let us prime the pump with the first value of A[] get_int256_from_qualified_field(phase1_result, phase1_rdigits, A[0], A_o[0], A_s[0]); @@ -600,7 +605,6 @@ __gg__add_fixed_phase1( cbl_arith_format_t , if( phase1_rdigits > temp_rdigits ) { scale_int256_by_digits(temp, phase1_rdigits - temp_rdigits); - temp_rdigits = phase1_rdigits; } else if( phase1_rdigits < temp_rdigits ) { @@ -628,14 +632,14 @@ __gg__addf1_fixed_phase2( cbl_arith_format_t , size_t , size_t , size_t , - cbl_round_t *rounded, + const cbl_round_t *rounded, int on_error_flag, int *compute_error ) { - cblc_field_t **C = __gg__treeplet_3f; - size_t *C_o = __gg__treeplet_3o; - size_t *C_s = __gg__treeplet_3s; + cblc_field_t **C = __gg__treeplet_3f; + const size_t *C_o = __gg__treeplet_3o; + const size_t *C_s = __gg__treeplet_3s; // This is the assignment phase of an ADD Format 1 @@ -680,7 +684,6 @@ __gg__addf1_fixed_phase2( cbl_arith_format_t , if( rdigits_a > rdigits_b ) { scale_int256_by_digits(value_b, rdigits_a - rdigits_b); - rdigits_b = rdigits_a; } else if( rdigits_a < rdigits_b ) { @@ -713,16 +716,16 @@ __gg__fixed_phase2_assign_to_c( cbl_arith_format_t , size_t , size_t , size_t , - cbl_round_t *rounded, + const cbl_round_t *rounded, int on_error_flag, int *compute_error ) { // This is the assignment phase of an ADD Format 2 - cblc_field_t **C = __gg__treeplet_3f; - size_t *C_o = __gg__treeplet_3o; - size_t *C_s = __gg__treeplet_3s; + cblc_field_t **C = __gg__treeplet_3f; + const size_t *C_o = __gg__treeplet_3o; + const size_t *C_s = __gg__treeplet_3s; // We take phase1_result and put it into C @@ -771,7 +774,7 @@ __gg__add_float_phase1( cbl_arith_format_t , size_t nA, size_t , size_t , - cbl_round_t *, + const cbl_round_t *, int , int *compute_error ) @@ -780,9 +783,9 @@ __gg__add_float_phase1( cbl_arith_format_t , // The result goes into the temporary phase1_result_ffloat. - cblc_field_t **A = __gg__treeplet_1f; - size_t *A_o = __gg__treeplet_1o; - size_t *A_s = __gg__treeplet_1s; + cblc_field_t **A = __gg__treeplet_1f; + const size_t *A_o = __gg__treeplet_1o; + const size_t *A_s = __gg__treeplet_1s; // Let us prime the pump with the first value of A[] phase1_result_float = __gg__float128_from_qualified_field(A[0], A_o[0], A_s[0]); @@ -804,14 +807,14 @@ __gg__addf1_float_phase2( cbl_arith_format_t , size_t , size_t , size_t , - cbl_round_t *rounded, + const cbl_round_t *rounded, int on_error_flag, int *compute_error ) { - cblc_field_t **C = __gg__treeplet_3f; - size_t *C_o = __gg__treeplet_3o; - size_t *C_s = __gg__treeplet_3s; + cblc_field_t **C = __gg__treeplet_3f; + const size_t *C_o = __gg__treeplet_3o; + const size_t *C_s = __gg__treeplet_3s; bool on_size_error = !!(on_error_flag & ON_SIZE_ERROR); // This is the assignment phase of an ADD Format 2 @@ -831,14 +834,14 @@ __gg__float_phase2_assign_to_c( cbl_arith_format_t , size_t , size_t , size_t , - cbl_round_t *rounded, + const cbl_round_t *rounded, int on_error_flag, int *compute_error ) { - cblc_field_t **C = __gg__treeplet_3f; - size_t *C_o = __gg__treeplet_3o; - size_t *C_s = __gg__treeplet_3s; + cblc_field_t **C = __gg__treeplet_3f; + const size_t *C_o = __gg__treeplet_3o; + const size_t *C_s = __gg__treeplet_3s; bool on_size_error = !!(on_error_flag & ON_SIZE_ERROR); // This is the assignment phase of an ADD Format 2 @@ -856,7 +859,7 @@ __gg__addf3(cbl_arith_format_t , size_t nA, size_t , size_t , - cbl_round_t *rounded, + const cbl_round_t *rounded, int on_error_flag, int *compute_error ) @@ -864,13 +867,13 @@ __gg__addf3(cbl_arith_format_t , // This is an ADD Format 3. Each A[i] gets accumulated into each C[i]. When // both are fixed, we do fixed arithmetic. When either is a FldFloat, we // do floating-point arithmetic. - cblc_field_t **A = __gg__treeplet_1f; - size_t *A_o = __gg__treeplet_1o; - size_t *A_s = __gg__treeplet_1s; + cblc_field_t **A = __gg__treeplet_1f; + const size_t *A_o = __gg__treeplet_1o; + const size_t *A_s = __gg__treeplet_1s; - cblc_field_t **C = __gg__treeplet_3f; - size_t *C_o = __gg__treeplet_3o; - size_t *C_s = __gg__treeplet_3s; + cblc_field_t **C = __gg__treeplet_3f; + const size_t *C_o = __gg__treeplet_3o; + const size_t *C_s = __gg__treeplet_3s; bool on_size_error = !!(on_error_flag & ON_SIZE_ERROR); @@ -906,7 +909,6 @@ __gg__addf3(cbl_arith_format_t , if( rdigits_a > rdigits_b ) { scale_int256_by_digits(value_b, rdigits_a - rdigits_b); - rdigits_b = rdigits_a; } else if( rdigits_a < rdigits_b ) { @@ -940,14 +942,14 @@ __gg__subtractf1_fixed_phase2(cbl_arith_format_t , size_t , size_t , size_t , - cbl_round_t *rounded, + const cbl_round_t *rounded, int on_error_flag, int *compute_error ) { - cblc_field_t **C = __gg__treeplet_3f; - size_t *C_o = __gg__treeplet_3o; - size_t *C_s = __gg__treeplet_3s; + cblc_field_t **C = __gg__treeplet_3f; + const size_t *C_o = __gg__treeplet_3o; + const size_t *C_s = __gg__treeplet_3s; // This is the assignment phase of an ADD Format 1 @@ -997,7 +999,6 @@ __gg__subtractf1_fixed_phase2(cbl_arith_format_t , else if( rdigits_a < rdigits_b ) { scale_int256_by_digits(value_a, rdigits_b - rdigits_a); - rdigits_a = rdigits_b; } // The two numbers have the same number of rdigits. It's now safe to add @@ -1025,16 +1026,16 @@ __gg__subtractf2_fixed_phase1(cbl_arith_format_t , size_t nA, size_t , size_t , - cbl_round_t *rounded, + const cbl_round_t *rounded, int on_error_flag, int *compute_error ) { // This is the calculation phase of a fixed-point SUBTRACT Format 2 - cblc_field_t **B = __gg__treeplet_2f; - size_t *B_o = __gg__treeplet_2o; - size_t *B_s = __gg__treeplet_2s; + cblc_field_t **B = __gg__treeplet_2f; + const size_t *B_o = __gg__treeplet_2o; + const size_t *B_s = __gg__treeplet_2s; // Add up all the A values __gg__add_fixed_phase1( not_expected_e , @@ -1065,7 +1066,6 @@ __gg__subtractf2_fixed_phase1(cbl_arith_format_t , else if( rdigits_a < rdigits_b ) { scale_int256_by_digits(value_a, rdigits_b - rdigits_a); - rdigits_a = rdigits_b; } // The two numbers have the same number of rdigits. It's now safe to add @@ -1081,21 +1081,20 @@ __gg__subtractf2_fixed_phase1(cbl_arith_format_t , phase1_rdigits = rdigits_b; } - extern "C" void __gg__subtractf1_float_phase2(cbl_arith_format_t , size_t , size_t , size_t , - cbl_round_t *rounded, + const cbl_round_t *rounded, int on_error_flag, int *compute_error ) { - cblc_field_t **C = __gg__treeplet_3f; - size_t *C_o = __gg__treeplet_3o; - size_t *C_s = __gg__treeplet_3s; + cblc_field_t **C = __gg__treeplet_3f; + const size_t *C_o = __gg__treeplet_3o; + const size_t *C_s = __gg__treeplet_3s; bool on_size_error = !!(on_error_flag & ON_SIZE_ERROR); // This is the assignment phase of an ADD Format 2 @@ -1109,23 +1108,22 @@ __gg__subtractf1_float_phase2(cbl_arith_format_t , *rounded++); } - extern "C" void __gg__subtractf2_float_phase1(cbl_arith_format_t , size_t nA, size_t , size_t , - cbl_round_t *rounded, + const cbl_round_t *rounded, int on_error_flag, int *compute_error ) { // This is the calculation phase of a fixed-point SUBTRACT Format 2 - cblc_field_t **B = __gg__treeplet_2f; - size_t *B_o = __gg__treeplet_2o; - size_t *B_s = __gg__treeplet_2s; + cblc_field_t **B = __gg__treeplet_2f; + const size_t *B_o = __gg__treeplet_2o; + const size_t *B_s = __gg__treeplet_2s; // Add up all the A values __gg__add_float_phase1( not_expected_e , @@ -1151,7 +1149,7 @@ __gg__subtractf3( cbl_arith_format_t , size_t nA, size_t , size_t , - cbl_round_t *rounded, + const cbl_round_t *rounded, int on_error_flag, int *compute_error ) @@ -1159,12 +1157,12 @@ __gg__subtractf3( cbl_arith_format_t , // This is an ADD Format 3. Each A[i] gets accumulated into each C[i]. Each // SUBTRACTION is treated separately. - cblc_field_t **A = __gg__treeplet_1f; - size_t *A_o = __gg__treeplet_1o; - size_t *A_s = __gg__treeplet_1s; - cblc_field_t **C = __gg__treeplet_3f; - size_t *C_o = __gg__treeplet_3o; - size_t *C_s = __gg__treeplet_3s; + cblc_field_t **A = __gg__treeplet_1f; + const size_t *A_o = __gg__treeplet_1o; + const size_t *A_s = __gg__treeplet_1s; + cblc_field_t **C = __gg__treeplet_3f; + const size_t *C_o = __gg__treeplet_3o; + const size_t *C_s = __gg__treeplet_3s; bool on_size_error = !!(on_error_flag & ON_SIZE_ERROR); @@ -1205,7 +1203,6 @@ __gg__subtractf3( cbl_arith_format_t , else if( rdigits_a < rdigits_b ) { scale_int256_by_digits(value_a, rdigits_b - rdigits_a); - rdigits_a = rdigits_b; } // The two numbers have the same number of rdigits. It's now safe to add @@ -1240,16 +1237,16 @@ __gg__multiplyf1_phase1(cbl_arith_format_t , size_t , size_t , size_t , - cbl_round_t *, + const cbl_round_t *, int , int *) { // We are getting just the one value, which we are converting to the necessary // intermediate form - cblc_field_t **A = __gg__treeplet_1f; - size_t *A_o = __gg__treeplet_1o; - size_t *A_s = __gg__treeplet_1s; + cblc_field_t **A = __gg__treeplet_1f; + const size_t *A_o = __gg__treeplet_1o; + const size_t *A_s = __gg__treeplet_1s; if( A[0]->type == FldFloat ) { @@ -1274,7 +1271,8 @@ void multiply_int128_by_int128(int256 &ABCD, __int128 ab_value, __int128 cd_value) { - int is_negative = ( ((uint8_t *)(&ab_value))[15]^((uint8_t *)(&cd_value))[15]) & 0x80; + int is_negative = ( (PTRCAST(uint8_t, (&ab_value)))[15] + ^(PTRCAST(uint8_t, (&cd_value)))[15]) & 0x80; if( ab_value < 0 ) { ab_value = -ab_value; @@ -1290,10 +1288,10 @@ void multiply_int128_by_int128(int256 &ABCD, uint128 BD; // Let's extract the digits. - uint64_t a = *(uint64_t *)((unsigned char *)(&ab_value)+8); - uint64_t b = *(uint64_t *)((unsigned char *)(&ab_value)+0); - uint64_t c = *(uint64_t *)((unsigned char *)(&cd_value)+8); - uint64_t d = *(uint64_t *)((unsigned char *)(&cd_value)+0); + uint64_t a = *PTRCAST(uint64_t, (PTRCAST(unsigned char, (&ab_value))+8)); + uint64_t b = *PTRCAST(uint64_t, (PTRCAST(unsigned char, (&ab_value))+0)); + uint64_t c = *PTRCAST(uint64_t, (PTRCAST(unsigned char, (&cd_value))+8)); + uint64_t d = *PTRCAST(uint64_t, (PTRCAST(unsigned char, (&cd_value))+0)); // multiply (a0 + b) * (c0 + d) @@ -1334,14 +1332,14 @@ __gg__multiplyf1_phase2(cbl_arith_format_t , size_t , size_t , size_t , - cbl_round_t *rounded, + const cbl_round_t *rounded, int on_error_flag, int *compute_error ) { - cblc_field_t **C = __gg__treeplet_3f; - size_t *C_o = __gg__treeplet_3o; - size_t *C_s = __gg__treeplet_3s; + cblc_field_t **C = __gg__treeplet_3f; + const size_t *C_o = __gg__treeplet_3o; + const size_t *C_s = __gg__treeplet_3s; bool on_size_error = !!(on_error_flag & ON_SIZE_ERROR); int error_this_time=0; @@ -1415,14 +1413,13 @@ __gg__multiplyf1_phase2(cbl_arith_format_t , if( error_this_time && on_size_error) { *compute_error |= error_this_time; - rounded++; } else { *compute_error |= conditional_stash(C[0], C_o[0], C_s[0], on_size_error, a_value, - *rounded++); + *rounded); } done: return; @@ -1434,20 +1431,20 @@ __gg__multiplyf2( cbl_arith_format_t , size_t , size_t , size_t nC, - cbl_round_t *rounded, + const cbl_round_t *rounded, int on_error_flag, int *compute_error ) { - cblc_field_t **A = __gg__treeplet_1f; - size_t *A_o = __gg__treeplet_1o; - size_t *A_s = __gg__treeplet_1s; - cblc_field_t **B = __gg__treeplet_2f; - size_t *B_o = __gg__treeplet_2o; - size_t *B_s = __gg__treeplet_2s; - cblc_field_t **C = __gg__treeplet_3f; - size_t *C_o = __gg__treeplet_3o; - size_t *C_s = __gg__treeplet_3s; + cblc_field_t **A = __gg__treeplet_1f; + const size_t *A_o = __gg__treeplet_1o; + const size_t *A_s = __gg__treeplet_1s; + cblc_field_t **B = __gg__treeplet_2f; + const size_t *B_o = __gg__treeplet_2o; + const size_t *B_s = __gg__treeplet_2s; + cblc_field_t **C = __gg__treeplet_3f; + const size_t *C_o = __gg__treeplet_3o; + const size_t *C_s = __gg__treeplet_3s; bool on_size_error = !!(on_error_flag & ON_SIZE_ERROR); @@ -1517,7 +1514,7 @@ shift_in_place128(uint8_t *buf, int size, int bits) uint128 temp; uint128 overflow = 0; - uint128 *as128 = (uint128 *)buf; + uint128 *as128 = PTRCAST(uint128, buf); for( size_t i=0; i<places; i++ ) { @@ -1598,7 +1595,7 @@ divide_int128_by_int128(int256 "ient, } // We are going to be referencing the 64-bit pices of the 128-bit divisor: - uint64_t *divisor64 = (uint64_t *)&divisor; + uint64_t *divisor64 = PTRCAST(uint64_t, &divisor); quotient.i128[1] = 0; quotient.i128[0] = dividend; @@ -1667,12 +1664,11 @@ divide_int128_by_int128(int256 "ient, int bits_to_shift = 0; int i=15; - while( ((uint8_t *)(&divisor))[i] == 0 ) + while( (PTRCAST(uint8_t, &divisor))[i] == 0 ) { i -= 1; bits_to_shift += 8; - } - uint8_t tail = ((uint8_t *)(&divisor))[i]; + } uint8_t tail = ( PTRCAST(uint8_t, &divisor) )[i]; while( !(tail & 0x80) ) { bits_to_shift += 1; @@ -1681,9 +1677,8 @@ divide_int128_by_int128(int256 "ient, // Shift both the numerator and the divisor that number of bits - shift_in_place128((uint8_t *)&numerator, sizeof(numerator), bits_to_shift); - shift_in_place128((uint8_t *)&divisor, sizeof(divisor), bits_to_shift); - + shift_in_place128( PTRCAST(uint8_t, &numerator), sizeof(numerator), bits_to_shift); + shift_in_place128( PTRCAST(uint8_t, &divisor), sizeof(divisor), bits_to_shift); // We are now ready to do the guess-multiply-subtract loop. We know that // the result will have two places, so we know we are going to go through @@ -1700,7 +1695,7 @@ divide_int128_by_int128(int256 "ient, // We develop our guess for a quotient by dividing the top two places of // the numerator area by C uint128 temp; - uint64_t *temp64 = (uint64_t *)&temp; + uint64_t *temp64 = PTRCAST(uint64_t, &temp); temp64[1] = numerator.i64[q_place+2]; temp64[0] = numerator.i64[q_place+1]; @@ -1714,10 +1709,10 @@ divide_int128_by_int128(int256 "ient, subber[2] = 0; // Start with the bottom 128 bits of the "subber" - *(uint128 *)subber = (uint128) divisor64[0] * quotient.i64[q_place]; + *PTRCAST(uint128, subber) = (uint128) divisor64[0] * quotient.i64[q_place]; // Get the next 128 bits of subber - temp = (uint128) divisor64[1] * quotient.i64[q_place]; + temp = (uint128) divisor64[1] * quotient.i64[q_place]; // Add the top of the first product to the bottom of the second: subber[1] += temp64[0]; @@ -1738,20 +1733,20 @@ divide_int128_by_int128(int256 "ient, // the numerator: uint64_t borrow = 0; - for(size_t i=0; i<3; i++) + for(size_t j=0; j<3; j++) { - if( numerator.i64[q_place + i] == 0 && borrow ) + if( numerator.i64[q_place + j] == 0 && borrow ) { // We are subtracting from zero and we have a borrow. Leave the // borrow on and just do the subtraction: - numerator.i64[q_place + i] -= subber[i]; + numerator.i64[q_place + j] -= subber[j]; } else { - uint64_t stash = numerator.i64[q_place + i]; - numerator.i64[q_place + i] -= borrow; - numerator.i64[q_place + i] -= subber[i]; - if( numerator.i64[q_place + i] > stash ) + uint64_t stash = numerator.i64[q_place + j]; + numerator.i64[q_place + j] -= borrow; + numerator.i64[q_place + j] -= subber[j]; + if( numerator.i64[q_place + j] > stash ) { // After subtracting, the value got bigger, which means we have // to borrow from the next value to the left @@ -1775,21 +1770,21 @@ divide_int128_by_int128(int256 "ient, { // We need to add subber back into the numerator area uint64_t carry = 0; - for(size_t i=0; i<3; i++) + for(size_t ii=0; ii<3; ii++) { - if( numerator.i64[q_place + i] == 0xFFFFFFFFFFFFFFFFUL && carry ) + if( numerator.i64[q_place + ii] == 0xFFFFFFFFFFFFFFFFUL && carry ) { // We are at the top and have a carry. Just leave the carry on // and do the addition: - numerator.i64[q_place + i] += subber[i]; + numerator.i64[q_place + ii] += subber[ii]; } else { // We are not at the top. - uint64_t stash = numerator.i64[q_place + i]; - numerator.i64[q_place + i] += carry; - numerator.i64[q_place + i] += subber[i]; - if( numerator.i64[q_place + i] < stash ) + uint64_t stash = numerator.i64[q_place + ii]; + numerator.i64[q_place + ii] += carry; + numerator.i64[q_place + ii] += subber[ii]; + if( numerator.i64[q_place + ii] < stash ) { // The addition caused the result to get smaller, meaning that // we wrapped around: @@ -1817,14 +1812,14 @@ __gg__dividef1_phase2(cbl_arith_format_t , size_t , size_t , size_t , - cbl_round_t *rounded, + const cbl_round_t *rounded, int on_error_flag, int *compute_error ) { - cblc_field_t **C = __gg__treeplet_3f; - size_t *C_o = __gg__treeplet_3o; - size_t *C_s = __gg__treeplet_3s; + cblc_field_t **C = __gg__treeplet_3f; + const size_t *C_o = __gg__treeplet_3o; + const size_t *C_s = __gg__treeplet_3s; bool on_size_error = !!(on_error_flag & ON_SIZE_ERROR); int error_this_time=0; @@ -1904,14 +1899,13 @@ __gg__dividef1_phase2(cbl_arith_format_t , if( error_this_time && on_size_error) { - rounded++; } else { *compute_error |= conditional_stash(C[0], C_o[0], C_s[0], on_size_error, b_value, - *rounded++); + *rounded); } done: return; @@ -1923,20 +1917,20 @@ __gg__dividef23(cbl_arith_format_t , size_t , size_t , size_t nC, - cbl_round_t *rounded, + const cbl_round_t *rounded, int on_error_flag, int *compute_error ) { - cblc_field_t **A = __gg__treeplet_1f; - size_t *A_o = __gg__treeplet_1o; - size_t *A_s = __gg__treeplet_1s; - cblc_field_t **B = __gg__treeplet_2f; - size_t *B_o = __gg__treeplet_2o; - size_t *B_s = __gg__treeplet_2s; - cblc_field_t **C = __gg__treeplet_3f; - size_t *C_o = __gg__treeplet_3o; - size_t *C_s = __gg__treeplet_3s; + cblc_field_t **A = __gg__treeplet_1f; + const size_t *A_o = __gg__treeplet_1o; + const size_t *A_s = __gg__treeplet_1s; + cblc_field_t **B = __gg__treeplet_2f; + const size_t *B_o = __gg__treeplet_2o; + const size_t *B_s = __gg__treeplet_2s; + cblc_field_t **C = __gg__treeplet_3f; + const size_t *C_o = __gg__treeplet_3o; + const size_t *C_s = __gg__treeplet_3s; bool on_size_error = !!(on_error_flag & ON_SIZE_ERROR); int error_this_time=0; @@ -2009,15 +2003,15 @@ __gg__dividef45(cbl_arith_format_t , int *compute_error ) { - cblc_field_t **A = __gg__treeplet_1f; // Numerator - size_t *A_o = __gg__treeplet_1o; - size_t *A_s = __gg__treeplet_1s; - cblc_field_t **B = __gg__treeplet_2f; // Denominator - size_t *B_o = __gg__treeplet_2o; - size_t *B_s = __gg__treeplet_2s; - cblc_field_t **C = __gg__treeplet_3f; // Has remainder, then quotient - size_t *C_o = __gg__treeplet_3o; - size_t *C_s = __gg__treeplet_3s; + cblc_field_t **A = __gg__treeplet_1f; // Numerator + const size_t *A_o = __gg__treeplet_1o; + const size_t *A_s = __gg__treeplet_1s; + cblc_field_t **B = __gg__treeplet_2f; // Denominator + const size_t *B_o = __gg__treeplet_2o; + const size_t *B_s = __gg__treeplet_2s; + cblc_field_t **C = __gg__treeplet_3f; // Has remainder, then quotient + const size_t *C_o = __gg__treeplet_3o; + const size_t *C_s = __gg__treeplet_3s; bool on_size_error = !!(on_error_flag & ON_SIZE_ERROR); int error_this_time=0; diff --git a/libgcobol/intrinsic.cc b/libgcobol/intrinsic.cc index 1af4a53..1053bf6 100644 --- a/libgcobol/intrinsic.cc +++ b/libgcobol/intrinsic.cc @@ -248,9 +248,12 @@ struct input_state nsubscript = N; if(N) { - subscript_alls = (bool *) malloc(nsubscript); - subscripts = (size_t *)malloc(nsubscript); - subscript_limits = (size_t *)malloc(nsubscript); + subscript_alls = static_cast<bool *>(malloc(nsubscript)); + subscripts = static_cast<size_t *>(malloc(nsubscript)); + subscript_limits = static_cast<size_t *>(malloc(nsubscript)); + massert(subscript_alls); + massert(subscripts); + massert(subscript_limits); } done = false; } @@ -378,7 +381,7 @@ year_to_yyyy(int arg1, int arg2, int arg3) static double -get_value_as_double_from_qualified_field( cblc_field_t *input, +get_value_as_double_from_qualified_field( const cblc_field_t *input, size_t input_o, size_t input_s) { @@ -411,9 +414,9 @@ get_value_as_double_from_qualified_field( cblc_field_t *input, static GCOB_FP128 kahan_summation(size_t ncount, cblc_field_t **source, - size_t *source_o, - size_t *source_s, - int *flags, + const size_t *source_o, + const size_t *source_s, + const int *flags, size_t *k_count) { // We use compensated addition. Look up Kahan summation. @@ -458,9 +461,9 @@ static GCOB_FP128 variance( size_t ncount, cblc_field_t **source, - size_t *source_o, - size_t *source_s, - int *flags) + const size_t *source_o, + const size_t *source_s, + const int *flags) { // In order to avoid catastrophic cancellation, we are going to use an // algorithm that is a bit wasteful of time, but is described as particularly @@ -547,14 +550,14 @@ get_all_time( char *stime, // days of January show up in the final week of the prior year. sprintf(stime, - "%4.4u%2.2u%2.2uT" // YYYYMMSS - "%2.2u%2.2u%2.2u" // hhmmss - ".%9.9u" // .sssssssss - "%c%2.2u%2.2u" // +hhmm - "W%2.2u" // Www - "%1u" // DOW [1-7], 1 for Monday - "%3.3u" // DDD day of year, 001 - 365,366 - "%4.4u", // ZZZZ Year for YYYY-Www-D + "%4.4d%2.2d%2.2dT" // YYYYMMSS + "%2.2d%2.2d%2.2d" // hhmmss + ".%9.9d" // .sssssssss + "%c%2.2d%2.2d" // +hhmm + "W%2.2d" // Www + "%1d" // DOW [1-7], 1 for Monday + "%3.3d" // DDD day of year, 001 - 365,366 + "%4.4d", // ZZZZ Year for YYYY-Www-D ctm.YYYY, ctm.MM, ctm.DD, @@ -687,7 +690,7 @@ populate_ctm_from_JD(struct cobol_tm &ctm, double JD ) static void populate_ctm_from_date( struct cobol_tm &ctm, - cblc_field_t *pdate, + const cblc_field_t *pdate, size_t pdate_offset, size_t pdate_size) { @@ -721,10 +724,10 @@ populate_ctm_from_double_time(struct cobol_tm &ctm, double time) static void populate_ctm_from_time( struct cobol_tm &ctm, - cblc_field_t *ptime, + const cblc_field_t *ptime, size_t ptime_o, size_t ptime_s, - cblc_field_t *poffset, + const cblc_field_t *poffset, size_t poffset_o, size_t poffset_s) { @@ -791,8 +794,10 @@ convert_to_zulu(cobol_tm &ctm) static void -ftime_replace(char *dest, char const * const dest_end, - char const *source, char const * const source_end, +ftime_replace(char *dest, + char const * const dest_end, + char const * source, + char const * const source_end, char const * const ftime) { // This routine is highly dependent on the source format being correct. @@ -956,7 +961,7 @@ ftime_replace(char *dest, char const * const dest_end, extern "C" void __gg__abs(cblc_field_t *dest, - cblc_field_t *source, + const cblc_field_t *source, size_t source_offset, size_t source_size) { @@ -978,7 +983,7 @@ __gg__abs(cblc_field_t *dest, extern "C" void __gg__acos( cblc_field_t *dest, - cblc_field_t *source, + const cblc_field_t *source, size_t source_offset, size_t source_size) { @@ -1005,10 +1010,10 @@ __gg__acos( cblc_field_t *dest, extern "C" void __gg__annuity(cblc_field_t *dest, - cblc_field_t *arg1, + const cblc_field_t *arg1, size_t arg1_offset, size_t arg1_size, - cblc_field_t *arg2, + const cblc_field_t *arg2, size_t arg2_offset, size_t arg2_size) { @@ -1050,7 +1055,7 @@ __gg__annuity(cblc_field_t *dest, extern "C" void __gg__asin( cblc_field_t *dest, - cblc_field_t *source, + const cblc_field_t *source, size_t source_offset, size_t source_size) { @@ -1080,7 +1085,7 @@ __gg__asin( cblc_field_t *dest, extern "C" void __gg__atan( cblc_field_t *dest, - cblc_field_t *source, + const cblc_field_t *source, size_t source_offset, size_t source_size) { @@ -1102,7 +1107,7 @@ __gg__atan( cblc_field_t *dest, extern "C" void __gg__byte_length(cblc_field_t *dest, - cblc_field_t */*source*/, + const cblc_field_t */*source*/, size_t /*source_offset*/, size_t source_size) { @@ -1118,7 +1123,7 @@ __gg__byte_length(cblc_field_t *dest, extern "C" void __gg__char( cblc_field_t *dest, - cblc_field_t *source, + const cblc_field_t *source, size_t source_offset, size_t source_size) { @@ -1143,10 +1148,10 @@ __gg__char( cblc_field_t *dest, extern "C" void __gg__combined_datetime(cblc_field_t *dest, - cblc_field_t *arg1, + const cblc_field_t *arg1, size_t arg1_offset, size_t arg1_size, - cblc_field_t *arg2, + const cblc_field_t *arg2, size_t arg2_offset, size_t arg2_size) { @@ -1192,7 +1197,7 @@ __gg__concat( cblc_field_t *dest, extern "C" void __gg__cos(cblc_field_t *dest, - cblc_field_t *source, + const cblc_field_t *source, size_t source_offset, size_t source_size) { @@ -1251,7 +1256,7 @@ __gg__seconds_past_midnight(cblc_field_t *dest) extern "C" void __gg__date_of_integer(cblc_field_t *dest, - cblc_field_t *source, + const cblc_field_t *source, size_t source_offset, size_t source_size) { @@ -1277,13 +1282,13 @@ __gg__date_of_integer(cblc_field_t *dest, extern "C" void __gg__date_to_yyyymmdd( cblc_field_t *dest, - cblc_field_t *par1, + const cblc_field_t *par1, size_t par1_o, size_t par1_s, - cblc_field_t *par2, + const cblc_field_t *par2, size_t par2_o, size_t par2_s, - cblc_field_t *par3, + const cblc_field_t *par3, size_t par3_o, size_t par3_s) { @@ -1308,7 +1313,7 @@ __gg__date_to_yyyymmdd( cblc_field_t *dest, extern "C" void __gg__day_of_integer( cblc_field_t *dest, - cblc_field_t *source, + const cblc_field_t *source, size_t source_offset, size_t source_size) { @@ -1337,13 +1342,13 @@ __gg__day_of_integer( cblc_field_t *dest, extern "C" void __gg__day_to_yyyyddd( cblc_field_t *dest, - cblc_field_t *par1, + const cblc_field_t *par1, size_t par1_o, size_t par1_s, - cblc_field_t *par2, + const cblc_field_t *par2, size_t par2_o, size_t par2_s, - cblc_field_t *par3, + const cblc_field_t *par3, size_t par3_o, size_t par3_s) { @@ -1382,7 +1387,7 @@ __gg__e(cblc_field_t *dest) extern "C" void __gg__exp(cblc_field_t *dest, - cblc_field_t *source, + const cblc_field_t *source, size_t source_offset, size_t source_size) { @@ -1401,7 +1406,7 @@ __gg__exp(cblc_field_t *dest, extern "C" void __gg__exp10(cblc_field_t *dest, - cblc_field_t *source, + const cblc_field_t *source, size_t source_offset, size_t source_size) { @@ -1420,7 +1425,7 @@ __gg__exp10(cblc_field_t *dest, extern "C" void __gg__factorial(cblc_field_t *dest, - cblc_field_t *source, + const cblc_field_t *source, size_t source_offset, size_t source_size) { @@ -1451,24 +1456,24 @@ __gg__factorial(cblc_field_t *dest, extern "C" void __gg__formatted_current_date( cblc_field_t *dest, // Destination string - cblc_field_t *input, // datetime format + const cblc_field_t *input, // datetime format size_t input_offset, size_t input_size) { // FUNCTION CURRENT-DATE // Establish the destination, and set it to spaces - char *d = (char *)dest->data; - char *dend = d + dest->capacity; + char *d = PTRCAST(char, dest->data); + const char *dend = d + dest->capacity; memset(d, internal_space, dest->capacity); // Establish the formatting string: - char *format = (char *)(input->data+input_offset); - char *format_end = format + input_size; + const char *format = PTRCAST(char, (input->data+input_offset)); + const char *format_end = format + input_size; bool is_zulu = false; - char *p = format; + const char *p = format; while( p < format_end ) { int ch = *p++; @@ -1512,23 +1517,23 @@ __gg__formatted_current_date( cblc_field_t *dest, // Destination string extern "C" void __gg__formatted_date(cblc_field_t *dest, // Destination string - cblc_field_t *arg1, // datetime format + const cblc_field_t *arg1, // datetime format size_t arg1_offset, size_t arg1_size, - cblc_field_t *arg2, // integer date + const cblc_field_t *arg2, // integer date size_t arg2_offset, size_t arg2_size) { // FUNCTION FORMATTED-DATE // Establish the destination, and set it to spaces - char *d = (char *)dest->data; - char *dend = d + dest->capacity; + char *d = PTRCAST(char, dest->data); + const char *dend = d + dest->capacity; memset(d, internal_space, dest->capacity); // Establish the formatting string: - char *format = (char *)(arg1->data+arg1_offset); - char *format_end = format + arg1_size; + char *format = PTRCAST(char, (arg1->data+arg1_offset)); + const char *format_end = format + arg1_size; struct cobol_tm ctm = {}; @@ -1550,16 +1555,16 @@ __gg__formatted_date(cblc_field_t *dest, // Destination string extern "C" void __gg__formatted_datetime( cblc_field_t *dest, // Destination string - cblc_field_t *par1, // datetime format + const cblc_field_t *par1, // datetime format size_t par1_o, size_t par1_s, - cblc_field_t *par2, // integer date + const cblc_field_t *par2, // integer date size_t par2_o, size_t par2_s, - cblc_field_t *par3, // numeric time + const cblc_field_t *par3, // numeric time size_t par3_o, size_t par3_s, - cblc_field_t *par4, // optional offset in seconds + const cblc_field_t *par4, // optional offset in seconds size_t par4_o, size_t par4_s ) @@ -1567,12 +1572,12 @@ __gg__formatted_datetime( cblc_field_t *dest, // Destination string // FUNCTION FORMATTED-DATETIME // Establish the destination, and set it to spaces - char *d = (char *)dest->data; - char *dend = d + dest->capacity; + char *d = PTRCAST(char, (dest->data)); + const char *dend = d + dest->capacity; memset(d, internal_space, dest->capacity); // Establish the formatting string: - char *format = (char *)(par1->data+par1_o); + char *format = PTRCAST(char, (par1->data+par1_o)); char *format_end = format + par1_s; trim_trailing_spaces(format, format_end); bool is_zulu = is_zulu_format(format, format_end); @@ -1605,13 +1610,13 @@ __gg__formatted_datetime( cblc_field_t *dest, // Destination string extern "C" void __gg__formatted_time( cblc_field_t *dest,// Destination string - cblc_field_t *par1, // datetime format + const cblc_field_t *par1, // datetime format size_t par1_o, size_t par1_s, - cblc_field_t *par2,// numeric time + const cblc_field_t *par2,// numeric time size_t par2_o, size_t par2_s, - cblc_field_t *par4, // optional offset in seconds + const cblc_field_t *par4, // optional offset in seconds size_t par4_o, size_t par4_s) @@ -1619,12 +1624,12 @@ __gg__formatted_time( cblc_field_t *dest,// Destination string // FUNCTION FORMATTED-TIME // Establish the destination, and set it to spaces - char *d = (char *)dest->data; - char *dend = d + dest->capacity; + char *d = PTRCAST(char, dest->data); + const char *dend = d + dest->capacity; memset(d, internal_space, dest->capacity); // Establish the formatting string: - char *format = (char *)(par1->data+par1_o); + char *format = PTRCAST(char, (par1->data+par1_o)); char *format_end = format + par1_s; trim_trailing_spaces(format, format_end); bool is_zulu = is_zulu_format(format, format_end); @@ -1659,7 +1664,7 @@ __gg__formatted_time( cblc_field_t *dest,// Destination string extern "C" void __gg__integer(cblc_field_t *dest, - cblc_field_t *source, + const cblc_field_t *source, size_t source_offset, size_t source_size) { @@ -1677,7 +1682,7 @@ __gg__integer(cblc_field_t *dest, extern "C" void __gg__integer_of_date(cblc_field_t *dest, - cblc_field_t *source, + const cblc_field_t *source, size_t source_offset, size_t source_size) { @@ -1732,7 +1737,7 @@ __gg__integer_of_date(cblc_field_t *dest, extern "C" void __gg__integer_of_day( cblc_field_t *dest, - cblc_field_t *source, + const cblc_field_t *source, size_t source_offset, size_t source_size) { @@ -1759,7 +1764,7 @@ __gg__integer_of_day( cblc_field_t *dest, extern "C" void __gg__integer_part( cblc_field_t *dest, - cblc_field_t *source, + const cblc_field_t *source, size_t source_offset, size_t source_size) { @@ -1782,7 +1787,7 @@ __gg__integer_part( cblc_field_t *dest, extern "C" void __gg__fraction_part(cblc_field_t *dest, - cblc_field_t *source, + const cblc_field_t *source, size_t source_offset, size_t source_size) { @@ -1811,10 +1816,10 @@ __gg__fraction_part(cblc_field_t *dest, extern "C" void -__gg__log( cblc_field_t *dest, - cblc_field_t *source, - size_t source_offset, - size_t source_size) +__gg__log(cblc_field_t *dest, + const cblc_field_t *source, + size_t source_offset, + size_t source_size) { // FUNCTION LOG GCOB_FP128 value = __gg__float128_from_qualified_field(source, @@ -1836,10 +1841,10 @@ __gg__log( cblc_field_t *dest, extern "C" void -__gg__log10( cblc_field_t *dest, - cblc_field_t *source, - size_t source_offset, - size_t source_size) +__gg__log10(cblc_field_t *dest, + const cblc_field_t *source, + size_t source_offset, + size_t source_size) { // FUNCTION LOG10 GCOB_FP128 value = __gg__float128_from_qualified_field(source, @@ -1870,8 +1875,8 @@ __gg__max(cblc_field_t *dest, || __gg__treeplet_1f[0]->type == FldLiteralA) ) { cblc_field_t *best_field ; - unsigned char *best_location ; - size_t best_length ; + unsigned char *best_location = nullptr ; + size_t best_length = 0 ; int best_attr ; int best_flags ; @@ -1931,8 +1936,10 @@ __gg__max(cblc_field_t *dest, } } + __gg__adjust_dest_size(dest, best_length); dest->type = FldAlphanumeric; + assert(best_location); memcpy(dest->data, best_location, best_length); } else @@ -1977,7 +1984,7 @@ __gg__max(cblc_field_t *dest, extern "C" void __gg__lower_case( cblc_field_t *dest, - cblc_field_t *input, + const cblc_field_t *input, size_t input_offset, size_t input_size) { @@ -1985,10 +1992,10 @@ __gg__lower_case( cblc_field_t *dest, size_t source_length = input_size; memset(dest->data, internal_space, dest_length); memcpy(dest->data, input->data+input_offset, std::min(dest_length, source_length)); - internal_to_ascii((char *)dest->data, dest_length); + internal_to_ascii( PTRCAST(char, dest->data), dest_length); std::transform(dest->data, dest->data + dest_length, dest->data, [](unsigned char c) { return std::tolower(c); }); - ascii_to_internal_str((char *)dest->data, dest_length); + ascii_to_internal_str( PTRCAST(char, dest->data), dest_length); } extern "C" @@ -2027,7 +2034,8 @@ __gg__median( cblc_field_t *dest, size_t list_size = 1; - GCOB_FP128 *the_list = (GCOB_FP128 *)malloc(list_size *sizeof(GCOB_FP128)); + GCOB_FP128 *the_list = static_cast<GCOB_FP128 *>(malloc(list_size *sizeof(GCOB_FP128))); + massert(the_list); size_t k_count = 0; assert(ncount); for(size_t i=0; i<ncount; i++) @@ -2040,9 +2048,11 @@ __gg__median( cblc_field_t *dest, if(k_count >= list_size) { list_size *= 2; - the_list = (GCOB_FP128 *)realloc(the_list, list_size *sizeof(GCOB_FP128)); + the_list = PTRCAST(GCOB_FP128, realloc(the_list, list_size *sizeof(GCOB_FP128))); + massert(the_list); } + assert(the_list); the_list[k_count] = __gg__float128_from_qualified_field(__gg__treeplet_1f[i], __gg__treeplet_1o[i], __gg__treeplet_1s[i]); @@ -2125,11 +2135,11 @@ __gg__min(cblc_field_t *dest, if( ( __gg__treeplet_1f[0]->type == FldAlphanumeric || __gg__treeplet_1f[0]->type == FldLiteralA) ) { - cblc_field_t *best_field ; - unsigned char *best_location ; - size_t best_length ; - int best_attr ; - int best_flags ; + cblc_field_t *best_field ; + unsigned char *best_location = nullptr ; + size_t best_length = 0 ; + int best_attr ; + int best_flags ; bool first_time = true; assert(ncount); @@ -2189,6 +2199,7 @@ __gg__min(cblc_field_t *dest, __gg__adjust_dest_size(dest, best_length); dest->type = FldAlphanumeric; + assert(best_location); memcpy(dest->data, best_location, best_length); } else @@ -2277,15 +2288,15 @@ __gg__mod(cblc_field_t *dest, static int numval( cblc_field_t *dest, - cblc_field_t *input, + const cblc_field_t *input, size_t input_offset, size_t input_size) { // Returns the one-based character position of a bad character // returns zero if it is okay - char *p = (char *)(input->data + input_offset); - char *pend = p + input_size; + const char *p = PTRCAST(char, (input->data + input_offset)); + const char *pend = p + input_size; int errpos = 0; __int128 retval = 0; @@ -2568,17 +2579,17 @@ numval( cblc_field_t *dest, static int numval_c( cblc_field_t *dest, - cblc_field_t *src, + const cblc_field_t *src, size_t src_offset, size_t src_size, - cblc_field_t *crcy, + const cblc_field_t *crcy, size_t crcy_offset, size_t crcy_size ) { size_t errcode = 0; - char *pstart = (char *)(src->data+src_offset); + char *pstart = PTRCAST(char, (src->data+src_offset)); char *pend = pstart + src_size; char *p = pstart; @@ -2593,7 +2604,7 @@ numval_c( cblc_field_t *dest, char *currency_end; if( crcy ) { - currency_start = (char *)(crcy->data+crcy_offset); + currency_start = PTRCAST(char, (crcy->data+crcy_offset)); currency_end = currency_start + crcy_size; } else @@ -2807,7 +2818,6 @@ numval_c( cblc_field_t *dest, if( sign ) { // A second sign isn't allowed - state = final_space; errcode = p - pstart; p = pend; } @@ -2875,7 +2885,7 @@ numval_c( cblc_field_t *dest, extern "C" void __gg__numval( cblc_field_t *dest, - cblc_field_t *source, + const cblc_field_t *source, size_t source_offset, size_t source_size) { @@ -2889,7 +2899,7 @@ __gg__numval( cblc_field_t *dest, extern "C" void __gg__test_numval(cblc_field_t *dest, - cblc_field_t *source, + const cblc_field_t *source, size_t source_offset, size_t source_size) { @@ -2904,10 +2914,10 @@ __gg__test_numval(cblc_field_t *dest, extern "C" void __gg__numval_c( cblc_field_t *dest, - cblc_field_t *src, + const cblc_field_t *src, size_t src_offset, size_t src_size, - cblc_field_t *crcy, + const cblc_field_t *crcy, size_t crcy_offset, size_t crcy_size ) @@ -2924,10 +2934,10 @@ __gg__numval_c( cblc_field_t *dest, extern "C" void __gg__test_numval_c(cblc_field_t *dest, - cblc_field_t *src, + const cblc_field_t *src, size_t src_offset, size_t src_size, - cblc_field_t *crcy, + const cblc_field_t *crcy, size_t crcy_offset, size_t crcy_size ) @@ -2949,12 +2959,12 @@ __gg__test_numval_c(cblc_field_t *dest, extern "C" void __gg__ord(cblc_field_t *dest, - cblc_field_t *input, + const cblc_field_t *input, size_t input_offset, size_t /*input_size*/) { // We get our input in internal_character form. - char *arg = (char *)(input->data + input_offset); + const char *arg = PTRCAST(char, (input->data + input_offset)); // The ORD function takes a single-character string and returns the // ordinal position of that character. @@ -3257,10 +3267,10 @@ __gg__range(cblc_field_t *dest, extern "C" void __gg__rem(cblc_field_t *dest, - cblc_field_t *par1, + const cblc_field_t *par1, size_t par1_offset, size_t par1_size, - cblc_field_t *par2, + const cblc_field_t *par2, size_t par2_offset, size_t par2_size) { @@ -3300,10 +3310,10 @@ __gg__rem(cblc_field_t *dest, extern "C" void __gg__trim( cblc_field_t *dest, - cblc_field_t *arg1, + const cblc_field_t *arg1, size_t arg1_offset, size_t arg1_size, - cblc_field_t *arg2, + const cblc_field_t *arg2, size_t arg2_offset, size_t arg2_size) { @@ -3329,7 +3339,7 @@ __gg__trim( cblc_field_t *dest, // No matter what, we want to find the leftmost non-space and the // rightmost non-space: - char *left = (char *)(arg1->data+arg1_offset); + char *left = PTRCAST(char, (arg1->data+arg1_offset)); char *right = left + arg1_size-1; // Find left and right: the first and last non-spaces @@ -3352,13 +3362,13 @@ __gg__trim( cblc_field_t *dest, { // We want to leave any trailing spaces, so we return 'right' to its // original value: - right = (char *)(arg1->data+arg1_offset) + arg1_size-1; + right = PTRCAST(char, (arg1->data+arg1_offset)) + arg1_size-1; } else if( type == TRAILING ) { // We want to leave any leading spaces, so we return 'left' to its // original value: - left = (char *)(arg1->data+arg1_offset); + left = PTRCAST(char, (arg1->data+arg1_offset)); } if( left > right ) @@ -3378,9 +3388,9 @@ __gg__trim( cblc_field_t *dest, // compiler believes the capacity to be at compile-time. But we obviously // think it'll be okay. - char *dest_left = (char *)dest->data; + char *dest_left = PTRCAST(char, dest->data); char *dest_right = dest_left + dest->capacity - 1; - char *dest_end = dest_left + dest->capacity; + const char *dest_end = dest_left + dest->capacity; while( dest_left <= dest_right && left <= right ) { @@ -3403,7 +3413,7 @@ static unsigned seed = 0; extern "C" void __gg__random( cblc_field_t *dest, - cblc_field_t *input, + const cblc_field_t *input, size_t input_offset, size_t input_size) { @@ -3480,7 +3490,7 @@ __gg__random_next(cblc_field_t *dest) extern "C" void __gg__reverse(cblc_field_t *dest, - cblc_field_t *input, + const cblc_field_t *input, size_t input_offset, size_t input_size) { @@ -3501,7 +3511,7 @@ __gg__reverse(cblc_field_t *dest, extern "C" void __gg__sign( cblc_field_t *dest, - cblc_field_t *source, + const cblc_field_t *source, size_t source_offset, size_t source_size) { @@ -3534,7 +3544,7 @@ __gg__sign( cblc_field_t *dest, extern "C" void __gg__sin(cblc_field_t *dest, - cblc_field_t *source, + const cblc_field_t *source, size_t source_offset, size_t source_size) { @@ -3555,7 +3565,7 @@ __gg__sin(cblc_field_t *dest, extern "C" void __gg__sqrt( cblc_field_t *dest, - cblc_field_t *source, + const cblc_field_t *source, size_t source_offset, size_t source_size) { @@ -3621,7 +3631,7 @@ __gg__sum(cblc_field_t *dest, extern "C" void __gg__tan(cblc_field_t *dest, - cblc_field_t *source, + const cblc_field_t *source, size_t source_offset, size_t source_size) { @@ -3640,7 +3650,7 @@ __gg__tan(cblc_field_t *dest, extern "C" void __gg__test_date_yyyymmdd( cblc_field_t *dest, - cblc_field_t *source, + const cblc_field_t *source, size_t source_offset, size_t source_size) { @@ -3650,14 +3660,8 @@ __gg__test_date_yyyymmdd( cblc_field_t *dest, source_offset, source_size); int retval; - int dd = yyyymmdd % 100; int mmdd = yyyymmdd % 10000; int mm = mmdd / 100; - int yyyy = yyyymmdd / 10000; - int jy; - int jm; - int jd; - double JD; if( yyyymmdd < 16010000 || yyyymmdd > 99999999 ) { retval = 1; @@ -3668,6 +3672,13 @@ __gg__test_date_yyyymmdd( cblc_field_t *dest, } else { + int dd = yyyymmdd % 100; + int yyyy = yyyymmdd / 10000; + int jy; + int jm; + int jd; + double JD; + // If there is something wrong with the number of days per month for a // given year, the Julian Date conversion won't reverse properly. // For example, January 32 will come back as February 1 @@ -3692,7 +3703,7 @@ __gg__test_date_yyyymmdd( cblc_field_t *dest, extern "C" void __gg__test_day_yyyyddd( cblc_field_t *dest, - cblc_field_t *source, + const cblc_field_t *source, size_t source_offset, size_t source_size) { @@ -3730,7 +3741,7 @@ __gg__test_day_yyyyddd( cblc_field_t *dest, extern "C" void __gg__upper_case( cblc_field_t *dest, - cblc_field_t *input, + const cblc_field_t *input, size_t input_offset, size_t input_size) { @@ -3738,10 +3749,10 @@ __gg__upper_case( cblc_field_t *dest, size_t source_length = input_size; memset(dest->data, internal_space, dest_length); memcpy(dest->data, input->data+input_offset, std::min(dest_length, source_length)); - internal_to_ascii((char *)dest->data, dest_length); + internal_to_ascii( PTRCAST(char, dest->data), dest_length); std::transform(dest->data, dest->data + dest_length, dest->data, [](unsigned char c) { return std::toupper(c); }); - ascii_to_internal_str((char *)dest->data, dest_length); + ascii_to_internal_str( PTRCAST(char, dest->data), dest_length); } extern "C" @@ -3777,13 +3788,13 @@ __gg__when_compiled(cblc_field_t *dest, size_t tv_sec, long tv_nsec) extern "C" void __gg__year_to_yyyy( cblc_field_t *dest, - cblc_field_t *par1, + const cblc_field_t *par1, size_t par1_o, size_t par1_s, - cblc_field_t *par2, + const cblc_field_t *par2, size_t par2_o, size_t par2_s, - cblc_field_t *par3, + const cblc_field_t *par3, size_t par3_o, size_t par3_s) { @@ -3804,7 +3815,7 @@ __gg__year_to_yyyy( cblc_field_t *dest, static int -gets_int(int ndigits, char *p, char *pend, int *digits) +gets_int(int ndigits, const char *p, const char *pend, int *digits) { // This routine returns the value of the integer at p. If there is something // wrong with the integer, it returns a negative number, the value being the @@ -3835,7 +3846,7 @@ gets_int(int ndigits, char *p, char *pend, int *digits) static int -gets_year(char *p, char *pend, struct cobol_tm &ctm) +gets_year(const char *p, const char *pend, struct cobol_tm &ctm) { // Populates ctm.YYYY, ctm.days_in_year, and ctm.weeks_in_year, which are // all determined by the YYYY value. @@ -3855,10 +3866,6 @@ gets_year(char *p, char *pend, struct cobol_tm &ctm) { return 2; } - if( digits[0] == 0 && digits[1] < 5) - { - return 2; - } if( digits[2] == -1 ) { return 3; @@ -3903,7 +3910,7 @@ gets_year(char *p, char *pend, struct cobol_tm &ctm) static int -gets_month(char *p, char *pend, struct cobol_tm &ctm) +gets_month(const char *p, const char *pend, struct cobol_tm &ctm) { // Populates ctm.MM @@ -3950,7 +3957,7 @@ gets_month(char *p, char *pend, struct cobol_tm &ctm) static int -gets_day(char *p, char *pend, struct cobol_tm &ctm) +gets_day(const char *p, const char *pend, struct cobol_tm &ctm) { // Populates ctm.DD, ctm.day_of_week, ctm.week_of_year, ctm.day_of_week @@ -3968,48 +3975,45 @@ gets_day(char *p, char *pend, struct cobol_tm &ctm) { return 2; } - if(DD >= 0) + if( DD >= 0 ) { - if( DD >= 0 ) + if( DD == 0) { - if( DD == 0) - { - // If zero, we know we failed at the second '0' in "00" - retval = 2; - } - else if( DD >= 40) + // If zero, we know we failed at the second '0' in "00" + retval = 2; + } + else if( DD >= 40) + { + // 40 or more, then we knew there was trouble at the first digit + retval = 1; + } + else if(ctm.MM == 2 && DD >=30) + { + // It's February, so if we see 3x we know on the 3 that we are in + // error: + retval = 1; + } + else + { + static const int month_days[13] = {-1,31,28,31,30,31,30,31,31,30,31,30,31}; + int days_in_month = month_days[ctm.MM]; + if( ctm.MM == 2 && ctm.days_in_year == 366 ) { - // 40 or more, then we knew there was trouble at the first digit - retval = 1; + days_in_month = 29; } - else if(ctm.MM == 2 && DD >=30) + + if( DD > days_in_month ) { - // It's February, so if we see 3x we know on the 3 that we are in - // error: - retval = 1; + retval = 2; } else { - static const int month_days[13] = {-1,31,28,31,30,31,30,31,31,30,31,30,31}; - int days_in_month = month_days[ctm.MM]; - if( ctm.MM == 2 && ctm.days_in_year == 366 ) - { - days_in_month = 29; - } - - if( DD > days_in_month ) - { - retval = 2; - } - else - { - // We have a good YYYY-MM-DD - ctm.DD = DD; - double JD = YMD_to_JD(ctm.YYYY, ctm.MM, DD); - double JD_Jan0 = YMD_to_JD(ctm.YYYY, 1, 0); - ctm.day_of_year = (int)(JD - JD_Jan0); - ctm.day_of_week = JD_to_DOW(JD); - } + // We have a good YYYY-MM-DD + ctm.DD = DD; + double JD = YMD_to_JD(ctm.YYYY, ctm.MM, DD); + double JD_Jan0 = YMD_to_JD(ctm.YYYY, 1, 0); + ctm.day_of_year = (int)(JD - JD_Jan0); + ctm.day_of_week = JD_to_DOW(JD); } } } @@ -4022,7 +4026,7 @@ gets_day(char *p, char *pend, struct cobol_tm &ctm) static int -gets_day_of_week(char *p, char *pend, struct cobol_tm &ctm) +gets_day_of_week(const char *p, const char *pend, struct cobol_tm &ctm) { // This is just a simple D, for day-of-week. The COBOL spec is that // it be 1 to 7, 1 being Monday @@ -4071,7 +4075,7 @@ gets_day_of_week(char *p, char *pend, struct cobol_tm &ctm) static int -gets_day_of_year(char *p, char *pend, struct cobol_tm &ctm) +gets_day_of_year(const char *p, const char *pend, struct cobol_tm &ctm) { // This is a three-digit day-of-year, 001 through 365,366 int digits[3]; @@ -4128,7 +4132,7 @@ gets_day_of_year(char *p, char *pend, struct cobol_tm &ctm) static int -gets_week(char *p, char *pend, struct cobol_tm &ctm) +gets_week(const char *p, const char *pend, struct cobol_tm &ctm) { // This is a two-digit value, 01 through 52,53 int digits[2]; @@ -4168,7 +4172,10 @@ gets_week(char *p, char *pend, struct cobol_tm &ctm) static int -gets_hours(char *p, char *pend, struct cobol_tm &ctm, bool in_offset) +gets_hours( const char *p, + const char *pend, + struct cobol_tm &ctm, + bool in_offset) { // This is a two-digit value, 01 through 23 int digits[2]; @@ -4213,7 +4220,10 @@ gets_hours(char *p, char *pend, struct cobol_tm &ctm, bool in_offset) static int -gets_minutes(char *p, char *pend, struct cobol_tm &ctm, bool in_offset) +gets_minutes( const char *p, + const char *pend, + struct cobol_tm &ctm, + bool in_offset) { // This is a two-digit value, 01 through 59 int digits[2]; @@ -4251,7 +4261,7 @@ gets_minutes(char *p, char *pend, struct cobol_tm &ctm, bool in_offset) static int -gets_seconds(char *p, char *pend, struct cobol_tm &ctm) +gets_seconds(const char *p, const char *pend, struct cobol_tm &ctm) { // This is a two-digit value, 01 through 59 int digits[2]; @@ -4281,7 +4291,11 @@ gets_seconds(char *p, char *pend, struct cobol_tm &ctm) static int -gets_nanoseconds(char *f, char *f_end, char *p, char *pend, struct cobol_tm &ctm) +gets_nanoseconds( const char *f, + const char *f_end, + const char *p, + const char *pend, + struct cobol_tm &ctm) { // Because nanoseconds digits to the right of the decimal point can vary from // one digit to our implementation-specific limit of nine characters, this @@ -4293,7 +4307,7 @@ gets_nanoseconds(char *f, char *f_end, char *p, char *pend, struct cobol_tm &ctm int ncount = 0; int nanoseconds = 0; - char *pinit = p; + const char *pinit = p; while( f < f_end && *f == internal_s && p < pend ) { f += 1; @@ -4325,19 +4339,19 @@ gets_nanoseconds(char *f, char *f_end, char *p, char *pend, struct cobol_tm &ctm static int fill_cobol_tm(cobol_tm &ctm, - cblc_field_t *par1, + const cblc_field_t *par1, size_t par1_offset, size_t par1_size, - cblc_field_t *par2, + const cblc_field_t *par2, size_t par2_offset, size_t par2_size) { // Establish the formatting string: - char *format = (char *)(par1->data+par1_offset); + char *format = PTRCAST(char, (par1->data+par1_offset)); char *format_end = format + par1_size; // Establish the string to be checked: - char *source = (char *)(par2->data+par2_offset); + char *source = PTRCAST(char, (par2->data+par2_offset)); char *source_end = source + par2_size; // Let's eliminate trailing spaces... @@ -4587,10 +4601,10 @@ proceed: extern "C" void __gg__test_formatted_datetime(cblc_field_t *dest, - cblc_field_t *arg1, + const cblc_field_t *arg1, size_t arg1_offset, size_t arg1_size, - cblc_field_t *arg2, + const cblc_field_t *arg2, size_t arg2_offset, size_t arg2_size) @@ -4610,10 +4624,10 @@ __gg__test_formatted_datetime(cblc_field_t *dest, extern "C" void __gg__integer_of_formatted_date(cblc_field_t *dest, - cblc_field_t *arg1, + const cblc_field_t *arg1, size_t arg1_offset, size_t arg1_size, - cblc_field_t *arg2, + const cblc_field_t *arg2, size_t arg2_offset, size_t arg2_size) { @@ -4645,10 +4659,10 @@ __gg__integer_of_formatted_date(cblc_field_t *dest, extern "C" void __gg__seconds_from_formatted_time(cblc_field_t *dest, - cblc_field_t *arg1, + const cblc_field_t *arg1, size_t arg1_offset, size_t arg1_size, - cblc_field_t *arg2, + const cblc_field_t *arg2, size_t arg2_offset, size_t arg2_size) { @@ -4673,7 +4687,7 @@ __gg__seconds_from_formatted_time(cblc_field_t *dest, extern "C" void __gg__hex_of(cblc_field_t *dest, - cblc_field_t *field, + const cblc_field_t *field, size_t field_offset, size_t field_size) { @@ -4691,7 +4705,7 @@ __gg__hex_of(cblc_field_t *dest, extern "C" void __gg__highest_algebraic(cblc_field_t *dest, - cblc_field_t *var, + const cblc_field_t *var, size_t, size_t) { @@ -4733,7 +4747,7 @@ __gg__highest_algebraic(cblc_field_t *dest, extern "C" void __gg__lowest_algebraic( cblc_field_t *dest, - cblc_field_t *var, + const cblc_field_t *var, size_t, size_t) { @@ -4795,7 +4809,7 @@ __gg__lowest_algebraic( cblc_field_t *dest, } static int -floating_format_tester(char const * const f, char * const f_end) +floating_format_tester(char const * const f, char const * const f_end) { int retval = -1; char decimal_point = __gg__get_decimal_point(); @@ -4983,13 +4997,13 @@ floating_format_tester(char const * const f, char * const f_end) extern "C" void __gg__numval_f( cblc_field_t *dest, - cblc_field_t *source, + const cblc_field_t *source, size_t source_offset, size_t source_size) { GCOB_FP128 value = 0; - char *data = (char * )(source->data + source_offset); - char *data_end = data + source_size; + const char *data = PTRCAST(char, (source->data + source_offset)); + const char *data_end = data + source_size; int error = floating_format_tester(data, data_end); @@ -5022,12 +5036,12 @@ __gg__numval_f( cblc_field_t *dest, extern "C" void __gg__test_numval_f(cblc_field_t *dest, - cblc_field_t *source, + const cblc_field_t *source, size_t source_offset, size_t source_size) { - char *data = (char * )(source->data + source_offset); - char *data_end = data + source_size; + const char *data = PTRCAST(char, (source->data + source_offset)); + const char *data_end = data + source_size; int error = floating_format_tester(data, data_end); @@ -5039,7 +5053,7 @@ __gg__test_numval_f(cblc_field_t *dest, } static bool -ismatch(char *a1, char *a2, char *b1, char *b2) +ismatch(const char *a1, const char *a2, const char *b1, const char *b2) { bool retval = true; while( a1 < a2 && b1 < b2 ) @@ -5053,7 +5067,7 @@ ismatch(char *a1, char *a2, char *b1, char *b2) } static bool -iscasematch(char *a1, char *a2, char *b1, char *b2) +iscasematch(const char *a1, const char *a2, const char *b1, const char *b2) { bool retval = true; while( a1 < a2 && b1 < b2 ) @@ -5066,11 +5080,15 @@ iscasematch(char *a1, char *a2, char *b1, char *b2) return retval; } -static char * -strstr(char *haystack, char *haystack_e, char *needle, char *needle_e) +static +const char * +strstr( const char *haystack, + const char *haystack_e, + const char *needle, + const char *needle_e) { - char *retval = NULL; - char *pend = haystack_e - (needle_e - needle); + const char *retval = NULL; + const char *pend = haystack_e - (needle_e - needle); while( haystack <= pend ) { if(ismatch(haystack, haystack_e, needle, needle_e)) @@ -5083,11 +5101,15 @@ strstr(char *haystack, char *haystack_e, char *needle, char *needle_e) return retval; } -static char * -strcasestr(char *haystack, char *haystack_e, char *needle, char *needle_e) +static +const char * +strcasestr( const char *haystack, + const char *haystack_e, + const char *needle, + const char *needle_e) { - char *retval = NULL; - char *pend = haystack_e - (needle_e - needle); + const char *retval = NULL; + const char *pend = haystack_e - (needle_e - needle); while( haystack <= pend ) { if(iscasematch(haystack, haystack_e, needle, needle_e)) @@ -5100,11 +5122,15 @@ strcasestr(char *haystack, char *haystack_e, char *needle, char *needle_e) return retval; } -static char * -strlaststr(char *haystack, char *haystack_e, char *needle, char *needle_e) +static +const char * +strlaststr( const char *haystack, + const char *haystack_e, + const char *needle, + const char *needle_e) { - char *retval = NULL; - char *pend = haystack_e - (needle_e - needle); + const char *retval = NULL; + const char *pend = haystack_e - (needle_e - needle); while( haystack <= pend ) { if(ismatch(haystack, haystack_e, needle, needle_e)) @@ -5116,11 +5142,15 @@ strlaststr(char *haystack, char *haystack_e, char *needle, char *needle_e) return retval; } -static char * -strcaselaststr(char *haystack, char *haystack_e, char *needle, char *needle_e) +static +const char * +strcaselaststr( const char *haystack, + const char *haystack_e, + const char *needle, + const char *needle_e) { - char *retval = NULL; - char *pend = haystack_e - (needle_e - needle); + const char *retval = NULL; + const char *pend = haystack_e - (needle_e - needle); while( haystack <= pend ) { if(iscasematch(haystack, haystack_e, needle, needle_e)) @@ -5134,13 +5164,13 @@ strcaselaststr(char *haystack, char *haystack_e, char *needle, char *needle_e) extern "C" -void __gg__substitute(cblc_field_t *dest, - cblc_field_t *arg1_f, - size_t arg1_o, - size_t arg1_s, - size_t N, - uint8_t *control - ) +void +__gg__substitute( cblc_field_t *dest, + const cblc_field_t *arg1_f, + size_t arg1_o, + size_t arg1_s, + size_t N, + const uint8_t *control) { // arg2 is the Group 1 triplet. // arg3 is the Group 2 triplet @@ -5148,19 +5178,22 @@ void __gg__substitute(cblc_field_t *dest, size_t *arg2_o = __gg__treeplet_1o; size_t *arg2_s = __gg__treeplet_1s; cblc_field_t **arg3_f = __gg__treeplet_2f; - size_t *arg3_o = __gg__treeplet_2o; - size_t *arg3_s = __gg__treeplet_2s; + const size_t *arg3_o = __gg__treeplet_2o; + const size_t *arg3_s = __gg__treeplet_2s; - ssize_t retval_size = 256; - char *retval = (char *)malloc(retval_size); + ssize_t retval_size; + retval_size = 256; + char *retval = static_cast<char *>(malloc(retval_size)); + massert(retval); *retval = '\0'; - char *haystack = (char *)(arg1_f->data + arg1_o); - char *haystack_e = haystack + arg1_s; + const char *haystack = PTRCAST(char, (arg1_f->data + arg1_o)); + const char *haystack_e = haystack + arg1_s; ssize_t outdex = 0; - char **pflasts = (char **)malloc(N * sizeof(char *)); + const char **pflasts = static_cast<const char **>(malloc(N * sizeof(char *))); + massert(pflasts); if( arg1_s == 0 ) { @@ -5181,15 +5214,15 @@ void __gg__substitute(cblc_field_t *dest, { pflasts[i] = strcasestr(haystack, haystack_e, - (char *)(arg2_f[i]->data+arg2_o[i]), - (char *)(arg2_f[i]->data+arg2_o[i]) + arg2_s[i]); + PTRCAST(char, (arg2_f[i]->data+arg2_o[i])), + PTRCAST(char, (arg2_f[i]->data+arg2_o[i])) + arg2_s[i]); } else if( control[i] & substitute_last_e) { pflasts[i] = strcaselaststr(haystack, haystack_e, - (char *)(arg2_f[i]->data+arg2_o[i]), - (char *)(arg2_f[i]->data+arg2_o[i]) + arg2_s[i]); + PTRCAST(char, (arg2_f[i]->data+arg2_o[i])), + PTRCAST(char, (arg2_f[i]->data+arg2_o[i])) + arg2_s[i]); } else { @@ -5202,15 +5235,15 @@ void __gg__substitute(cblc_field_t *dest, { pflasts[i] = strstr(haystack, haystack_e, - (char *)(arg2_f[i]->data+arg2_o[i]), - (char *)(arg2_f[i]->data+arg2_o[i]) + arg2_s[i]); + PTRCAST(char, (arg2_f[i]->data+arg2_o[i])), + PTRCAST(char, (arg2_f[i]->data+arg2_o[i])) + arg2_s[i]); } else if( control[i] & substitute_last_e) { pflasts[i] = strlaststr(haystack, haystack_e, - (char *)(arg2_f[i]->data+arg2_o[i]), - (char *)(arg2_f[i]->data+arg2_o[i]) + arg2_s[i]); + PTRCAST(char, (arg2_f[i]->data+arg2_o[i])), + PTRCAST(char, (arg2_f[i]->data+arg2_o[i])) + arg2_s[i]); } else { @@ -5230,7 +5263,8 @@ void __gg__substitute(cblc_field_t *dest, > retval_size ) { retval_size *= 2; - retval = (char *)realloc(retval, retval_size); + retval = static_cast<char *>(realloc(retval, retval_size)); + massert(retval); } // We checked earlier for FIRST/LAST matches @@ -5245,8 +5279,8 @@ void __gg__substitute(cblc_field_t *dest, continue; } - char *needle = (char *)(arg2_f[i]->data+arg2_o[i]); - char *needle_e = (char *)(arg2_f[i]->data+arg2_o[i]) + arg2_s[i]; + const char *needle = PTRCAST(char, arg2_f[i]->data+arg2_o[i]); + const char *needle_e = PTRCAST(char, arg2_f[i]->data+arg2_o[i]) + arg2_s[i]; matched = (control[i] & substitute_anycase_e) && iscasematch( haystack, haystack_e, @@ -5274,7 +5308,8 @@ void __gg__substitute(cblc_field_t *dest, while( outdex + 1 > retval_size ) { retval_size *= 2; - retval = (char *)realloc(retval, retval_size); + retval = static_cast<char *>(realloc(retval, retval_size)); + massert(retval); } retval[outdex++] = *haystack++; } @@ -5291,13 +5326,13 @@ void __gg__substitute(cblc_field_t *dest, extern "C" void __gg__locale_compare( cblc_field_t *dest, - cblc_field_t *arg1, + const cblc_field_t *arg1, size_t arg1_o, size_t arg1_s, - cblc_field_t *arg2, + const cblc_field_t *arg2, size_t arg2_o, size_t arg2_s, - cblc_field_t *arg_locale, + const cblc_field_t *arg_locale, size_t /*arg_locale_o*/, size_t /*arg_locale_s*/ ) @@ -5348,10 +5383,10 @@ __gg__locale_compare( cblc_field_t *dest, extern "C" void __gg__locale_date(cblc_field_t *dest, - cblc_field_t *arg1, + const cblc_field_t *arg1, size_t arg1_o, size_t /*arg1_s*/, - cblc_field_t *arg_locale, + const cblc_field_t *arg_locale, size_t /*arg_locale_o*/, size_t /*arg_locale_s*/) { @@ -5384,10 +5419,10 @@ __gg__locale_date(cblc_field_t *dest, extern "C" void __gg__locale_time(cblc_field_t *dest, - cblc_field_t *arg1, + const cblc_field_t *arg1, size_t arg1_o, size_t /*arg1_s*/, - cblc_field_t *arg_locale, + const cblc_field_t *arg_locale, size_t /*arg_locale_o*/, size_t /*arg_locale_s*/) @@ -5420,10 +5455,10 @@ __gg__locale_time(cblc_field_t *dest, extern "C" void __gg__locale_time_from_seconds( cblc_field_t *dest, - cblc_field_t *arg1, + const cblc_field_t *arg1, size_t arg1_o, size_t arg1_s, - cblc_field_t *arg_locale, + const cblc_field_t *arg_locale, size_t /*arg_locale_o*/, size_t /*arg_locale_s*/) { @@ -5439,7 +5474,7 @@ __gg__locale_time_from_seconds( cblc_field_t *dest, // Default locale tm tm = {}; - int rdigits; + int rdigits=0; long seconds = (long)__gg__binary_value_from_qualified_field(&rdigits, arg1, arg1_o, diff --git a/libgcobol/libgcobol.cc b/libgcobol/libgcobol.cc index 3ab7463..f17c659 100644 --- a/libgcobol/libgcobol.cc +++ b/libgcobol/libgcobol.cc @@ -65,14 +65,11 @@ #include "gfileio.h" #include "charmaps.h" #include "valconv.h" - #include <sys/mman.h> #include <sys/resource.h> #include <sys/stat.h> #include <sys/types.h> - #include <execinfo.h> - #include "exceptl.h" /* BSD extension. */ @@ -196,7 +193,7 @@ size_t __gg__unique_prog_id = 0 ; // location information are established in the "last_exception..." variables. // This is in accordance with the ISO requirements of "14.6.13.1.1 General" that // describe how a "last exception status" is maintained. -// other "location" information +// other "location" information static int last_exception_code; static const char *last_exception_program_id; static const char *last_exception_section; @@ -240,36 +237,43 @@ void *__gg__exit_address = NULL; * 4. handled, where handled == type * * If the statement includes some kind of ON ERROR - * clause that covers it, the generated code does not raise an EC. + * clause that covers it, the generated code does not raise an EC. * * The status is updated by __gg_match_exception if it runs, else - * __gg__check_fatal_exception. + * __gg__check_fatal_exception. * * If a Declarative is matched, its section number is passed to handled_by(), * which does two things: * 1. sets isection to record the declarative * 2. for a nonfatal EC, sets handled, indication no further action is needed * - * A Declarative may use RESUME, which clears ec_status, which is a "handled" state. - * - * Default processing ensures return to initial state. + * A Declarative may use RESUME, which clears ec_status, which is a "handled" state. + * + * Default processing ensures return to initial state. */ class ec_status_t { public: struct file_status_t { - size_t ifile; - cblc_file_prior_op_t operation; - cbl_file_mode_t mode; + size_t ifile; + cblc_file_prior_op_t operation; + cbl_file_mode_t mode; cblc_field_t *user_status; const char * filename; - file_status_t() : ifile(0) , operation(file_op_none), mode(file_mode_none_e) {} - file_status_t( cblc_file_t *file ) - : ifile(file->symbol_table_index) - , operation(file->prior_op) - , mode(cbl_file_mode_t(file->mode_char)) - , user_status(file->user_status) - , filename(file->filename) - {} + file_status_t() + : ifile(0) + , operation(file_op_none) + , mode(file_mode_none_e) + , user_status(nullptr) + , filename(nullptr) + {} +// cppcheck-suppress noExplicitConstructor + file_status_t( const cblc_file_t *file ) + : ifile(file->symbol_table_index) + , operation(file->prior_op) + , mode(cbl_file_mode_t(file->mode_char)) + , user_status(file->user_status) + , filename(file->filename) + {} const char * op_str() const { switch( operation ) { case file_op_none: return "none"; @@ -284,7 +288,7 @@ class ec_status_t { return "???"; } }; - private: + private: char msg[132]; ec_type_t type, handled; size_t isection; @@ -308,13 +312,13 @@ class ec_status_t { bool is_fatal() const; ec_status_t& update(); - + bool is_enabled() const { return enabled.match(type); } bool is_enabled( ec_type_t ec) const { return enabled.match(ec); } ec_status_t& handled_by( size_t declarative_section ) { isection = declarative_section; - // A fatal exception remains unhandled unless RESUME clears it. - if( ! is_fatal() ) { + // A fatal exception remains unhandled unless RESUME clears it. + if( ! is_fatal() ) { handled = type; } return *this; @@ -326,10 +330,10 @@ class ec_status_t { return *this; } bool unset() const { return isection == 0 && lineno == 0; } - + void reset_environment() const; ec_status_t& copy_environment(); - + // Return the EC's type if it is *not* handled. ec_type_t unhandled() const { bool was_handled = ec_cmp(type, handled); @@ -428,8 +432,17 @@ ec_status_t::reset_environment() const { ::declaratives = declaratives; } + +// This is the default truncation mode static cbl_truncation_mode truncation_mode = trunc_std_e; +extern "C" +void +__gg__set_truncation_mode(cbl_truncation_mode trunc_mode) + { + truncation_mode = trunc_mode; + } + struct program_state { // These are the run-time values of these characters. @@ -535,7 +548,6 @@ void *malloc(size_t a) void *retval = malloc(a); fprintf(stderr, " --malloc(%p)-- ", retval); return retval; - return retval; } #endif @@ -546,6 +558,12 @@ __gg__abort(const char *msg) abort(); } +void +__gg__mabort() + { + __gg__abort("Memory allocation error\n"); + } + extern "C" char __gg__get_decimal_point() @@ -576,7 +594,7 @@ __gg__resize_int_p( size_t *size, if( new_size > *size ) { *size = new_size; - *block = (int *)realloc(*block, new_size * sizeof(int)); + *block = static_cast<int *>(realloc(*block, new_size * sizeof(int))); } } @@ -591,36 +609,36 @@ __gg__resize_treeplet(int ngroup, if( new_size > treeplet_1_size ) { treeplet_1_size = new_size; - __gg__treeplet_1f = (cblc_field_t **)realloc(__gg__treeplet_1f, new_size * sizeof(cblc_field_t *)); - __gg__treeplet_1o = (size_t *)realloc(__gg__treeplet_1o, new_size * sizeof(size_t)); - __gg__treeplet_1s = (size_t *)realloc(__gg__treeplet_1s, new_size * sizeof(size_t)); + __gg__treeplet_1f = static_cast<cblc_field_t **>(realloc(__gg__treeplet_1f, new_size * sizeof(cblc_field_t *))); + __gg__treeplet_1o = static_cast<size_t *>(realloc(__gg__treeplet_1o, new_size * sizeof(size_t))); + __gg__treeplet_1s = static_cast<size_t *>(realloc(__gg__treeplet_1s, new_size * sizeof(size_t))); } break; case 2: if( new_size > treeplet_2_size ) { treeplet_2_size = new_size; - __gg__treeplet_2f = (cblc_field_t **)realloc(__gg__treeplet_2f, new_size * sizeof(cblc_field_t *)); - __gg__treeplet_2o = (size_t *)realloc(__gg__treeplet_2o, new_size * sizeof(size_t)); - __gg__treeplet_2s = (size_t *)realloc(__gg__treeplet_2s, new_size * sizeof(size_t)); + __gg__treeplet_2f = static_cast<cblc_field_t **>(realloc(__gg__treeplet_2f, new_size * sizeof(cblc_field_t *))); + __gg__treeplet_2o = static_cast<size_t *>(realloc(__gg__treeplet_2o, new_size * sizeof(size_t))); + __gg__treeplet_2s = static_cast<size_t *>(realloc(__gg__treeplet_2s, new_size * sizeof(size_t))); } break; case 3: if( new_size > treeplet_3_size ) { treeplet_3_size = new_size; - __gg__treeplet_3f = (cblc_field_t **)realloc(__gg__treeplet_3f, new_size * sizeof(cblc_field_t *)); - __gg__treeplet_3o = (size_t *)realloc(__gg__treeplet_3o, new_size * sizeof(size_t)); - __gg__treeplet_3s = (size_t *)realloc(__gg__treeplet_3s, new_size * sizeof(size_t)); + __gg__treeplet_3f = static_cast<cblc_field_t **>(realloc(__gg__treeplet_3f, new_size * sizeof(cblc_field_t *))); + __gg__treeplet_3o = static_cast<size_t *>(realloc(__gg__treeplet_3o, new_size * sizeof(size_t))); + __gg__treeplet_3s = static_cast<size_t *>(realloc(__gg__treeplet_3s, new_size * sizeof(size_t))); } break; case 4: if( new_size > treeplet_4_size ) { treeplet_4_size = new_size; - __gg__treeplet_4f = (cblc_field_t **)realloc(__gg__treeplet_4f, new_size * sizeof(cblc_field_t *)); - __gg__treeplet_4o = (size_t *)realloc(__gg__treeplet_4o, new_size * sizeof(size_t)); - __gg__treeplet_4s = (size_t *)realloc(__gg__treeplet_4s, new_size * sizeof(size_t)); + __gg__treeplet_4f = static_cast<cblc_field_t **>(realloc(__gg__treeplet_4f, new_size * sizeof(cblc_field_t *))); + __gg__treeplet_4o = static_cast<size_t *>(realloc(__gg__treeplet_4o, new_size * sizeof(size_t))); + __gg__treeplet_4s = static_cast<size_t *>(realloc(__gg__treeplet_4s, new_size * sizeof(size_t))); } break; } @@ -738,7 +756,7 @@ __gg__init_program_state() } static int -var_is_refmod( cblc_field_t *var ) +var_is_refmod( const cblc_field_t *var ) { return (var->attr & refmod_e) != 0; } @@ -907,9 +925,9 @@ __gg__binary_to_string_internal(char *result, int digits, __int128 value) } static bool -value_is_too_big( cblc_field_t *var, - __int128 value, - int source_rdigits) +value_is_too_big(const cblc_field_t *var, + __int128 value, + int source_rdigits) { // This routine is in support of arithmetic ON SIZE ERROR. It returns // TRUE if var hasn't enough bytes to hold the decimal representation @@ -1046,12 +1064,13 @@ is_sign_bit_on(char ch) extern "C" void -__gg__string_to_alpha_edited_ascii( char *dest, - char *source, - int slength, - char *picture) +__gg__string_to_alpha_edited_ascii( char *dest, + const char *source, + int slength, + const char *picture) { - char *dupe = (char *)malloc(slength); + char *dupe = static_cast<char *>(malloc(slength)); + massert(dupe); memcpy(dupe, source, slength); ascii_to_internal_str(dupe, slength); __gg__string_to_alpha_edited(dest, dupe, slength, picture); @@ -1406,7 +1425,7 @@ int128_to_field(cblc_field_t *var, { float tvalue = (float)value; tvalue /= (float)__gg__power_of_ten(source_rdigits); - *(float *)location = tvalue; + *PTRCAST(float, location) = tvalue; break; } @@ -1414,7 +1433,7 @@ int128_to_field(cblc_field_t *var, { double tvalue = (double)value; tvalue /= (double)__gg__power_of_ten(source_rdigits); - *(double *)location = tvalue; + *PTRCAST(double, location) = tvalue; break; } @@ -1478,8 +1497,6 @@ int128_to_field(cblc_field_t *var, default: { - bool size_error = false; - int target_rdigits = var->rdigits; if( var->attr & intermediate_e && var->type == FldNumericBin5) { @@ -1569,6 +1586,7 @@ int128_to_field(cblc_field_t *var, else { // Value is now scaled to the target's target_rdigits + bool size_error = false; int is_negative = value < 0 ; @@ -1598,8 +1616,9 @@ int128_to_field(cblc_field_t *var, // Note that sending a signed value to an alphanumeric strips off // any plus or minus signs. - size_error = __gg__binary_to_string_internal( (char *)location, - length, value); + size_error = __gg__binary_to_string_internal( + PTRCAST(char, location), + length, value); break; case FldNumericDisplay: @@ -1615,7 +1634,7 @@ int128_to_field(cblc_field_t *var, { // The sign character goes into the first location size_error = - __gg__binary_to_string_internal((char *)(location+1), + __gg__binary_to_string_internal(PTRCAST(char, location+1), length-1, value); location[0] = sign_ch; } @@ -1623,8 +1642,8 @@ int128_to_field(cblc_field_t *var, { // The sign character goes into the last location size_error = - __gg__binary_to_string_internal( (char *)location, - length-1, value); + __gg__binary_to_string_internal(PTRCAST(char, location), + length-1, value); location[length-1] = sign_ch; } } @@ -1633,7 +1652,7 @@ int128_to_field(cblc_field_t *var, // The sign information is not separate, so we put it into // the number size_error = - __gg__binary_to_string_internal(( char *)location, + __gg__binary_to_string_internal(PTRCAST(char, location), length, value); if( size_error && is_negative ) @@ -1669,7 +1688,8 @@ int128_to_field(cblc_field_t *var, else { // It's a simple positive number - size_error = __gg__binary_to_string_internal( (char *)location, + size_error = __gg__binary_to_string_internal( PTRCAST(char, + location), length, value); } @@ -1692,12 +1712,12 @@ int128_to_field(cblc_field_t *var, // Convert that string according to the PICTURE clause size_error |= __gg__string_to_numeric_edited( - (char *)location, + PTRCAST(char, location), ach, target_rdigits, is_negative, var->picture); - ascii_to_internal_str((char *)location, var->capacity); + ascii_to_internal_str( PTRCAST(char, location), var->capacity); } break; @@ -1733,7 +1753,7 @@ int128_to_field(cblc_field_t *var, // Convert that string according to the PICTURE clause __gg__string_to_alpha_edited( - (char *)location, + PTRCAST(char, location), ach, strlen(ach), var->picture); @@ -1849,11 +1869,11 @@ int128_to_field(cblc_field_t *var, } static __int128 -edited_to_binary( const char *ps_, +edited_to_binary( char *ps_, int length, int *rdigits) { - const unsigned char *ps = (const unsigned char *)ps_; + const unsigned char *ps = const_cast<const unsigned char *>(PTRCAST(unsigned char, ps_)); // This routine is used for converting NumericEdited strings to // binary. @@ -1879,8 +1899,6 @@ edited_to_binary( const char *ps_, __int128 result = 0; - unsigned char ch; - // We need to check the last two characters. If CR or DB, then the result // is negative: if( length >= 2) @@ -1901,7 +1919,7 @@ edited_to_binary( const char *ps_, while( index < length ) { - ch = ps[index++] & 0xFF; + unsigned char ch = ps[index++] & 0xFF; if( ch == ascii_to_internal(__gg__decimal_point) ) { delta_r = 1; @@ -1923,11 +1941,7 @@ edited_to_binary( const char *ps_, } } - if( result == 0 ) - { - hyphen = 0; - } - else if( hyphen ) + if( hyphen ) { result = -result; } @@ -1957,7 +1971,7 @@ big_endian_to_binary_signed( } // move the bytes of psource into retval, flipping them end-to-end - unsigned char *dest = (unsigned char *)&retval; + unsigned char *dest = PTRCAST(unsigned char, &retval); while(capacity > 0) { *dest++ = psource[--capacity]; @@ -2021,7 +2035,7 @@ big_endian_to_binary_unsigned( __int128 retval = 0 ; // move the bytes of psource into retval, flipping them end-to-end - unsigned char *dest = (unsigned char *)&retval; + unsigned char *dest = PTRCAST(unsigned char, &retval); while(capacity > 0) { *dest++ = psource[--capacity]; @@ -2031,10 +2045,10 @@ big_endian_to_binary_unsigned( static __int128 -get_binary_value_local( int *rdigits, - cblc_field_t *resolved_var, - unsigned char *resolved_location, - size_t resolved_length) +get_binary_value_local( int *rdigits, + const cblc_field_t *resolved_var, + unsigned char *resolved_location, + size_t resolved_length) { __int128 retval = 0; @@ -2055,7 +2069,8 @@ get_binary_value_local( int *rdigits, case FldGroup : case FldAlphanumeric : // Read the data area as a dirty string: - retval = __gg__dirty_to_binary_internal( (const char *)resolved_location, + retval = __gg__dirty_to_binary_internal( PTRCAST(const char, + resolved_location), resolved_length, rdigits ); break; @@ -2082,8 +2097,8 @@ get_binary_value_local( int *rdigits, // Turn all the bits on memset( &retval, 0xFF, sizeof(retval) ); - // Make it positive - ((unsigned char *)&retval)[sizeof(retval)-1] = 0x3F; + // Make it positive by turning off the highest order bit: + (PTRCAST(unsigned char, &retval))[sizeof(retval)-1] = 0x3F; *rdigits = resolved_var->rdigits; } else @@ -2120,7 +2135,8 @@ get_binary_value_local( int *rdigits, // We know where the decimal point is because of rdigits. Because // we know that it a clean string of ASCII digits, we can use the // dirty converter: - retval = __gg__dirty_to_binary_internal((const char *)resolved_location, + retval = __gg__dirty_to_binary_internal(PTRCAST(const char, + resolved_location), resolved_length, rdigits ); *rdigits = resolved_var->rdigits; @@ -2136,7 +2152,7 @@ get_binary_value_local( int *rdigits, break; case FldNumericEdited : - retval = edited_to_binary( (const char *)resolved_location, + retval = edited_to_binary( PTRCAST(char, resolved_location), resolved_length, rdigits); break; @@ -2145,13 +2161,13 @@ get_binary_value_local( int *rdigits, if( resolved_var->attr & signable_e) { retval = big_endian_to_binary_signed( - (const unsigned char *)resolved_location, + PTRCAST(const unsigned char, resolved_location), resolved_length); } else { retval = big_endian_to_binary_unsigned( - (const unsigned char *)resolved_location, + PTRCAST(const unsigned char, resolved_location), resolved_length); } *rdigits = resolved_var->rdigits; @@ -2179,13 +2195,13 @@ get_binary_value_local( int *rdigits, if( resolved_var->attr & signable_e) { retval = little_endian_to_binary_signed( - (const unsigned char *)resolved_location, + PTRCAST(const unsigned char, resolved_location), resolved_length); } else { retval = little_endian_to_binary_unsigned( - (const unsigned char *)resolved_location, + PTRCAST(const unsigned char, resolved_location), resolved_length); } *rdigits = resolved_var->rdigits; @@ -2285,7 +2301,7 @@ __gg__get_date_yymmdd() char ach[32]; time_t t = cobol_time(); - struct tm *local = localtime(&t); + const struct tm *local = localtime(&t); sprintf(ach, "%2.2d%2.2d%2.2d", @@ -2304,7 +2320,7 @@ __gg__get_date_yyyymmdd() char ach[32]; time_t t = cobol_time(); - struct tm *local = localtime(&t); + const struct tm *local = localtime(&t); sprintf(ach, "%4.4d%2.2d%2.2d", @@ -2323,7 +2339,7 @@ __gg__get_date_yyddd() char ach[32]; time_t t = cobol_time(); - struct tm *local = localtime(&t); + const struct tm *local = localtime(&t); sprintf(ach, "%2.2d%3.3d", @@ -2341,7 +2357,7 @@ __gg__get_yyyyddd() char ach[32]; time_t t = cobol_time(); - struct tm *local = localtime(&t); + const struct tm *local = localtime(&t); sprintf(ach, "%4.4d%3.3d", @@ -2359,7 +2375,7 @@ __gg__get_date_dow() char ach[32]; time_t t = cobol_time(); - struct tm *local = localtime(&t); + const struct tm *local = localtime(&t); sprintf(ach, "%1.1d", @@ -2459,20 +2475,19 @@ int __gg__setop_compare( const char *candidate, int capacity, - const char *domain) + char *domain) { // This routine is called to compare the characters of 'candidate' // against the list of character pairs in 'domain' int retval = 0; - int ch; int l; int h; - const char *d; + char *d; for(int i=0; i<capacity; i++) { - ch = (*candidate++ & 0xFF); + int ch = (*candidate++ & 0xFF); d = domain; while(*d) { @@ -2484,7 +2499,7 @@ __gg__setop_compare( // See the comments in genapi.cc::get_class_condition_string // to see how this string was encoded. - l = (int)strtoll(d, (char **)&d, 16); + l = (int)strtoll(d, reinterpret_cast<char **>(&d), 16); if( l < 0 ) { l = -l; @@ -2493,7 +2508,7 @@ __gg__setop_compare( if( *d == '/' ) { d += 1; - h = (int)strtoll(d, (char **)&d, 16); + h = (int)strtoll(d, reinterpret_cast<char **>(&d), 16); if( h < 0 ) { h = -h; @@ -2943,7 +2958,7 @@ void psz_to_internal(char *psz) } static int -get_scaled_rdigits(cblc_field_t *field) +get_scaled_rdigits(const cblc_field_t *field) { int retval; if( !(field->attr & scaled_e) ) @@ -3048,7 +3063,7 @@ format_for_display_internal(char **dest, break; } - unsigned char *running_location = actual_location; + const unsigned char *running_location = actual_location; // We need the counts of digits to the left and right of the decimal point int rdigits = get_scaled_rdigits(var); @@ -3063,7 +3078,6 @@ format_for_display_internal(char **dest, rdigits += ldigits; } - int index = 0; // This is the running index into our output destination if( rdigits ) { // We need room for the inside decimal point @@ -3080,6 +3094,7 @@ format_for_display_internal(char **dest, if( actual_location ) { + int index = 0; // This is the running index into our output destination if( var->attr & signable_e ) { if( var->attr & separate_e ) @@ -3124,7 +3139,7 @@ format_for_display_internal(char **dest, // the user. if( (*dest)[index-1] != (char)DEGENERATE_HIGH_VALUE ) { - turn_sign_bit_off((unsigned char *)&ch); + turn_sign_bit_off( PTRCAST(unsigned char, &ch)); } (*dest)[index++] = ch; } @@ -3148,7 +3163,7 @@ format_for_display_internal(char **dest, char ch = *running_location++; if( (*dest)[index-1] != (char)DEGENERATE_HIGH_VALUE ) { - turn_sign_bit_off((unsigned char *)&ch); + turn_sign_bit_off(PTRCAST(unsigned char, &ch)); } (*dest)[index++] = ch; } @@ -3257,11 +3272,9 @@ format_for_display_internal(char **dest, } __gg__realloc_if_necessary(dest, dest_size, nsize); - bool is_signed = value < 0; - if( var->attr & signable_e ) { - if( is_signed ) + if( value < 0 ) { (*dest)[index++] = internal_minus; } @@ -3293,7 +3306,7 @@ format_for_display_internal(char **dest, actual_location, actual_length); char ach[64]; - sprintf(ach, "%lu", (size_t)value); + sprintf(ach, "%lu", (unsigned long)value); __gg__realloc_if_necessary(dest, dest_size, strlen(ach)+1); strcpy(*dest, ach); } @@ -3349,7 +3362,7 @@ format_for_display_internal(char **dest, // side, and 9999999 and then 1E+7 on the high side // 10,000,000 = 1E7 char ach[64]; - _Float32 floatval = *(_Float32 *)actual_location; + _Float32 floatval = *PTRCAST(_Float32, actual_location); strfromf32(ach, sizeof(ach), "%.9E", floatval); char *p = strchr(ach, 'E'); if( !p ) @@ -3389,7 +3402,7 @@ format_for_display_internal(char **dest, // We will also format numbers so that we produce 0.01 and 1E-3 on the low // side, and 9999999 and then 1E+15 on the high side char ach[64]; - _Float64 floatval = *(_Float64 *)actual_location; + _Float64 floatval = *PTRCAST(_Float64, actual_location); strfromf64(ach, sizeof(ach), "%.17E", floatval); char *p = strchr(ach, 'E'); if( !p ) @@ -3483,7 +3496,8 @@ format_for_display_internal(char **dest, if( var->attr & scaled_e && var->type != FldNumericDisplay ) { static size_t buffer_size = MINIMUM_ALLOCATION_SIZE; - static char * buffer = (char *)malloc(buffer_size); + static char *buffer = static_cast<char *>(malloc(buffer_size)); + massert(buffer); if( var->rdigits > 0) { // We have something like 123 or +123. We need to insert a decimal @@ -3542,7 +3556,7 @@ format_for_display_internal(char **dest, { p2 += 1; } - strcpy((char *)p1, (char *)p2); + strcpy(PTRCAST(char, p1), PTRCAST(char, p2)); } done: @@ -3591,7 +3605,8 @@ compare_88( const char *list, { // We are working with a figurative constant - test = (char *)malloc(conditional_length); + test = static_cast<char *>(malloc(conditional_length)); + massert(test); test_len = conditional_length; // This is where we handle the zero-length strings that // nonetheless can magically be expanded into figurative @@ -3628,14 +3643,16 @@ compare_88( const char *list, else if( list_len < conditional_length ) { // 'list' is too short; we have to right-fill with spaces: - test = (char *)malloc(conditional_length); + test = static_cast<char *>(malloc(conditional_length)); + massert(test); test_len = conditional_length; memset(test, internal_space, conditional_length); memcpy(test, list, list_len); } else { - test = (char *)malloc(list_len); + test = static_cast<char *>(malloc(list_len)); + massert(test); test_len = list_len; memcpy(test, list, list_len); } @@ -3648,7 +3665,9 @@ compare_88( const char *list, } else { - cmpval = cstrncmp(test, (char *)conditional_location, conditional_length); + cmpval = cstrncmp (test, + PTRCAST(char, conditional_location), + conditional_length); if( cmpval == 0 && (int)strlen(test) != conditional_length ) { // When strncmp returns 0, the actual smaller string is the @@ -3671,7 +3690,7 @@ compare_88( const char *list, } static GCOB_FP128 -get_float128( cblc_field_t *field, +get_float128( const cblc_field_t *field, unsigned char *location ) { GCOB_FP128 retval=0; @@ -3680,10 +3699,10 @@ get_float128( cblc_field_t *field, switch( field->capacity ) { case 4: - retval = *(_Float32 *)location; + retval = *PTRCAST(_Float32 , location); break; case 8: - retval = *(_Float64 *)location; + retval = *PTRCAST(_Float64 , location); break; case 16: // retval = *(_Float128 *)location; doesn't work, because the SSE @@ -3703,12 +3722,13 @@ get_float128( cblc_field_t *field, { // We need to replace any commas with periods static size_t size = 128; - static char *buffer = (char *)malloc(size); + static char *buffer = static_cast<char *>(malloc(size)); while( strlen(field->initial)+1 > size ) { size *= 2; - buffer = (char *)malloc(size); + buffer = static_cast<char *>(malloc(size)); } + massert(buffer); strcpy(buffer, field->initial); char *p = strchr(buffer, ','); if(p) @@ -3753,7 +3773,7 @@ compare_field_class(cblc_field_t *conditional, conditional, conditional_location, conditional_length); - char *walker = list->initial; + const char *walker = list->initial; while(*walker) { char left_flag; @@ -3899,8 +3919,8 @@ compare_field_class(cblc_field_t *conditional, case FldFloat: { - GCOB_FP128 value = get_float128(conditional, conditional_location) ; - char *walker = list->initial; + GCOB_FP128 fp128 = get_float128(conditional, conditional_location) ; + const char *walker = list->initial; while(*walker) { char left_flag; @@ -3945,7 +3965,7 @@ compare_field_class(cblc_field_t *conditional, right_len); } - if( left_value <= value && value <= right_value ) + if( left_value <= fp128 && fp128 <= right_value ) { retval = 0; break; @@ -4025,12 +4045,12 @@ local_is_alpha(int type, bool address_of) static int -compare_strings(char *left_string, - size_t left_length, - bool left_all, - char *right_string, - size_t right_length, - bool right_all) +compare_strings(const char *left_string, + size_t left_length, + bool left_all, + const char *right_string, + size_t right_length, + bool right_all) { int retval = 0; size_t i = 0; @@ -4284,6 +4304,7 @@ __gg__compare_2(cblc_field_t *left_side, retval = 0; retval = value < 0 ? -1 : retval; retval = value > 0 ? 1 : retval; + compare = true; break; } @@ -4294,6 +4315,7 @@ __gg__compare_2(cblc_field_t *left_side, retval = 0; retval = value < 0 ? -1 : retval; retval = value > 0 ? 1 : retval; + compare = true; break; } @@ -4312,9 +4334,7 @@ __gg__compare_2(cblc_field_t *left_side, compare = true; break; } - compare = true; goto fixup_retval; - break; } } } @@ -4329,10 +4349,10 @@ __gg__compare_2(cblc_field_t *left_side, if( local_is_alpha(left_side->type, left_address_of) && local_is_alpha(right_side->type, right_address_of) ) { - retval = compare_strings( (char *)left_location, + retval = compare_strings( reinterpret_cast<char *>(left_location), left_length, left_all, - (char *)right_location, + reinterpret_cast<char *>(right_location), right_length, right_all ); @@ -4368,12 +4388,13 @@ __gg__compare_2(cblc_field_t *left_side, // literal to be the same flavor as the left side: // We need to replace any commas with periods static size_t size = 128; - static char *buffer = (char *)malloc(size); + static char *buffer = static_cast<char *>(malloc(size)); while( strlen(right_side->initial)+1 > size ) { size *= 2; - buffer = (char *)malloc(size); + buffer = static_cast<char *>(malloc(size)); } + massert(buffer); strcpy(buffer, right_side->initial); if( __gg__decimal_point == ',' ) { @@ -4391,31 +4412,31 @@ __gg__compare_2(cblc_field_t *left_side, { case 4: { - _Float32 left_value = *(_Float32 *)left_location; - _Float32 right_value = strtof(buffer, NULL); + _Float32 left_value4 = *PTRCAST(_Float32, left_location); + _Float32 right_value4 = strtof(buffer, NULL); retval = 0; - retval = left_value < right_value ? -1 : retval; - retval = left_value > right_value ? 1 : retval; + retval = left_value4 < right_value4 ? -1 : retval; + retval = left_value4 > right_value4 ? 1 : retval; break; } case 8: { - _Float64 left_value = *(_Float64 *)left_location; - _Float64 right_value = strtod(buffer, NULL); + _Float64 left_value8 = *PTRCAST(_Float64, left_location); + _Float64 right_value8 = strtod(buffer, NULL); retval = 0; - retval = left_value < right_value ? -1 : retval; - retval = left_value > right_value ? 1 : retval; + retval = left_value8 < right_value8 ? -1 : retval; + retval = left_value8 > right_value8 ? 1 : retval; break; } case 16: { //_Float128 left_value = *(_Float128 *)left_location; - GCOB_FP128 left_value; - memcpy(&left_value, left_location, 16); - GCOB_FP128 right_value = strtofp128(buffer, NULL); + GCOB_FP128 left_value16; + memcpy(&left_value16, left_location, 16); + GCOB_FP128 right_value16 = strtofp128(buffer, NULL); retval = 0; - retval = left_value < right_value ? -1 : retval; - retval = left_value > right_value ? 1 : retval; + retval = left_value16 < right_value16 ? -1 : retval; + retval = left_value16 > right_value16 ? 1 : retval; break; } } @@ -4500,10 +4521,10 @@ __gg__compare_2(cblc_field_t *left_side, if( right_refmod ) { - retval = compare_strings( (char *)left_location, + retval = compare_strings( reinterpret_cast<char *>(left_location), left_length, left_all, - (char *)right_location, + reinterpret_cast<char *>(right_location), right_length, right_all); compare = true; @@ -4521,12 +4542,13 @@ __gg__compare_2(cblc_field_t *left_side, // VAL5 EQUAL "005" is TRUE if( left_side->type == FldLiteralA ) { - left_location = (unsigned char *)left_side->data; + left_location = reinterpret_cast<unsigned char *>(left_side->data); left_length = left_side->capacity; } static size_t right_string_size = MINIMUM_ALLOCATION_SIZE; - static char *right_string = (char *)malloc(right_string_size); + static char *right_string + = static_cast<char *>(malloc(right_string_size)); right_string = format_for_display_internal( &right_string, @@ -4550,7 +4572,7 @@ __gg__compare_2(cblc_field_t *left_side, left_length -= 1; } - char *right_fixed; + const char *right_fixed; if( *right_string == internal_plus || *right_string == internal_minus ) { right_fixed = right_string + 1; @@ -4560,7 +4582,7 @@ __gg__compare_2(cblc_field_t *left_side, right_fixed = right_string; } - retval = compare_strings( (char *)left_location, + retval = compare_strings( reinterpret_cast<char *>(left_location), left_length, left_all, right_fixed, @@ -4793,16 +4815,16 @@ sort_contents(unsigned char *contents, extern "C" void -__gg__sort_table( cblc_field_t *table, - size_t table_o, - size_t depending_on, - size_t nkeys, - cblc_field_t **keys, - size_t *ascending, - int duplicates ) +__gg__sort_table( const cblc_field_t *table, + size_t table_o, + size_t depending_on, + size_t nkeys, + cblc_field_t **keys, + size_t *ascending, + int duplicates ) { size_t buffer_size = 128; - unsigned char *contents = (unsigned char *)malloc(buffer_size); + unsigned char *contents = static_cast<unsigned char *>(malloc(buffer_size)); size_t offset = 0; std::vector<size_t>offsets; size_t record_size = table->capacity; @@ -4814,7 +4836,7 @@ __gg__sort_table( cblc_field_t *table, while( offset + sizeof(size_t) + record_size > buffer_size ) { buffer_size *= 2; - contents = (unsigned char *)realloc(contents, buffer_size); + contents = static_cast<unsigned char *>(realloc(contents, buffer_size)); } offsets.push_back(offset); memcpy(contents+offset, &record_size, sizeof(size_t)); @@ -4894,7 +4916,7 @@ init_var_both(cblc_field_t *var, { //fprintf(stderr, "ABORTING on %2.2d %s %d\n", var->level, var->name, var->type); //abort(); - var->data = (unsigned char *)malloc(var->capacity); + var->data = static_cast<unsigned char *>(malloc(var->capacity)); } // Set the "initialized" bit, which is tested in parser_symbol_add to make @@ -4920,11 +4942,11 @@ init_var_both(cblc_field_t *var, // We need to convert the options to the internal native codeset size_t buffer_size = 4; - char *buffer = (char *)malloc(buffer_size); + char *buffer = static_cast<char *>(malloc(buffer_size)); size_t index = 0; - cblc_field_t *parent = var->parent; + const cblc_field_t *parent = var->parent; switch(parent->type) { case FldGroup: @@ -4934,9 +4956,9 @@ init_var_both(cblc_field_t *var, while(*walker) { static size_t first_size = MINIMUM_ALLOCATION_SIZE; - static char *first = (char *)malloc(first_size); + static char *first = static_cast<char *>(malloc(first_size)); static size_t last_size = MINIMUM_ALLOCATION_SIZE; - static char *last = (char *)malloc(last_size); + static char *last = static_cast<char *>(malloc(last_size)); if( (*walker & 0xFF) == 0xFF ) { strcpy(first, walker); @@ -4959,7 +4981,7 @@ init_var_both(cblc_field_t *var, while(index + strlen(first) + strlen(last) + 3 > buffer_size) { buffer_size *= 2; - buffer = (char *)realloc(buffer, buffer_size); + buffer = static_cast<char *>(realloc(buffer, buffer_size)); } strcpy(buffer+index, first); index += strlen(first) + 1; @@ -4972,7 +4994,7 @@ init_var_both(cblc_field_t *var, } if( index > 0 ) { - buffer = (char *)realloc(buffer, index); + buffer = static_cast<char *>(realloc(buffer, index)); local_initial = buffer; } } @@ -5012,7 +5034,7 @@ init_var_both(cblc_field_t *var, // memory to the default. But if a parent has been initialized, we must not // touch our memory: bool a_parent_initialized = false; - if( var->data && !explicitly ) + if( !explicitly ) { while(parent) { @@ -5228,7 +5250,7 @@ init_var_both(cblc_field_t *var, __gg__abort("Unknown variable type"); } - char *location = (char *)save_the_location; + char *location = reinterpret_cast<char *>(save_the_location); there_is_more = false; size_t i=0; @@ -5254,7 +5276,7 @@ init_var_both(cblc_field_t *var, } } - outer_location = (unsigned char *)location; + outer_location = reinterpret_cast<unsigned char *>(location); } while(there_is_more); var->data = save_the_location; @@ -5301,7 +5323,7 @@ alpha_to_alpha_move_from_location(cblc_field_t *field, // and dest are alphanumeric dest_length = dest_length ? dest_length : field->capacity; - char *to = (char *)field->data + dest_offset; + char *to = reinterpret_cast<char *>(field->data + dest_offset); const char *from = source_location; size_t count = std::min(dest_length, source_length); @@ -5397,7 +5419,7 @@ static void alpha_to_alpha_move(cblc_field_t *dest, size_t dest_offset, size_t dest_size, - cblc_field_t *source, + const cblc_field_t *source, size_t source_offset, size_t source_size, bool source_move_all) @@ -5405,7 +5427,7 @@ alpha_to_alpha_move(cblc_field_t *dest, alpha_to_alpha_move_from_location( dest, dest_offset, dest_size, - (char *)(source->data + source_offset), + reinterpret_cast<char *>(source->data + source_offset), source_size, source_move_all); } @@ -5439,13 +5461,9 @@ __gg__move( cblc_field_t *fdest, { int size_error = 0; // This is the return value - bool moved = true; - __int128 value; int rdigits; - size_t min_length; - cbl_figconst_t source_figconst = (cbl_figconst_t)(fsource->attr & FIGCONST_MASK); cbl_field_type_t dest_type = (cbl_field_type_t)fdest->type; @@ -5489,7 +5507,7 @@ __gg__move( cblc_field_t *fdest, * standard COBOL and its use should be avoided */ - int special_char; + int special_char = 0; // quiets cppcheck if( source_figconst == low_value_e ) { special_char = ascii_to_internal(__gg__low_value_character); @@ -5512,6 +5530,8 @@ __gg__move( cblc_field_t *fdest, } else { + size_t min_length; + bool moved = true; switch( dest_type ) { case FldGroup: @@ -5592,9 +5612,6 @@ __gg__move( cblc_field_t *fdest, // alphanumeric. We ignore any sign bit, and just // move the characters: - int rdigits; - __int128 value; - size_t source_digits = fsource->digits + ( fsource->rdigits < 0 @@ -5760,7 +5777,7 @@ __gg__move( cblc_field_t *fdest, fsource, source_offset, source_size); - sprintf(ach, "%lu", (size_t)value); + sprintf(ach, "%lu", (unsigned long)value); char *pach = ach; @@ -5884,31 +5901,31 @@ __gg__move( cblc_field_t *fdest, { rdigits = get_scaled_rdigits(fdest); bool negative = false; - __int128 value=0; + __int128 value128 = 0; switch(fsource->capacity) { case 4: { - _Float32 val = *(_Float32 *)(fsource->data+source_offset); + _Float32 val = *PTRCAST(_Float32, fsource->data+source_offset); if(val < 0) { negative = true; val = -val; } - val *= (_Float32)__gg__power_of_ten(rdigits); - value = (__int128)val; + val *= static_cast<_Float32>(__gg__power_of_ten(rdigits)); + value128 = (__int128)val; break; } case 8: { - _Float64 val = *(_Float64 *)(fsource->data+source_offset); + _Float64 val = *PTRCAST(_Float64, fsource->data+source_offset); if(val < 0) { negative = true; val = -val; } val *= (_Float32)__gg__power_of_ten(rdigits); - value = (__int128)val; + value128 = (__int128)val; break; } case 16: @@ -5922,19 +5939,19 @@ __gg__move( cblc_field_t *fdest, val = -val; } val *= (_Float32)__gg__power_of_ten(rdigits); - value = (__int128)val; + value128 = (__int128)val; break; } } if( negative ) { - value = -value; + value128 = -value128; } __gg__int128_to_qualified_field( fdest, dest_offset, dest_size, - value, + value128, rdigits, rounded, &size_error ); @@ -6002,30 +6019,30 @@ __gg__move( cblc_field_t *fdest, // We are converted a floating-point value fixed-point rdigits = get_scaled_rdigits(fdest); - GCOB_FP128 value=0; + GCOB_FP128 fp128=0; switch(fsource->capacity) { case 4: { - value = *(_Float32 *)(fsource->data+source_offset); + fp128 = *reinterpret_cast<_Float32 *>(fsource->data+source_offset); break; } case 8: { - value = *(_Float64 *)(fsource->data+source_offset); + fp128 = *reinterpret_cast<_Float64 *>(fsource->data+source_offset); break; } case 16: { // value = *(_Float128 *)(fsource->data+source_offset); - memcpy(&value, fsource->data+source_offset, 16); + memcpy(&fp128, fsource->data+source_offset, 16); break; } } __gg__float128_to_qualified_field( fdest, dest_offset, - value, + fp128, rounded, &size_error); break; @@ -6056,9 +6073,6 @@ __gg__move( cblc_field_t *fdest, case FldNumericDisplay: { - int rdigits; - __int128 value; - int source_digits = fsource->digits + (fsource->rdigits<0 ? -fsource->rdigits : 0) ; // Pick up the absolute value of the source @@ -6079,7 +6093,7 @@ __gg__move( cblc_field_t *fdest, } // And move them into place: - __gg__string_to_alpha_edited( (char *)(fdest->data+dest_offset), + __gg__string_to_alpha_edited( reinterpret_cast<char *>(fdest->data+dest_offset), ach, source_digits, fdest->picture); @@ -6089,7 +6103,7 @@ __gg__move( cblc_field_t *fdest, default: { static size_t display_string_size = MINIMUM_ALLOCATION_SIZE; - static char *display_string = (char *)malloc(display_string_size); + static char *display_string = static_cast<char *>(malloc(display_string_size)); size_t display_string_length = dest_size; __gg__realloc_if_necessary( &display_string, @@ -6122,12 +6136,12 @@ __gg__move( cblc_field_t *fdest, &display_string, &display_string_size, fsource, - (unsigned char *)(fsource->data+source_offset), + reinterpret_cast<unsigned char *>(fsource->data+source_offset), source_size, source_flags && REFER_T_ADDRESS_OF); display_string_length = strlen(display_string); } - __gg__string_to_alpha_edited( (char *)(fdest->data+dest_offset), + __gg__string_to_alpha_edited( reinterpret_cast<char *>(fdest->data+dest_offset), display_string, display_string_length, fdest->picture); @@ -6152,12 +6166,12 @@ __gg__move( cblc_field_t *fdest, { case 4: { - *(float *)(fdest->data+dest_offset) = strtof(ach, NULL); + *PTRCAST(float, fdest->data+dest_offset) = strtod(ach, NULL); break; } case 8: { - *(double *)(fdest->data+dest_offset) = strtod(ach, NULL); + *PTRCAST(double, fdest->data+dest_offset) = strtod(ach, NULL); break; } case 16: @@ -6167,7 +6181,6 @@ __gg__move( cblc_field_t *fdest, memcpy(fdest->data+dest_offset, &t, 16); break; } - break; } break; } @@ -6296,7 +6309,7 @@ __gg__move_literala(cblc_field_t *field, case FldAlphaEdited: { static size_t display_string_size = MINIMUM_ALLOCATION_SIZE; - static char *display_string = (char *)malloc(display_string_size); + static char *display_string = static_cast<char *>(malloc(display_string_size)); __gg__realloc_if_necessary( &display_string, &display_string_size, @@ -6305,7 +6318,7 @@ __gg__move_literala(cblc_field_t *field, memset(display_string, internal_space, display_string_size); size_t len = std::min(display_string_size, strlen); memcpy(display_string, str, len); - __gg__string_to_alpha_edited( (char *)(field->data+field_offset), + __gg__string_to_alpha_edited( reinterpret_cast<char *>(field->data+field_offset), display_string, field_size, field->picture); @@ -6322,12 +6335,12 @@ __gg__move_literala(cblc_field_t *field, { case 4: { - *(float *)(field->data+field_offset) = strtof(ach, NULL); + *PTRCAST(float, field->data+field_offset) = strtod(ach, NULL); break; } case 8: { - *(double *)(field->data+field_offset) = strtod(ach, NULL); + *PTRCAST(double, field->data+field_offset) = strtod(ach, NULL); break; } case 16: @@ -6336,7 +6349,6 @@ __gg__move_literala(cblc_field_t *field, memcpy(field->data+field_offset, &t, 16); break; } - break; } break; } @@ -6457,7 +6469,7 @@ __gg__sort_workfile(cblc_file_t *workfile, // Read the file into memory size_t buffer_size = 128; - unsigned char *contents = (unsigned char *)malloc(buffer_size); + unsigned char *contents = static_cast<unsigned char *>(malloc(buffer_size)); size_t offset = 0; std::vector<size_t>offsets; size_t bytes_read; @@ -6487,7 +6499,7 @@ __gg__sort_workfile(cblc_file_t *workfile, while( offset + sizeof(size_t) + bytes_read > buffer_size ) { buffer_size *= 2; - contents = (unsigned char *)realloc(contents, buffer_size); + contents = static_cast<unsigned char *>(realloc(contents, buffer_size)); } offsets.push_back(offset); @@ -6586,7 +6598,8 @@ __gg__merge_files( cblc_file_t *workfile, return; } - unsigned char *prior_winner = (unsigned char *)malloc(the_biggest); + unsigned char *prior_winner = static_cast<unsigned char *>(malloc(the_biggest)); + massert(prior_winner); *prior_winner = '\0'; for(;;) @@ -6766,7 +6779,7 @@ normalize_id( const cblc_field_t *refer, if( refer ) { - unsigned char *data = refer->data + refer_o; + const unsigned char *data = refer->data + refer_o; cbl_figconst_t figconst = (cbl_figconst_t)(refer->attr & FIGCONST_MASK); @@ -7007,7 +7020,7 @@ the_alpha_and_omega_backward( const normalized_operand &id_before, static void -inspect_backward_format_1(size_t integers[]) +inspect_backward_format_1(const size_t integers[]) { size_t int_index = 0; size_t cblc_index = 0; @@ -7020,9 +7033,9 @@ inspect_backward_format_1(size_t integers[]) std::vector<id_2_result> id_2_results(n_identifier_2); // Pick up identifier_1, which is the string being inspected - cblc_field_t *id1 = __gg__treeplet_1f[cblc_index]; - size_t id1_o = __gg__treeplet_1o[cblc_index]; - size_t id1_s = __gg__treeplet_1s[cblc_index]; + const cblc_field_t *id1 = __gg__treeplet_1f[cblc_index]; + size_t id1_o = __gg__treeplet_1o[cblc_index]; + size_t id1_s = __gg__treeplet_1s[cblc_index]; cblc_index += 1; // normalize it, according to the language specification. normalized_operand normalized_id_1 = normalize_id(id1, id1_o, id1_s); @@ -7055,19 +7068,19 @@ inspect_backward_format_1(size_t integers[]) // We are counting characters. There is no identifier-3, // but we we hard-code the length to one to represent a // single character. - comparand next_comparand; + comparand next_comparand = {}; next_comparand.id_2_index = i; next_comparand.operation = operation; next_comparand.identifier_3.length = 1; - cblc_field_t *id4_before = __gg__treeplet_1f [cblc_index]; - size_t id4_before_o = __gg__treeplet_1o[cblc_index]; - size_t id4_before_s = __gg__treeplet_1s[cblc_index]; + const cblc_field_t *id4_before = __gg__treeplet_1f [cblc_index]; + size_t id4_before_o = __gg__treeplet_1o[cblc_index]; + size_t id4_before_s = __gg__treeplet_1s[cblc_index]; cblc_index += 1; - cblc_field_t *id4_after = __gg__treeplet_1f [cblc_index]; - size_t id4_after_o = __gg__treeplet_1o[cblc_index]; - size_t id4_after_s = __gg__treeplet_1s[cblc_index]; + const cblc_field_t *id4_after = __gg__treeplet_1f [cblc_index]; + size_t id4_after_o = __gg__treeplet_1o[cblc_index]; + size_t id4_after_s = __gg__treeplet_1s[cblc_index]; cblc_index += 1; normalized_operand normalized_id_4_before @@ -7099,23 +7112,23 @@ inspect_backward_format_1(size_t integers[]) for(size_t k=0; k<pair_count; k++) { - comparand next_comparand; + comparand next_comparand = {}; next_comparand.id_2_index = i; next_comparand.operation = operation; - cblc_field_t *id3 = __gg__treeplet_1f[cblc_index]; - size_t id3_o = __gg__treeplet_1o[cblc_index]; - size_t id3_s = __gg__treeplet_1s[cblc_index]; + const cblc_field_t *id3 = __gg__treeplet_1f[cblc_index]; + size_t id3_o = __gg__treeplet_1o[cblc_index]; + size_t id3_s = __gg__treeplet_1s[cblc_index]; cblc_index += 1; - cblc_field_t *id4_before = __gg__treeplet_1f[cblc_index]; - size_t id4_before_o = __gg__treeplet_1o[cblc_index]; - size_t id4_before_s = __gg__treeplet_1s[cblc_index]; + const cblc_field_t *id4_before = __gg__treeplet_1f[cblc_index]; + size_t id4_before_o = __gg__treeplet_1o[cblc_index]; + size_t id4_before_s = __gg__treeplet_1s[cblc_index]; cblc_index += 1; - cblc_field_t *id4_after = __gg__treeplet_1f[cblc_index]; - size_t id4_after_o = __gg__treeplet_1o[cblc_index]; - size_t id4_after_s = __gg__treeplet_1s[cblc_index]; + const cblc_field_t *id4_after = __gg__treeplet_1f[cblc_index]; + size_t id4_after_o = __gg__treeplet_1o[cblc_index]; + size_t id4_after_s = __gg__treeplet_1s[cblc_index]; cblc_index += 1; next_comparand.identifier_3 @@ -7356,9 +7369,9 @@ __gg__inspect_format_1(int backward, size_t integers[]) std::vector<id_2_result> id_2_results(n_identifier_2); // Pick up identifier_1, which is the string being inspected - cblc_field_t *id1 = __gg__treeplet_1f[cblc_index]; - size_t id1_o = __gg__treeplet_1o[cblc_index]; - size_t id1_s = __gg__treeplet_1s[cblc_index]; + const cblc_field_t *id1 = __gg__treeplet_1f[cblc_index]; + size_t id1_o = __gg__treeplet_1o[cblc_index]; + size_t id1_s = __gg__treeplet_1s[cblc_index]; cblc_index += 1; // normalize it, according to the language specification. normalized_operand normalized_id_1 @@ -7392,19 +7405,19 @@ __gg__inspect_format_1(int backward, size_t integers[]) // We are counting characters. There is no identifier-3, // but we we hard-code the length to one to represent a // single character. - comparand next_comparand; + comparand next_comparand = {}; next_comparand.id_2_index = i; next_comparand.operation = operation; next_comparand.identifier_3.length = 1; - cblc_field_t *id4_before = __gg__treeplet_1f [cblc_index]; - size_t id4_before_o = __gg__treeplet_1o[cblc_index]; - size_t id4_before_s = __gg__treeplet_1s[cblc_index]; + const cblc_field_t *id4_before = __gg__treeplet_1f [cblc_index]; + size_t id4_before_o = __gg__treeplet_1o[cblc_index]; + size_t id4_before_s = __gg__treeplet_1s[cblc_index]; cblc_index += 1; - cblc_field_t *id4_after = __gg__treeplet_1f [cblc_index]; - size_t id4_after_o = __gg__treeplet_1o[cblc_index]; - size_t id4_after_s = __gg__treeplet_1s[cblc_index]; + const cblc_field_t *id4_after = __gg__treeplet_1f [cblc_index]; + size_t id4_after_o = __gg__treeplet_1o[cblc_index]; + size_t id4_after_s = __gg__treeplet_1s[cblc_index]; cblc_index += 1; normalized_operand normalized_id_4_before @@ -7436,23 +7449,23 @@ __gg__inspect_format_1(int backward, size_t integers[]) for(size_t k=0; k<pair_count; k++) { - comparand next_comparand; + comparand next_comparand = {}; next_comparand.id_2_index = i; next_comparand.operation = operation; - cblc_field_t *id3 = __gg__treeplet_1f[cblc_index]; - size_t id3_o = __gg__treeplet_1o[cblc_index]; - size_t id3_s = __gg__treeplet_1s[cblc_index]; + const cblc_field_t *id3 = __gg__treeplet_1f[cblc_index]; + size_t id3_o = __gg__treeplet_1o[cblc_index]; + size_t id3_s = __gg__treeplet_1s[cblc_index]; cblc_index += 1; - cblc_field_t *id4_before = __gg__treeplet_1f[cblc_index]; - size_t id4_before_o = __gg__treeplet_1o[cblc_index]; - size_t id4_before_s = __gg__treeplet_1s[cblc_index]; + const cblc_field_t *id4_before = __gg__treeplet_1f[cblc_index]; + size_t id4_before_o = __gg__treeplet_1o[cblc_index]; + size_t id4_before_s = __gg__treeplet_1s[cblc_index]; cblc_index += 1; - cblc_field_t *id4_after = __gg__treeplet_1f[cblc_index]; - size_t id4_after_o = __gg__treeplet_1o[cblc_index]; - size_t id4_after_s = __gg__treeplet_1s[cblc_index]; + const cblc_field_t *id4_after = __gg__treeplet_1f[cblc_index]; + size_t id4_after_o = __gg__treeplet_1o[cblc_index]; + size_t id4_after_s = __gg__treeplet_1s[cblc_index]; cblc_index += 1; next_comparand.identifier_3 @@ -7681,7 +7694,7 @@ __gg__inspect_format_1(int backward, size_t integers[]) static void -inspect_backward_format_2(size_t integers[]) +inspect_backward_format_2(const size_t integers[]) { size_t int_index = 0; size_t cblc_index = 0; @@ -7711,22 +7724,22 @@ inspect_backward_format_2(size_t integers[]) { case bound_characters_e: { - comparand next_comparand; + comparand next_comparand = {}; next_comparand.operation = operation; - cblc_field_t *id5 = __gg__treeplet_1f[cblc_index]; - size_t id5_o = __gg__treeplet_1o[cblc_index]; - size_t id5_s = __gg__treeplet_1s[cblc_index]; + const cblc_field_t *id5 = __gg__treeplet_1f[cblc_index]; + size_t id5_o = __gg__treeplet_1o[cblc_index]; + size_t id5_s = __gg__treeplet_1s[cblc_index]; cblc_index += 1; - cblc_field_t *id4_before = __gg__treeplet_1f[cblc_index]; - size_t id4_before_o = __gg__treeplet_1o[cblc_index]; - size_t id4_before_s = __gg__treeplet_1s[cblc_index]; + const cblc_field_t *id4_before = __gg__treeplet_1f[cblc_index]; + size_t id4_before_o = __gg__treeplet_1o[cblc_index]; + size_t id4_before_s = __gg__treeplet_1s[cblc_index]; cblc_index += 1; - cblc_field_t *id4_after = __gg__treeplet_1f [cblc_index]; - size_t id4_after_o = __gg__treeplet_1o[cblc_index]; - size_t id4_after_s = __gg__treeplet_1s[cblc_index]; + const cblc_field_t *id4_after = __gg__treeplet_1f [cblc_index]; + size_t id4_after_o = __gg__treeplet_1o[cblc_index]; + size_t id4_after_s = __gg__treeplet_1s[cblc_index]; cblc_index += 1; next_comparand.identifier_5 @@ -7762,27 +7775,27 @@ inspect_backward_format_2(size_t integers[]) for(size_t k=0; k<pair_count; k++) { - comparand next_comparand; + comparand next_comparand = {}; next_comparand.operation = operation; - cblc_field_t *id3 = __gg__treeplet_1f[cblc_index]; - size_t id3_o = __gg__treeplet_1o[cblc_index]; - size_t id3_s = __gg__treeplet_1s[cblc_index]; + const cblc_field_t *id3 = __gg__treeplet_1f[cblc_index]; + size_t id3_o = __gg__treeplet_1o[cblc_index]; + size_t id3_s = __gg__treeplet_1s[cblc_index]; cblc_index += 1; - cblc_field_t *id5 = __gg__treeplet_1f[cblc_index]; - size_t id5_o = __gg__treeplet_1o[cblc_index]; - size_t id5_s = __gg__treeplet_1s[cblc_index]; + const cblc_field_t *id5 = __gg__treeplet_1f[cblc_index]; + size_t id5_o = __gg__treeplet_1o[cblc_index]; + size_t id5_s = __gg__treeplet_1s[cblc_index]; cblc_index += 1; - cblc_field_t *id4_before = __gg__treeplet_1f[cblc_index]; - size_t id4_before_o = __gg__treeplet_1o[cblc_index]; - size_t id4_before_s = __gg__treeplet_1s[cblc_index]; + const cblc_field_t *id4_before = __gg__treeplet_1f[cblc_index]; + size_t id4_before_o = __gg__treeplet_1o[cblc_index]; + size_t id4_before_s = __gg__treeplet_1s[cblc_index]; cblc_index += 1; - cblc_field_t *id4_after = __gg__treeplet_1f[cblc_index]; - size_t id4_after_o = __gg__treeplet_1o[cblc_index]; - size_t id4_after_s = __gg__treeplet_1s[cblc_index]; + const cblc_field_t *id4_after = __gg__treeplet_1f[cblc_index]; + size_t id4_after_o = __gg__treeplet_1o[cblc_index]; + size_t id4_after_s = __gg__treeplet_1s[cblc_index]; cblc_index += 1; next_comparand.identifier_3 = normalize_id(id3, id3_o, id3_s); @@ -8059,22 +8072,22 @@ __gg__inspect_format_2(int backward, size_t integers[]) { case bound_characters_e: { - comparand next_comparand; + comparand next_comparand = {} ; next_comparand.operation = operation; - cblc_field_t *id5 = __gg__treeplet_1f[cblc_index]; - size_t id5_o = __gg__treeplet_1o[cblc_index]; - size_t id5_s = __gg__treeplet_1s[cblc_index]; + const cblc_field_t *id5 = __gg__treeplet_1f[cblc_index]; + size_t id5_o = __gg__treeplet_1o[cblc_index]; + size_t id5_s = __gg__treeplet_1s[cblc_index]; cblc_index += 1; - cblc_field_t *id4_before = __gg__treeplet_1f[cblc_index]; - size_t id4_before_o = __gg__treeplet_1o[cblc_index]; - size_t id4_before_s = __gg__treeplet_1s[cblc_index]; + const cblc_field_t *id4_before = __gg__treeplet_1f[cblc_index]; + size_t id4_before_o = __gg__treeplet_1o[cblc_index]; + size_t id4_before_s = __gg__treeplet_1s[cblc_index]; cblc_index += 1; - cblc_field_t *id4_after = __gg__treeplet_1f [cblc_index]; - size_t id4_after_o = __gg__treeplet_1o[cblc_index]; - size_t id4_after_s = __gg__treeplet_1s[cblc_index]; + const cblc_field_t *id4_after = __gg__treeplet_1f [cblc_index]; + size_t id4_after_o = __gg__treeplet_1o[cblc_index]; + size_t id4_after_s = __gg__treeplet_1s[cblc_index]; cblc_index += 1; next_comparand.identifier_5 @@ -8110,27 +8123,27 @@ __gg__inspect_format_2(int backward, size_t integers[]) for(size_t k=0; k<pair_count; k++) { - comparand next_comparand; + comparand next_comparand = {}; next_comparand.operation = operation; - cblc_field_t *id3 = __gg__treeplet_1f[cblc_index]; - size_t id3_o = __gg__treeplet_1o[cblc_index]; - size_t id3_s = __gg__treeplet_1s[cblc_index]; + const cblc_field_t *id3 = __gg__treeplet_1f[cblc_index]; + size_t id3_o = __gg__treeplet_1o[cblc_index]; + size_t id3_s = __gg__treeplet_1s[cblc_index]; cblc_index += 1; - cblc_field_t *id5 = __gg__treeplet_1f[cblc_index]; - size_t id5_o = __gg__treeplet_1o[cblc_index]; - size_t id5_s = __gg__treeplet_1s[cblc_index]; + const cblc_field_t *id5 = __gg__treeplet_1f[cblc_index]; + size_t id5_o = __gg__treeplet_1o[cblc_index]; + size_t id5_s = __gg__treeplet_1s[cblc_index]; cblc_index += 1; - cblc_field_t *id4_before = __gg__treeplet_1f[cblc_index]; - size_t id4_before_o = __gg__treeplet_1o[cblc_index]; - size_t id4_before_s = __gg__treeplet_1s[cblc_index]; + const cblc_field_t *id4_before = __gg__treeplet_1f[cblc_index]; + size_t id4_before_o = __gg__treeplet_1o[cblc_index]; + size_t id4_before_s = __gg__treeplet_1s[cblc_index]; cblc_index += 1; - cblc_field_t *id4_after = __gg__treeplet_1f[cblc_index]; - size_t id4_after_o = __gg__treeplet_1o[cblc_index]; - size_t id4_after_s = __gg__treeplet_1s[cblc_index]; + const cblc_field_t *id4_after = __gg__treeplet_1f[cblc_index]; + size_t id4_after_o = __gg__treeplet_1o[cblc_index]; + size_t id4_after_s = __gg__treeplet_1s[cblc_index]; cblc_index += 1; next_comparand.identifier_3 = normalize_id(id3, id3_o, id3_s); @@ -8405,12 +8418,12 @@ __gg__inspect_format_4( int backward, static size_t psz_before_size = MINIMUM_ALLOCATION_SIZE; static size_t psz_figstring_size = MINIMUM_ALLOCATION_SIZE; - static char *psz_input = (char *)malloc(psz_input_size ); - static char *psz_original = (char *)malloc(psz_original_size ); - static char *psz_replacement = (char *)malloc(psz_replacement_size); - static char *psz_after = (char *)malloc(psz_after_size ); - static char *psz_before = (char *)malloc(psz_before_size ); - static char *psz_figstring = (char *)malloc(psz_figstring_size ); + static char *psz_input = static_cast<char *>(malloc(psz_input_size )); + static char *psz_original = static_cast<char *>(malloc(psz_original_size )); + static char *psz_replacement = static_cast<char *>(malloc(psz_replacement_size)); + static char *psz_after = static_cast<char *>(malloc(psz_after_size )); + static char *psz_before = static_cast<char *>(malloc(psz_before_size )); + static char *psz_figstring = static_cast<char *>(malloc(psz_figstring_size )); bool all = replacement_size == (size_t)(-1LL); if( all ) @@ -8504,7 +8517,7 @@ __gg__inspect_format_4( int backward, } char *pstart = NULL; - char *pend = NULL; + const char *pend = NULL; if( backward ) { if( strlen(psz_before) ) @@ -8597,7 +8610,7 @@ move_string(cblc_field_t *field, case FldAlphanumeric: case FldAlphaEdited: { - char *to = (char *)(field->data + offset); + char *to = reinterpret_cast<char *>(field->data + offset); size_t dest_length = length ? length : field->capacity; size_t source_length = strlen_from; size_t count = std::min(dest_length, source_length); @@ -8706,7 +8719,7 @@ brute_force_trim(char *str) extern "C" int -__gg__string(size_t integers[]) +__gg__string(const size_t integers[]) { // The first integer is the count of identifier-2 values. Call it N // The following N integers are the counts of each of the identifier-1 values, @@ -8720,12 +8733,11 @@ __gg__string(size_t integers[]) // And so on cblc_field_t **ref = __gg__treeplet_1f; - size_t *ref_o = __gg__treeplet_1o; - size_t *ref_s = __gg__treeplet_1s; + const size_t *ref_o = __gg__treeplet_1o; + const size_t *ref_s = __gg__treeplet_1s; static const int INDEX_OF_POINTER = 1; - size_t index_int = 0; size_t index_cblc = 0 ; char figlow[2] = {ascii_to_internal(__gg__low_value_character), 0x00}; @@ -8743,15 +8755,13 @@ __gg__string(size_t integers[]) fighigh[0] = ascii_to_internal(__gg__high_value_character); } - // Pick up the number of identifier-2 values - size_t N = integers[index_int++]; // Pick up the target - cblc_field_t *tgt = ref[index_cblc]; - size_t tgt_o = ref_o[index_cblc]; - size_t tgt_s = ref_s[index_cblc]; + const cblc_field_t *tgt = ref[index_cblc]; + size_t tgt_o = ref_o[index_cblc]; + size_t tgt_s = ref_s[index_cblc]; index_cblc += 1; - char *dest = (char *)(tgt->data + tgt_o); + char *dest = reinterpret_cast<char *>(tgt->data + tgt_o); ssize_t dest_length = tgt_s; // Skip over the index of POINTER: @@ -8778,18 +8788,23 @@ __gg__string(size_t integers[]) { // We are go for looping through identifier-2 values: + size_t index_int = 0; + + // Pick up the number of identifier-2 values + size_t N = integers[index_int++]; + for( size_t i=0; i<N; i++ ) { size_t M = integers[index_int++]; // Pick up the identifier_2 DELIMITED BY value - cblc_field_t *id2 = ref[index_cblc]; - size_t id2_o = ref_o[index_cblc]; - size_t id2_s = ref_s[index_cblc]; + const cblc_field_t *id2 = ref[index_cblc]; + size_t id2_o = ref_o[index_cblc]; + size_t id2_s = ref_s[index_cblc]; index_cblc += 1; char *piece; - char *piece_end; + const char *piece_end; cbl_figconst_t figconst = (cbl_figconst_t) ( id2 ? (id2->attr & FIGCONST_MASK) : 0 ); @@ -8816,24 +8831,24 @@ __gg__string(size_t integers[]) piece_end = piece + 1; break; default: - piece = id2 ? (char *)(id2->data + id2_o) : NULL; + piece = id2 ? reinterpret_cast<char *>(id2->data + id2_o) : NULL; piece_end = id2 ? piece + id2_s : NULL; break; } - for(size_t i=0; i<M; i++) + for(size_t j=0; j<M; j++) { // Pick up the next identifier-1 source string: - cblc_field_t *id1 = ref[index_cblc]; + const cblc_field_t *id1 = ref[index_cblc]; size_t id1_o = ref_o[index_cblc]; size_t id1_s = ref_s[index_cblc]; index_cblc += 1; - const char *whole = id1 ? (const char *)(id1->data + id1_o): NULL ; + const char *whole = id1 ? reinterpret_cast<char *>(id1->data + id1_o): NULL ; const char *whole_end = id1 ? whole + id1_s : NULL; // As usual, we need to cope with figurative constants: - cbl_figconst_t figconst = (cbl_figconst_t) ( id1 ? (id1->attr & FIGCONST_MASK) : 0 ); + figconst = (cbl_figconst_t) ( id1 ? (id1->attr & FIGCONST_MASK) : 0 ); switch( figconst ) { case low_value_e: @@ -8866,11 +8881,7 @@ __gg__string(size_t integers[]) whole, whole_end); if(found) { -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-qual" - char *wfound = (char *)found; -#pragma GCC diagnostic pop - whole_end = wfound; + whole_end = found; } } while(whole < whole_end) @@ -8920,7 +8931,7 @@ display_both(cblc_field_t *field, int advance ) { static size_t display_string_size = MINIMUM_ALLOCATION_SIZE; - static char *display_string = (char *)malloc(display_string_size); + static char *display_string = static_cast<char *>(malloc(display_string_size)); format_for_display_internal(&display_string, &display_string_size, @@ -8931,7 +8942,7 @@ display_both(cblc_field_t *field, // Let's honor the locale of the system, as best we can: static size_t converted_size = MINIMUM_ALLOCATION_SIZE; - static char *converted = (char *)malloc(converted_size); + static char *converted = static_cast<char *>(malloc(converted_size)); internal_to_console(&converted, &converted_size, display_string, strlen(display_string)); @@ -8941,7 +8952,7 @@ display_both(cblc_field_t *field, if(ss == -1) { fprintf(stderr, "__gg__display() %s %p\n", field->name, qual_data); - fprintf(stderr, "__gg__display() %zd\n", converted_size); + fprintf(stderr, "__gg__display() %ld\n", static_cast<long>(converted_size)); fprintf(stderr, "__gg__display() "); for(size_t i=0; i<converted_size; i++) { @@ -8953,9 +8964,9 @@ display_both(cblc_field_t *field, if( advance ) { - ss = write( file_descriptor, - "\n", - 1); + write( file_descriptor, + "\n", + 1); } } @@ -8994,20 +9005,20 @@ __gg__display_clean(cblc_field_t *field, extern "C" void -__gg__display_string( int file_descriptor, - char *str, - size_t length, - int advance ) +__gg__display_string( int file_descriptor, + const char *str, + size_t length, + int advance ) { // Let's honor the locale of the system, as best we can: static size_t converted_size = MINIMUM_ALLOCATION_SIZE; - static char *converted = (char *)malloc(converted_size); + static char *converted = static_cast<char *>(malloc(converted_size)); size_t max_possible = 2 * length; if( max_possible > converted_size ) { converted_size = max_possible; - converted = (char *)realloc(converted, converted_size); + converted = static_cast<char *>(realloc(converted, converted_size)); } __gg__ascii_to_console(&converted, &converted_size, str, length); @@ -9143,7 +9154,8 @@ __gg__accept( enum special_name_t special_e, } } - char *buffer = (char *)malloc(max_chars+1); + char *buffer = static_cast<char *>(malloc(max_chars+1)); + massert(buffer); memset(buffer, ascii_space, max_chars); buffer[max_chars] = NULLCH; size_t i = 0; @@ -9309,7 +9321,7 @@ __gg__binary_value_from_field( int *rdigits, extern "C" __int128 __gg__binary_value_from_qualified_field(int *rdigits, - cblc_field_t *var, + const cblc_field_t *var, size_t offset, size_t size) { @@ -9342,7 +9354,7 @@ __gg__float128_from_field( cblc_field_t *field ) extern "C" GCOB_FP128 -__gg__float128_from_qualified_field( cblc_field_t *field, size_t offset, size_t size) +__gg__float128_from_qualified_field(const cblc_field_t *field, size_t offset, size_t size) { GCOB_FP128 retval=0; if( field->type == FldFloat || field->type == FldLiteralN ) @@ -9419,11 +9431,11 @@ __gg__int128_to_qualified_field(cblc_field_t *tgt, } static __int128 -float128_to_int128( int *rdigits, - cblc_field_t *field, - GCOB_FP128 value, - cbl_round_t rounded, - int *compute_error) +float128_to_int128( int *rdigits, + const cblc_field_t *field, + GCOB_FP128 value, + cbl_round_t rounded, + int *compute_error) { __int128 retval = 0; if( value == INFINITY ) @@ -9505,16 +9517,16 @@ float128_to_location( cblc_field_t *tgt, } if( value < 0 ) { - *(float *)(data) = -INFINITY; + *PTRCAST(float, data) = -INFINITY; } else { - *(float *)(data) = INFINITY; + *PTRCAST(float, data) = INFINITY; } } else { - *(float *)(data) = (float)value; + *PTRCAST(float, data) = static_cast<float>(value); } break; @@ -9528,16 +9540,16 @@ float128_to_location( cblc_field_t *tgt, } if( value < 0 ) { - *(double *)(data) = -INFINITY; + *PTRCAST(double, data) = -INFINITY; } else { - *(double *)(data) = INFINITY; + *PTRCAST(double, data) = INFINITY; } } else { - *(double *)(data) = (double)value; + *PTRCAST(double, data) = static_cast<double>(value); } break; @@ -9738,7 +9750,7 @@ __gg__set_initial_switch_value( ) __int128 bit = 1; char ach[129]; memset(ach, 0, sizeof(ach)); - char *p = getenv("UPSI"); + const char *p = getenv("UPSI"); if( p ) { snprintf(ach, sizeof(ach), "%s", p); @@ -9771,7 +9783,7 @@ is_numeric_display_numeric(cblc_field_t *field, size_t offset, size_t size) bool leading = !!(field->attr & leading_e); bool separate = !!(field->attr & separate_e); - char *digits = (char *)(field->data + offset); + char *digits = reinterpret_cast<char *>(field->data + offset); char *digits_e = digits + size; if( leading && separate && signable ) @@ -9843,13 +9855,13 @@ is_numeric_display_numeric(cblc_field_t *field, size_t offset, size_t size) } static int -is_packed_numeric(cblc_field_t *field, size_t offset, size_t size) +is_packed_numeric(const cblc_field_t *field, size_t offset, size_t size) { int retval = 1; bool is_comp6 = !!(field->attr&packed_no_sign_e); int digits = field->digits; bool signable = !!(field->attr & signable_e); - unsigned char *bytes = field->data + offset; + const unsigned char *bytes = field->data + offset; int nybble = 0; int nybble_e = nybble + digits; @@ -9918,10 +9930,12 @@ is_packed_numeric(cblc_field_t *field, size_t offset, size_t size) } static int -is_alpha_a_number(cblc_field_t *field, size_t offset, size_t size) +is_alpha_a_number(const cblc_field_t *field, + size_t offset, + size_t size) { int retval = 1; - unsigned char *bytes = (field->data + offset); + const unsigned char *bytes = (field->data + offset); for( size_t i=0; i<size; i++ ) { unsigned char ch = bytes[i]; @@ -9945,7 +9959,7 @@ __gg__classify( classify_t type, // The default answer is TRUE int retval = 1; - const unsigned char *alpha = (unsigned char *)(field->data+offset); + const unsigned char *alpha = reinterpret_cast<unsigned char *>(field->data+offset); size_t str_length = size; @@ -10095,7 +10109,7 @@ __gg__accept_envar( cblc_field_t *tgt, if( env_length < name_length+1 ) { env_length = name_length+1; - env = (char *)realloc(env, env_length); + env = static_cast<char *>(realloc(env, env_length)); } memcpy(env, name->data + name_offset, name_length); env[name_length] = '\0'; @@ -10107,7 +10121,7 @@ __gg__accept_envar( cblc_field_t *tgt, __gg__internal_to_console_in_place(trimmed_env, strlen(trimmed_env)); // Pick up the environment variable, and convert it to the internal codeset - char *p = getenv(trimmed_env); + const char *p = getenv(trimmed_env); if(p) { char *pp = strdup(p); @@ -10146,14 +10160,17 @@ __gg__set_envar(cblc_field_t *name, if( env_length < name_length+1 ) { env_length = name_length+1; - env = (char *)realloc(env, env_length); + env = static_cast<char *>(realloc(env, env_length)); } if( val_length < value_length+1 ) { val_length = value_length+1; - val = (char *)realloc(val, val_length); + val = static_cast<char *>(realloc(val, val_length)); } + massert(val); + massert(env); + // The name and the value arrive in the internal codeset: memcpy(env, name->data+name_offset , name_length); env[name_length] = '\0'; @@ -10222,15 +10239,15 @@ command_line_plan_b() if( bytes_read ) { char *p = input; - char *p_end = p + bytes_read; + const char *p_end = p + bytes_read; char prior_char = '\0'; while( p < p_end ) { if( prior_char == '\0' ) { stashed_argc += 1; - stashed_argv = (char **)realloc(stashed_argv, - stashed_argc * sizeof(char *)); + stashed_argv = static_cast<char **>(realloc(stashed_argv, + stashed_argc * sizeof(char *))); stashed_argv[stashed_argc-1] = p; } prior_char = *p++; @@ -10301,7 +10318,8 @@ __gg__get_command_line( cblc_field_t *field, int retcode; command_line_plan_b(); size_t length = 1; - char *retval = (char *)malloc(length); + char *retval = static_cast<char *>(malloc(length)); + massert(retval); *retval = NULLCH; for( int i=1; i<stashed_argc; i++ ) @@ -10309,7 +10327,8 @@ __gg__get_command_line( cblc_field_t *field, while( strlen(retval) + strlen(stashed_argv[i]) + 2 > length ) { length *= 2; - retval = (char *)realloc(retval, length); + retval = static_cast<char *>(realloc(retval, length)); + massert(retval); } if( *retval ) { @@ -10337,12 +10356,12 @@ __gg__get_command_line( cblc_field_t *field, extern "C" void -__gg__set_pointer(cblc_field_t *target, - size_t target_o, - int target_flags, - cblc_field_t *source, - size_t source_o, - int source_flags) +__gg__set_pointer(cblc_field_t *target, + size_t target_o, + int target_flags, + const cblc_field_t *source, + size_t source_o, + int source_flags) { void *source_address; if( source_flags & REFER_T_ADDRESS_OF ) @@ -10355,7 +10374,7 @@ __gg__set_pointer(cblc_field_t *target, // This is SET <something> TO POINTER if( source ) { - source_address = *(void **)(source->data + source_o); + source_address = *reinterpret_cast<void **>(source->data + source_o); } else { @@ -10368,7 +10387,7 @@ __gg__set_pointer(cblc_field_t *target, { // This is SET ADDRESS OF target TO .... // We know it has to be an unqualified LINKAGE level 01 or level 77 - target->data = (unsigned char *)source_address; + target->data = reinterpret_cast<unsigned char *>(source_address); // The caller will propogate data + offset to their children. } else @@ -10379,12 +10398,12 @@ __gg__set_pointer(cblc_field_t *target, // This is [almost certainly] INITIALIZE <pointer> when -fdefaultbyte // was specified. memset( target->data+target_o, - *(unsigned char *)source_address, + *reinterpret_cast<unsigned char *>(source_address), target->capacity); } else { - *(void **)(target->data+target_o) = source_address; + *reinterpret_cast<void **>(target->data+target_o) = source_address; } } } @@ -10467,7 +10486,7 @@ extern "C" void __gg__ascii_to_internal_field(cblc_field_t *var) { - ascii_to_internal_str((char *)var->data, var->capacity); + ascii_to_internal_str(reinterpret_cast<char *>(var->data), var->capacity); } extern "C" @@ -10519,7 +10538,7 @@ void __gg__internal_to_console_in_place(char *loc, size_t length) { static size_t dest_size = MINIMUM_ALLOCATION_SIZE; - static char *dest = (char *)malloc(dest_size); + static char *dest = static_cast<char *>(malloc(dest_size)); internal_to_console(&dest, &dest_size, loc, length); memcpy(loc, dest, length); @@ -10527,8 +10546,8 @@ __gg__internal_to_console_in_place(char *loc, size_t length) extern "C" int -__gg__routine_to_call(char *name, - int program_id) +__gg__routine_to_call(const char *name, + int program_id) { // The list of names is sorted, so at the very least this should be replaced // with a binary search: @@ -10544,10 +10563,10 @@ __gg__routine_to_call(char *name, char **names = *(it->second); int retval = -1; - int i=0; if( names ) { + int i=0; while(*names) { if( strstr(*names, name) ) @@ -10569,14 +10588,14 @@ __gg__routine_to_call(char *name, extern "C" __int128 -__gg__fetch_call_by_value_value(cblc_field_t *field, +__gg__fetch_call_by_value_value(const cblc_field_t *field, size_t field_o, size_t field_s) { int rdigits; - unsigned char *data = field->data + field_o; - size_t length = field_s; + unsigned char *data = field->data + field_o; + const size_t length = field_s; __int128 retval = 0; switch(field->type) @@ -10585,7 +10604,7 @@ __gg__fetch_call_by_value_value(cblc_field_t *field, case FldAlphanumeric: case FldAlphaEdited: case FldLiteralA: - retval = *(char *)data; + retval = *reinterpret_cast<char *>(data); break; case FldFloat: @@ -10593,11 +10612,11 @@ __gg__fetch_call_by_value_value(cblc_field_t *field, switch(length) { case 4: - *(float *)(&retval) = *(float *)data; + *PTRCAST(float, &retval) = *PTRCAST(float, data); break; case 8: - *(double *)(&retval) = *(double *)data; + *PTRCAST(double, &retval) = *PTRCAST(double, data); break; case 16: @@ -10654,11 +10673,11 @@ __gg__assign_value_from_stack(cblc_field_t *dest, __int128 parameter) switch(dest->capacity) { case 4: - *(float *)(dest->data) = *(float *)¶meter; + *PTRCAST(float, dest->data) = *PTRCAST(float, (¶meter)); break; case 8: - *(double *)(dest->data) = *(double *)¶meter; + *PTRCAST(double, dest->data) = *PTRCAST(double, (¶meter)); break; case 16: @@ -10692,28 +10711,31 @@ __gg__assign_value_from_stack(cblc_field_t *dest, __int128 parameter) extern "C" int -__gg__literaln_alpha_compare(char *left_side, - cblc_field_t *right, - size_t offset, - size_t length, - int flags) +__gg__literaln_alpha_compare(const char *left_side, + const cblc_field_t *right, + size_t offset, + size_t length, + int flags) { int retval; if( length == 0 ) { length = right->capacity; } - retval = compare_strings( (char *)left_side, + retval = compare_strings( left_side, strlen(left_side), false, - (char *)right->data + offset, + reinterpret_cast<char *>((right->data + offset)), length, !!(flags & REFER_T_MOVE_ALL) ); return retval; } static char * -string_in(char *str, char *str_e, char *frag, char *frag_e) +string_in( char *str, + const char *str_e, + const char *frag, + const char *frag_e) { // This simple routine could be improved. Instead of using memcmp, we could // use established, albeit complex, techniques of string searching: @@ -10743,11 +10765,11 @@ string_in(char *str, char *str_e, char *frag, char *frag_e) extern "C" int -__gg__unstring( cblc_field_t *id1, // The string being unstring - size_t id1_o, - size_t id1_s, +__gg__unstring( const cblc_field_t *id1, // The string being unstring + size_t id1_o, + size_t id1_s, size_t ndelimiteds, // The number of DELIMITED entries - char *all_flags, // The number of ALL flags, one per ndelimiteds + const char *all_flags, // The number of ALL flags, one per ndelimiteds size_t nreceivers, // The number of DELIMITER receivers cblc_field_t *id7, // The index of characters, both for starting updated at end size_t id7_o, @@ -10766,18 +10788,22 @@ __gg__unstring( cblc_field_t *id1, // The string being unstring // resolved. Each might have an identifier-5 delimiter, and each might have // an identifier-6 count. - cblc_field_t **id2 = __gg__treeplet_1f; // The delimiting strings; one per ndelimiteds - size_t *id2_o = __gg__treeplet_1o; - size_t *id2_s = __gg__treeplet_1s; - cblc_field_t **id4 = __gg__treeplet_2f; // The delimited string; one per nreceiver - size_t *id4_o = __gg__treeplet_2o; - size_t *id4_s = __gg__treeplet_2s; - cblc_field_t **id5 = __gg__treeplet_3f; // The delimiting string; one per receiver - size_t *id5_o = __gg__treeplet_3o; - size_t *id5_s = __gg__treeplet_3s; - cblc_field_t **id6 = __gg__treeplet_4f; // The count of characters examined; one per receiver - size_t *id6_o = __gg__treeplet_4o; - size_t *id6_s = __gg__treeplet_4s; + // The delimiting strings; one per ndelimiteds + cblc_field_t **id2 = __gg__treeplet_1f; + const size_t *id2_o = __gg__treeplet_1o; + const size_t *id2_s = __gg__treeplet_1s; + // The delimited string; one per nreceiver + cblc_field_t **id4 = __gg__treeplet_2f; + const size_t *id4_o = __gg__treeplet_2o; + const size_t *id4_s = __gg__treeplet_2s; + // The delimiting string; one per receiver + cblc_field_t **id5 = __gg__treeplet_3f; + const size_t *id5_o = __gg__treeplet_3o; + const size_t *id5_s = __gg__treeplet_3s; + // The count of characters examined; one per receiver + cblc_field_t **id6 = __gg__treeplet_4f; + const size_t *id6_o = __gg__treeplet_4o; + const size_t *id6_s = __gg__treeplet_4s; // Initialize the state variables int overflow = 0; @@ -10820,8 +10846,8 @@ __gg__unstring( cblc_field_t *id1, // The string being unstring goto done; } - left = (char *)(id1->data+id1_o) + pointer-1; - right = (char *)(id1->data+id1_o) + id1_s; + left = reinterpret_cast<char *>(id1->data+id1_o) + pointer-1; + right = reinterpret_cast<char *>(id1->data+id1_o) + id1_s; if( ndelimiteds == 0 ) { @@ -10919,8 +10945,9 @@ __gg__unstring( cblc_field_t *id1, // The string being unstring default: pfound = string_in( left, right, - (char *)(id2[i]->data+id2_o[i]), - (char *)(id2[i]->data+id2_o[i]) + id2_s[i]); + reinterpret_cast<char *>(id2[i]->data+id2_o[i]), + reinterpret_cast<char *>((id2[i]->data+id2_o[i]) + + id2_s[i])); break; } @@ -10997,7 +11024,7 @@ __gg__unstring( cblc_field_t *id1, // The string being unstring else { move_string(id5[nreceiver], id5_o[nreceiver], id5_s[nreceiver], - (char *)(id2[ifound]->data+id2_o[ifound]), + reinterpret_cast<char *>(id2[ifound]->data+id2_o[ifound]), id2_s[ifound]); } } @@ -11092,15 +11119,15 @@ static inline ec_type_t local_ec_type_of( file_status_t status ) { int status10 = (int)status / 10; - assert( 0 <= status10 ); // was enum, can't be negative. - if( 10 < status10 ) + assert( 0 <= status10 ); // was enum, can't be negative. + if( 10 < status10 ) { __gg__abort("local_ec_type_of(): status10 out of range"); } - + static const std::vector<ec_type_t> ec_by_status { /* 0 */ ec_none_e, // ec_io_warning_e if low byte is nonzero - /* 1 */ ec_io_at_end_e, + /* 1 */ ec_io_at_end_e, /* 2 */ ec_io_invalid_key_e, /* 3 */ ec_io_permanent_error_e, /* 4 */ ec_io_logic_error_e, @@ -11122,11 +11149,12 @@ local_ec_type_of( file_status_t status ) */ struct exception_descr_t { bool location; - std::set<size_t> files; + //std::set<size_t> files; }; struct cbl_exception_t { - size_t program, file; +// size_t program, + size_t file; ec_type_t type; cbl_file_mode_t mode; }; @@ -11188,16 +11216,16 @@ default_exception_handler( ec_type_t ec ) { #if HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME /* Declared in errno.h, when available. */ - const char *ident = program_invocation_short_name; + static const char * const ident = program_invocation_short_name; #elif defined (HAVE_GETPROGNAME) /* Declared in stdlib.h. */ - const char *ident = getprogname(); + static const char * const ident = getprogname(); #else /* Avoid a NULL entry. */ - const char *ident = "unnamed_COBOL_program"; + static const char * const ident = "unnamed_COBOL_program"; #endif static bool first_time = true; - static int priority = LOG_INFO, option = LOG_PERROR, facility = LOG_USER; + static const int priority = LOG_INFO, option = LOG_PERROR, facility = LOG_USER; ec_disposition_t disposition = ec_category_fatal_e; if( first_time ) { @@ -11450,7 +11478,7 @@ cbl_enabled_exception_t::dump( int i ) const { * specific EC. It's matched based on the file's status, irrespective of * whether or not EC-I-O is enabled. USE Format 1 Declaratives are honored * regardless of any >>TURN directive. - * + * * An EC is enabled by the >>TURN directive. The only ECs that can be disabled * are those that were explicitly enabled. If EC-I-O is enabled, and mentioned * in a Declarative with USE Format 3, then it is matched just like any other. @@ -11465,19 +11493,19 @@ __gg__match_exception( cblc_field_t *index ) auto ec = ec_status.update().unhandled(); - if( ec != ec_none_e ) { + if( ec != ec_none_e ) { /* - * An EC was raised and was not handled by the statement. - * We know the EC and, for I/O, the current file and its mode. - * Scan declaratives for a match: + * An EC was raised and was not handled by the statement. + * We know the EC and, for I/O, the current file and its mode. + * Scan declaratives for a match: * - EC is enabled or program has a Format 1 Declarative * - EC matches the Declarative's USE statement - * Format 1 declaratives apply only to EC-I-O, whether or not enabled. + * Format 1 declaratives apply only to EC-I-O, whether or not enabled. * Format 1 may be restricted to a particular mode (for all files). - * Format 1 and 3 may be restricted to a set of files. + * Format 1 and 3 may be restricted to a set of files. */ auto f = ec_status.file_status(); - cbl_exception_t raised = { 0, f.ifile, ec, f.mode }; + cbl_exception_t raised = { /*0,*/ f.ifile, ec, f.mode }; bool enabled = enabled_ECs.match(ec); if( MATCH_DECLARATIVE ) enabled_ECs.dump("match_exception enabled"); @@ -11506,8 +11534,8 @@ __gg__match_exception( cblc_field_t *index ) p->section); } } - assert(ec != ec_none_e); - } // end EC match logic + assert(ec != ec_none_e); + } // end EC match logic // If a declarative matches the raised exception, return its // symbol_table index. @@ -11581,20 +11609,23 @@ __gg__pseudo_return_flush() extern "C" GCOB_FP128 -__gg__float128_from_location(cblc_field_t *var, unsigned char *location) +__gg__float128_from_location( const cblc_field_t *var, + const unsigned char *location) { GCOB_FP128 retval = 0; switch( var->capacity ) { case 4: { - retval = *(_Float32 *)location; + retval = *reinterpret_cast<_Float32 *>( + const_cast<unsigned char *>(location)); break; } case 8: { - retval = *(_Float64 *)location; + retval = *reinterpret_cast<_Float64 *>( + const_cast<unsigned char *>(location)); break; } @@ -11610,7 +11641,7 @@ __gg__float128_from_location(cblc_field_t *var, unsigned char *location) extern "C" __int128 -__gg__integer_from_float128(cblc_field_t *field) +__gg__integer_from_float128(const cblc_field_t *field) { GCOB_FP128 fvalue = __gg__float128_from_location(field, field->data); // we round() to take care of the possible 2.99999999999... problem. @@ -11729,7 +11760,7 @@ __gg__func_exception_status(cblc_field_t *dest) extern "C" void -__gg__set_exception_file(cblc_file_t *file) +__gg__set_exception_file(const cblc_file_t *file) { ec_type_t ec = local_ec_type_of( file->io_status ); if( ec ) @@ -11748,7 +11779,8 @@ __gg__set_exception_file(cblc_file_t *file) extern "C" void -__gg__func_exception_file(cblc_field_t *dest, cblc_file_t *file) +__gg__func_exception_file(cblc_field_t *dest, + const cblc_file_t *file) { char ach[128]; if( !file ) @@ -11833,7 +11865,7 @@ __gg__set_exception_code(ec_type_t ec, int from_raise_statement) last_exception_statement = __gg__exception_statement ; // These are set in __gg__set_exception_file just before this routine is - // called. In cases where the ec is not a file-i-o operation, we clear + // called. In cases where the ec is not a file-i-o operation, we clear // them here: if( !(ec & ec_io_e) ) { @@ -11932,16 +11964,16 @@ __gg__float128_from_int128(cblc_field_t *destination, extern "C" int -__gg__is_float_infinite(cblc_field_t *source, size_t offset) +__gg__is_float_infinite(const cblc_field_t *source, size_t offset) { int retval = 0; switch(source->capacity) { case 4: - retval = fpclassify( *(_Float32*)(source->data+offset)) == FP_INFINITE; + retval = fpclassify( *reinterpret_cast<_Float32*>(source->data+offset)) == FP_INFINITE; break; case 8: - retval = fpclassify( *(_Float64*)(source->data+offset)) == FP_INFINITE; + retval = fpclassify( *reinterpret_cast<_Float64*>(source->data+offset)) == FP_INFINITE; break; case 16: // retval = *(_Float128*)(source->data+offset) == INFINITY; @@ -11955,10 +11987,10 @@ __gg__is_float_infinite(cblc_field_t *source, size_t offset) extern "C" int -__gg__float32_from_128( cblc_field_t *dest, - size_t dest_offset, - cblc_field_t *source, - size_t source_offset) +__gg__float32_from_128( const cblc_field_t *dest, + size_t dest_offset, + const cblc_field_t *source, + size_t source_offset) { int retval = 0; //_Float128 value = *(_Float128*)(source->data+source_offset); @@ -11970,37 +12002,37 @@ __gg__float32_from_128( cblc_field_t *dest, } else { - *(_Float32 *)(dest->data+dest_offset) = (_Float32)value; + *reinterpret_cast<_Float32 *>(dest->data+dest_offset) = (_Float32)value; } return retval; } extern "C" int -__gg__float32_from_64( cblc_field_t *dest, - size_t dest_offset, - cblc_field_t *source, - size_t source_offset) +__gg__float32_from_64( const cblc_field_t *dest, + size_t dest_offset, + const cblc_field_t *source, + size_t source_offset) { int retval = 0; - _Float64 value = *(_Float64*)(source->data+source_offset); + _Float64 value = *reinterpret_cast<_Float64*>(source->data+source_offset); if( FP128_FUNC(fabs)(value) > GCOB_FP128_LITERAL (3.4028235E38) ) { retval = 1; } else { - *(_Float32 *)(dest->data+dest_offset) = (_Float32)value; + *reinterpret_cast<_Float32 *>(dest->data+dest_offset) = (_Float32)value; } return retval; } extern "C" int -__gg__float64_from_128( cblc_field_t *dest, - size_t dest_offset, - cblc_field_t *source, - size_t source_offset) +__gg__float64_from_128( const cblc_field_t *dest, + size_t dest_offset, + const cblc_field_t *source, + size_t source_offset) { int retval = 0; // _Float128 value = *(_Float128*)(source->data+source_offset); @@ -12012,7 +12044,7 @@ __gg__float64_from_128( cblc_field_t *dest, } else { - *(_Float64 *)(dest->data+dest_offset) = (_Float64)value; + *reinterpret_cast<_Float64 *>(dest->data+dest_offset) = (_Float64)value; } return retval; } @@ -12084,7 +12116,8 @@ __gg__pop_local_variables() extern "C" void -__gg__copy_as_big_endian(unsigned char *dest, unsigned char *source) +__gg__copy_as_big_endian( unsigned char *dest, + const unsigned char *source) { // copy eight bytes of source to dest, flipping the endianness for(size_t i=0; i<8; i++) @@ -12107,7 +12140,7 @@ __gg__codeset_figurative_constants() extern "C" unsigned char * -__gg__get_figconst_data(cblc_field_t *field) +__gg__get_figconst_data(const cblc_field_t *field) { unsigned char *retval = NULL; cbl_figconst_t figconst = (cbl_figconst_t)(size_t)(field->initial); @@ -12192,7 +12225,7 @@ find_in_dirs(const char *dirs, char *unmangled_name, char *mangled_name) { while( !retval ) { - dirent *entry = readdir(dir); + const dirent *entry = readdir(dir); if( !entry ) { break; @@ -12248,7 +12281,7 @@ __gg__function_handle_from_cobpath( char *unmangled_name, char *mangled_name) { handle_executable = dlopen(NULL, RTLD_LAZY); } - if( !retval ) + //if( !retval ) { retval = dlsym(handle_executable, unmangled_name); } @@ -12272,14 +12305,17 @@ __gg__function_handle_from_cobpath( char *unmangled_name, char *mangled_name) extern "C" void -__gg__just_mangle_name( cblc_field_t *field, - char **mangled_name +__gg__just_mangle_name( const cblc_field_t *field, + char **mangled_name ) { static char ach_name[1024]; static char ach_unmangled[1024]; static char ach_mangled[1024]; + assert(field); + assert(field->data); + size_t length; length = field->capacity; memcpy(ach_name, field->data, length); @@ -12293,7 +12329,7 @@ __gg__just_mangle_name( cblc_field_t *field, bool is_pointer = false; - if( (field && field->type == FldPointer) ) + if( field->type == FldPointer ) { is_pointer = true; } @@ -12317,8 +12353,8 @@ __gg__just_mangle_name( cblc_field_t *field, extern "C" void * -__gg__function_handle_from_literal(int program_id, - char *literal) +__gg__function_handle_from_literal(int program_id, + const char *literal) { void *retval = NULL; static char ach_unmangled[1024]; @@ -12346,7 +12382,7 @@ __gg__function_handle_from_literal(int program_id, } PFUNC **pointers_p = it->second; PFUNC *pointers = *pointers_p; - retval = (void *)pointers[function_index]; + retval = reinterpret_cast<void *>(pointers[function_index]); } else { @@ -12358,10 +12394,10 @@ __gg__function_handle_from_literal(int program_id, extern "C" void * -__gg__function_handle_from_name(int program_id, - cblc_field_t *field, - size_t offset, - size_t length ) +__gg__function_handle_from_name(int program_id, + const cblc_field_t *field, + size_t offset, + size_t length ) { void *retval = NULL; static char ach_name[1024]; @@ -12399,7 +12435,7 @@ __gg__function_handle_from_name(int program_id, } PFUNC **pointers_p = it->second; PFUNC *pointers = *pointers_p; - retval = (void *)pointers[function_index]; + retval = reinterpret_cast<void *>(pointers[function_index]); } else { @@ -12435,10 +12471,10 @@ __gg__mirror_range( size_t nrows, cblc_field_t *src, // The row size_t src_o, size_t nspans, // The number of spans - size_t *spans, + const size_t *spans, size_t table, size_t ntbl, - size_t *tbls) + const size_t *tbls) { static std::unordered_map<size_t, size_t> rows_in_table; static std::unordered_map<size_t, size_t> widths_of_table; @@ -12459,7 +12495,7 @@ __gg__mirror_range( size_t nrows, // We need to know the width of one row of this table, which is different // depending on type of src: - cblc_field_t *parent = src; + const cblc_field_t *parent = src; while( parent ) { if( parent->occurs_upper ) @@ -12581,7 +12617,7 @@ __gg__mirror_range( size_t nrows, std::vector<size_t> subtable_spans = spans_in_table [subtable_index]; - unsigned char *subtable_source = source + subtable_offset; + const unsigned char *subtable_source = source + subtable_offset; if( subtable_spans.size() == 0 ) { @@ -12666,15 +12702,17 @@ __gg__deallocate( cblc_field_t *target, { // Target is a pointer. Free the data location int rdigits; - void *ptr = (void *)get_binary_value_local(&rdigits, + size_t addrv = get_binary_value_local(&rdigits, target, target->data + offset, sizeof(void *)); + void *ptr = reinterpret_cast<void *>(addrv); if( ptr ) { free(ptr); // And set the data location to zero - *(char **)(target->data + offset) = NULL; + *static_cast<char **>(static_cast<void *>(target->data + offset)) + = NULL; } } } @@ -12716,17 +12754,18 @@ get_the_byte(cblc_field_t *field) extern "C" void -__gg__allocate( cblc_field_t *first, - size_t first_offset, - int initialized, - int default_byte, - cblc_field_t *f_working_byte, - cblc_field_t *f_local_byte, - cblc_field_t *returning, - size_t returning_offset) +__gg__allocate( cblc_field_t *first, + size_t first_offset, + int initialized, + int default_byte, + cblc_field_t *f_working_byte, + cblc_field_t *f_local_byte, + const cblc_field_t *returning, + size_t returning_offset) { int working_byte = get_the_byte(f_working_byte); int local_byte = get_the_byte(f_local_byte); + int fill_char; unsigned char *retval = NULL; if( first->attr & based_e ) @@ -12734,12 +12773,12 @@ __gg__allocate( cblc_field_t *first, // first is the BASED variable we are allocating memory for if( first->capacity ) { - retval = (unsigned char *)malloc(first->capacity); + retval = static_cast<unsigned char *>(malloc(first->capacity)); + fill_char = 0; if( initialized ) { // This is ISO 2023 ALLOCATE rule 7 (ALL TO VALUE) - int fill_char = 0; if( default_byte >= 0 ) { fill_char = default_byte; @@ -12749,7 +12788,6 @@ __gg__allocate( cblc_field_t *first, else { // This is ISO 2023 ALLOCATE rule 9 (pointers NULL, otherwise OPT_INIT) - int fill_char = 0; if( default_byte >= 0 ) { fill_char = default_byte; @@ -12793,9 +12831,13 @@ __gg__allocate( cblc_field_t *first, tsize /= pof10; if( tsize ) { - retval = (unsigned char *)malloc(tsize); + retval = static_cast<unsigned char *>(malloc(tsize)); + if(!retval) + { + abort(); + } - int fill_char = 0; + fill_char = 0; if( initialized ) { // This is ISO 2023 rule 6 (defaultbyte if specified, else zero) @@ -12834,7 +12876,7 @@ __gg__allocate( cblc_field_t *first, if( returning ) { // 'returning' has to be a FldPointer variable; assign the retval to it. - *(unsigned char **)(returning->data + returning_offset) = retval; + *reinterpret_cast<unsigned char **>(returning->data + returning_offset) = retval; } } @@ -12863,7 +12905,8 @@ void __gg__module_name(cblc_field_t *dest, module_type_t type) { static size_t result_size = 64; - static char *result = (char *)malloc(result_size); + static char *result = static_cast<char *>(malloc(result_size)); + massert(result); strcpy(result, ""); @@ -12952,7 +12995,7 @@ __gg__module_name(cblc_field_t *dest, module_type_t type) if( strlen(result) + module_name_stack[i].substr(1).length() + 4 > result_size) { result_size *= 2; - result = (char *)realloc(result, result_size); + result = static_cast<char *>(realloc(result, result_size)); } strcat(result, module_name_stack[i].substr(1).c_str()); strcat(result, ";"); @@ -13101,39 +13144,42 @@ static char *sv_envname = NULL; extern "C" void -__gg__set_env_name( cblc_field_t *var, - size_t offset, - size_t length ) +__gg__set_env_name( const cblc_field_t *var, + size_t offset, + size_t length ) { free(sv_envname); - sv_envname = (char *)malloc(length+1); + sv_envname = static_cast<char *>(malloc(length+1)); + massert(sv_envname); memcpy(sv_envname, var->data+offset, length); sv_envname[length] = '\0'; } extern "C" void -__gg__set_env_value(cblc_field_t *value, - size_t offset, - size_t length ) +__gg__set_env_value(const cblc_field_t *value, + size_t offset, + size_t length ) { size_t name_length = strlen(sv_envname); size_t value_length = length; - static char *env = NULL; - static size_t env_length = 0; - static char *val = NULL; - static size_t val_length = 0; + static size_t env_length = 16; + static char *env = static_cast<char *>(malloc(env_length+1)); + static size_t val_length = 16; + static char *val = static_cast<char *>(malloc(val_length+1)); if( env_length < name_length+1 ) { env_length = name_length+1; - env = (char *)realloc(env, env_length); + env = static_cast<char *>(realloc(env, env_length)); } if( val_length < value_length+1 ) { val_length = value_length+1; - val = (char *)realloc(val, val_length); + val = static_cast<char *>(realloc(val, val_length)); } + massert(env); + massert(val); // The name and the value arrive in the internal codeset: memcpy(env, sv_envname, name_length); diff --git a/libgcobol/libgcobol.h b/libgcobol/libgcobol.h index f35987d..ace321d 100644 --- a/libgcobol/libgcobol.h +++ b/libgcobol/libgcobol.h @@ -39,6 +39,21 @@ Some are also called between source code modules in libgcobol, hence the need here for declarations. */ +extern void __gg__mabort(); + + +// The unnecessary abort() that follows is necessary to make cppcheck be +// aware that massert() actually terminates processing after a failed +// malloc(). +#define massert(p) if(!p){__gg__mabort();abort();} + +// This was part of an exercise to make cppcheck shut up about invalid +// pointer type conversions. +// It was also to avoid having reinterpret_cast<> all over the place. +// So, instead of reinterpret_cast<char *>(VALUE) +// I sometimes use PTRCAST(char, VALUE) +#define PTRCAST(TYPE, VALUE) static_cast<TYPE *>(static_cast<void *>(VALUE)) + extern "C" __int128 __gg__power_of_ten(int n); extern "C" __int128 __gg__dirty_to_binary_source( const char *dirty, @@ -91,20 +106,21 @@ extern "C" char * __gg__get_default_currency_string(); extern "C" void __gg__clock_gettime(clockid_t clk_id, struct timespec *tp); -extern "C" GCOB_FP128 __gg__float128_from_location(cblc_field_t *var, - unsigned char *location); +extern "C" GCOB_FP128 __gg__float128_from_location( + const cblc_field_t *var, + const unsigned char *location); extern "C" void __gg__adjust_dest_size(cblc_field_t *dest, size_t ncount); extern "C" void __gg__realloc_if_necessary( char **dest, size_t *dest_size, size_t new_size); -extern "C" void __gg__set_exception_file(cblc_file_t *file); +extern "C" void __gg__set_exception_file(const cblc_file_t *file); extern "C" void __gg__internal_to_console_in_place(char *loc, size_t length); -extern "C" __int128 __gg__binary_value_from_qualified_field(int *rdigits, - cblc_field_t *var, +extern "C" __int128 __gg__binary_value_from_qualified_field(int *rdigits, + const cblc_field_t *var, size_t offset, size_t size); -extern "C" GCOB_FP128 __gg__float128_from_qualified_field(cblc_field_t *field, +extern "C" GCOB_FP128 __gg__float128_from_qualified_field(const cblc_field_t *field, size_t offset, size_t size); extern "C" __int128 __gg__integer_from_qualified_field(cblc_field_t *var, diff --git a/libgcobol/valconv.cc b/libgcobol/valconv.cc index 8349b76..aaa89f5 100644 --- a/libgcobol/valconv.cc +++ b/libgcobol/valconv.cc @@ -71,7 +71,7 @@ __gg__realloc_if_necessary(char **dest, size_t *dest_size, size_t new_size) new_size |= new_size>>16; new_size |= (new_size>>16)>>16; *dest_size = new_size + 1; - *dest = (char *)realloc(*dest, *dest_size); + *dest = static_cast<char *>(realloc(*dest, *dest_size)); } } @@ -79,7 +79,7 @@ extern "C" void __gg__alphabet_create( cbl_encoding_t encoding, size_t alphabet_index, - unsigned char *alphabet, + const unsigned char *alphabet, int low_char, int high_char ) { @@ -222,7 +222,7 @@ Rindex(const char *dest, int length, char ch) extern "C" bool __gg__string_to_numeric_edited( char * const dest, - char *source, // In source characters + const char *source, // In source characters int rdigits, int is_negative, const char *picture) @@ -1222,9 +1222,9 @@ got_float: extern "C" void __gg__string_to_alpha_edited( char *dest, - char *source, + const char *source, int slength, - char *picture) + const char *picture) { // Put the PICTURE into the data area. If the caller didn't leave enough // room, well, poo on them. Said another way; if they specify disaster, diff --git a/libgcobol/valconv.h b/libgcobol/valconv.h index d907e6f..1efb2b9 100644 --- a/libgcobol/valconv.h +++ b/libgcobol/valconv.h @@ -60,18 +60,18 @@ extern "C" void __gg__realloc_if_necessary(char **dest, size_t *dest_size, size_t new_size); void __gg__alphabet_create(cbl_encoding_t encoding, size_t alphabet_index, - unsigned char *alphabet, + const unsigned char *alphabet, int low_char, int high_char ); bool __gg__string_to_numeric_edited(char * const dest, - char *source, // ASCII + const char *source, // ASCII int rdigits, int is_negative, const char *picture); void __gg__string_to_alpha_edited(char *dest, - char *source, + const char *source, int slength, - char *picture); + const char *picture); void __gg__currency_sign_init(); void __gg__currency_sign(int symbol, const char *sign); void __gg__remove_trailing_zeroes(char *p); 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..974c44b 100644 --- a/libgomp/ChangeLog +++ b/libgomp/ChangeLog @@ -1,3 +1,37 @@ +2025-06-03 Jakub Jelinek <jakub@redhat.com> + + PR libgomp/120444 + * testsuite/libgomp.c-c++-common/omp_target_memset-3.c (test_it): + Change ptr argument type from void * to int8_t *. + (main): Change ptr variable type from void * to int8_t * and cast + omp_target_alloc result to the latter type. + +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..7116fcd 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 @@ -3038,6 +3130,11 @@ and Fortran or used with @code{NULL} as argument in C and C++. If successful, In GCC, the effect of running this routine in a @code{target} region that is not the initial device is unspecified. +GCC implements the OpenMP 6.0 version of this function for C and C++, which is not +compatible with its type signature in previous versions of the OpenMP specification. +In older versions, the type @code{int*} was used for the @var{ret_code} argument +in place of a pointer to the enumerated type @code{omp_interop_rc_t}. + @c Implementation remark: In GCC, the Fortran interface differs from the one shown @c below: the function has C binding and @var{interop} and @var{property_id} are @c passed by value, which permits use of the same ABI as the C function. This does @@ -3084,6 +3181,11 @@ and Fortran or used with @code{NULL} as argument in C and C++. If successful, In GCC, the effect of running this routine in a @code{target} region that is not the initial device is unspecified. +GCC implements the OpenMP 6.0 version of this function for C and C++, which is not +compatible with its type signature in previous versions of the OpenMP specification. +In older versions, the type @code{int*} was used for the @var{ret_code} argument +in place of a pointer to the enumerated type @code{omp_interop_rc_t}. + @c Implementation remark: In GCC, the Fortran interface differs from the one shown @c below: the function has C binding and @var{interop} and @var{property_id} are @c passed by value, which permits use of the same ABI as the C function. This does @@ -3130,6 +3232,11 @@ and Fortran or used with @code{NULL} as argument in C and C++. If successful, In GCC, the effect of running this routine in a @code{target} region that is not the initial device is unspecified. +GCC implements the OpenMP 6.0 version of this function for C and C++, which is not +compatible with its type signature in previous versions of the OpenMP specification. +In older versions, the type @code{int*} was used for the @var{ret_code} argument +in place of a pointer to the enumerated type @code{omp_interop_rc_t}. + @c Implementation remark: In GCC, the Fortran interface differs from the one shown @c below: @var{interop} and @var{property_id} are passed by value. This does not @c affect the usage of the function when GCC's @code{omp_lib} module or @@ -3256,6 +3363,11 @@ the @var{ret_code} in human-readable form. The behavior is unspecified if value of @var{ret_code} was not set by an interoperability routine invoked for @var{interop}. +GCC implements the OpenMP 6.0 version of this function for C and C++, which is not +compatible with its type signature in previous versions of the OpenMP specification. +In older versions, the type @code{int} was used for the @var{ret_code} argument +in place of the enumerated type @code{omp_interop_rc_t}. + @item @emph{C/C++}: @multitable @columnfractions .20 .80 @item @emph{Prototype}: @tab @code{const char *omp_get_interop_rc_desc(const omp_interop_t interop, 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..9cbb8a0 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,107 @@ +2025-06-03 Jonathan Wakely <jwakely@redhat.com> + + * include/std/stop_token: Check __glibcxx_jthread instead of + __cplusplus. + +2025-06-03 Jonathan Wakely <jwakely@redhat.com> + + * include/std/type_traits (is_destructible, is_destructible_v): + Define using new built-in. + (is_nothrow_destructible, is_nothrow_destructible_v): Likewise. + (is_trivially_destructible, is_trivially_destructible_v): + Likewise. + +2025-06-03 Jonathan Wakely <jwakely@redhat.com> + + * include/bits/atomic_timed_wait.h (__detail::__wait_until): + Remove incorrect comment. + (__atomic_wait_address_until_v): Do not take address of __args in + call to __detail::__wait_until. Fix return statement to refer to + member of __wait_result_type. + (__atomic_wait_address_for_v): Change parameter type from + time_point to duration. + * src/c++20/atomic.cc (__spin_until_impl): Fix incorrect + return value. Reuse result of first call to clock. + +2025-06-03 Jonathan Wakely <jwakely@redhat.com> + + * include/bits/stl_vector.h (~_Vector_base): Add unreachable + hint for negative capacity and cast to size_t explicitly. + * include/bits/vector.tcc (vector::_M_realloc_append): Use + size() instead of end() - begin(). + +2025-06-03 Jonathan Wakely <jwakely@redhat.com> + + * include/std/bit (__rotl, __rotr): Use static_cast for + conversion from int to unsigned. + +2025-06-03 Jonathan Wakely <jwakely@redhat.com> + + * src/c++23/std.cc.in: Remove redundant checks for feature test + macros that are always true. + +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/chrono_io.h b/libstdc++-v3/include/bits/chrono_io.h index 346eb8b..239f9c7 100644 --- a/libstdc++-v3/include/bits/chrono_io.h +++ b/libstdc++-v3/include/bits/chrono_io.h @@ -1296,7 +1296,8 @@ namespace __format else { auto __str = std::format(_S_empty_spec, __ss.count()); - __out = std::format_to(_GLIBCXX_WIDEN("{:0>{}s}"), + __out = std::format_to(std::move(__out), + _GLIBCXX_WIDEN("{:0>{}s}"), __str, __hms.fractional_width); } 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..a62c3cd 100644 --- a/libstdc++-v3/include/bits/ranges_algo.h +++ b/libstdc++-v3/include/bits/ranges_algo.h @@ -438,6 +438,254 @@ namespace ranges inline constexpr __search_n_fn search_n{}; +#if __glibcxx_ranges_starts_ends_with // C++ >= 23 + struct __starts_with_fn + { + template<input_iterator _Iter1, sentinel_for<_Iter1> _Sent1, + input_iterator _Iter2, sentinel_for<_Iter2> _Sent2, + typename _Pred = ranges::equal_to, + typename _Proj1 = identity, typename _Proj2 = identity> + requires indirectly_comparable<_Iter1, _Iter2, _Pred, _Proj1, _Proj2> + constexpr bool + operator()(_Iter1 __first1, _Sent1 __last1, + _Iter2 __first2, _Sent2 __last2, _Pred __pred = {}, + _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const + { + iter_difference_t<_Iter1> __n1 = -1; + iter_difference_t<_Iter2> __n2 = -1; + if constexpr (sized_sentinel_for<_Sent1, _Iter1>) + __n1 = __last1 - __first1; + if constexpr (sized_sentinel_for<_Sent2, _Iter2>) + __n2 = __last2 - __first2; + return _S_impl(std::move(__first1), __last1, __n1, + std::move(__first2), __last2, __n2, + std::move(__pred), + std::move(__proj1), std::move(__proj2)); + } + + template<input_range _Range1, input_range _Range2, + typename _Pred = ranges::equal_to, + typename _Proj1 = identity, typename _Proj2 = identity> + requires indirectly_comparable<iterator_t<_Range1>, iterator_t<_Range2>, + _Pred, _Proj1, _Proj2> + constexpr bool + operator()(_Range1&& __r1, _Range2&& __r2, _Pred __pred = {}, + _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const + { + range_difference_t<_Range1> __n1 = -1; + range_difference_t<_Range2> __n2 = -1; + if constexpr (sized_range<_Range1>) + __n1 = ranges::size(__r1); + if constexpr (sized_range<_Range2>) + __n2 = ranges::size(__r2); + return _S_impl(ranges::begin(__r1), ranges::end(__r1), __n1, + ranges::begin(__r2), ranges::end(__r2), __n2, + std::move(__pred), + std::move(__proj1), std::move(__proj2)); + } + + private: + template<typename _Iter1, typename _Sent1, typename _Iter2, typename _Sent2, + typename _Pred, + typename _Proj1, typename _Proj2> + static constexpr bool + _S_impl(_Iter1 __first1, _Sent1 __last1, iter_difference_t<_Iter1> __n1, + _Iter2 __first2, _Sent2 __last2, iter_difference_t<_Iter2> __n2, + _Pred __pred, _Proj1 __proj1, _Proj2 __proj2) + { + if (__first2 == __last2) [[unlikely]] + return true; + else if (__n1 == -1 || __n2 == -1) + return ranges::mismatch(std::move(__first1), __last1, + std::move(__first2), __last2, + std::move(__pred), + std::move(__proj1), std::move(__proj2)).in2 == __last2; + else if (__n1 < __n2) + return false; + else if constexpr (random_access_iterator<_Iter1>) + return ranges::equal(__first1, __first1 + iter_difference_t<_Iter1>(__n2), + std::move(__first2), __last2, + std::move(__pred), + std::move(__proj1), std::move(__proj2)); + else + return ranges::equal(counted_iterator(std::move(__first1), + iter_difference_t<_Iter1>(__n2)), + default_sentinel, + std::move(__first2), __last2, + std::move(__pred), + std::move(__proj1), std::move(__proj2)); + } + + friend struct __ends_with_fn; + }; + + inline constexpr __starts_with_fn starts_with{}; + + struct __ends_with_fn + { + template<input_iterator _Iter1, sentinel_for<_Iter1> _Sent1, + input_iterator _Iter2, sentinel_for<_Iter2> _Sent2, + typename _Pred = ranges::equal_to, + typename _Proj1 = identity, typename _Proj2 = identity> + requires (forward_iterator<_Iter1> || sized_sentinel_for<_Sent1, _Iter1>) + && (forward_iterator<_Iter2> || sized_sentinel_for<_Sent2, _Iter2>) + && indirectly_comparable<_Iter1, _Iter2, _Pred, _Proj1, _Proj2> + constexpr bool + operator()(_Iter1 __first1, _Sent1 __last1, + _Iter2 __first2, _Sent2 __last2, _Pred __pred = {}, + _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const + { + iter_difference_t<_Iter1> __n1 = -1; + iter_difference_t<_Iter2> __n2 = -1; + if constexpr (sized_sentinel_for<_Sent1, _Iter1>) + __n1 = __last1 - __first1; + if constexpr (sized_sentinel_for<_Sent2, _Iter2>) + __n2 = __last2 - __first2; + return _S_impl(std::move(__first1), __last1, __n1, + std::move(__first2), __last2, __n2, + std::move(__pred), + std::move(__proj1), std::move(__proj2)); + } + + template<input_range _Range1, input_range _Range2, + typename _Pred = ranges::equal_to, + typename _Proj1 = identity, typename _Proj2 = identity> + requires (forward_range<_Range1> || sized_range<_Range1>) + && (forward_range<_Range2> || sized_range<_Range2>) + && indirectly_comparable<iterator_t<_Range1>, iterator_t<_Range2>, + _Pred, _Proj1, _Proj2> + constexpr bool + operator()(_Range1&& __r1, _Range2&& __r2, _Pred __pred = {}, + _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const + { + range_difference_t<_Range1> __n1 = -1; + range_difference_t<_Range2> __n2 = -1; + if constexpr (sized_range<_Range1>) + __n1 = ranges::size(__r1); + if constexpr (sized_range<_Range2>) + __n2 = ranges::size(__r2); + return _S_impl(ranges::begin(__r1), ranges::end(__r1), __n1, + ranges::begin(__r2), ranges::end(__r2), __n2, + std::move(__pred), + std::move(__proj1), std::move(__proj2)); + } + + private: + template<typename _Iter1, typename _Sent1, + typename _Iter2, typename _Sent2, + typename _Pred, + typename _Proj1, typename _Proj2> + static constexpr bool + _S_impl(_Iter1 __first1, _Sent1 __last1, iter_difference_t<_Iter1> __n1, + _Iter2 __first2, _Sent2 __last2, iter_difference_t<_Iter2> __n2, + _Pred __pred, _Proj1 __proj1, _Proj2 __proj2) + { + if constexpr (!random_access_iterator<_Iter1> + && bidirectional_iterator<_Iter1> && same_as<_Iter1, _Sent1> + && bidirectional_iterator<_Iter2> && same_as<_Iter2, _Sent2>) + return starts_with._S_impl(std::make_reverse_iterator(__last1), + std::make_reverse_iterator(__first1), + __n1, + std::make_reverse_iterator(__last2), + std::make_reverse_iterator(__first2), + __n2, + std::move(__pred), + std::move(__proj1), std::move(__proj2)); + + if (__first2 == __last2) [[unlikely]] + return true; + + if constexpr (forward_iterator<_Iter2>) + if (__n2 == -1) + __n2 = ranges::distance(__first2, __last2); + + // __glibcxx_assert(__n2 != -1); + + if (__n1 != -1) + { + if (__n1 < __n2) + return false; + auto __shift = __n1 - iter_difference_t<_Iter1>(__n2); + if (random_access_iterator<_Iter1> + || !bidirectional_iterator<_Iter1> + || !same_as<_Iter1, _Sent1> + || __shift < __n2) + { + ranges::advance(__first1, __shift); + return ranges::equal(std::move(__first1), __last1, + std::move(__first2), __last2, + std::move(__pred), + std::move(__proj1), std::move(__proj2)); + } + } + + if constexpr (bidirectional_iterator<_Iter1> && same_as<_Iter1, _Sent1>) + { + _Iter1 __it1 = __last1; + if (__n1 != -1) + ranges::advance(__it1, -iter_difference_t<_Iter1>(__n2)); + else + { + // We can't use ranges::advance if the haystack size is + // unknown, since we need to detect and return false if + // it's smaller than the needle. + iter_difference_t<_Iter2> __m = __n2; + while (__m != 0 && __it1 != __first1) + { + --__m; + --__it1; + } + if (__m != 0) + return false; + } + return ranges::equal(__it1, __last1, + std::move(__first2), __last2, + std::move(__pred), + std::move(__proj1), std::move(__proj2)); + } + else if constexpr (forward_iterator<_Iter1>) + { + // __glibcxx_assert(__n1 == -1); + _Iter1 __prev_first1; + __n1 = 0; + while (true) + { + iter_difference_t<_Iter2> __m = __n2; + _Iter1 __it1 = __first1; + while (__m != 0 && __it1 != __last1) + { + ++__n1; + --__m; + ++__it1; + } + if (__m != 0) + { + // __glibcxx_assert(__it1 == __last1); + if (__n1 < __n2) + return false; + __first1 = ranges::next(__prev_first1, + iter_difference_t<_Iter1>(__n2 - __m)); + break; + } + __prev_first1 = __first1; + __first1 = __it1; + } + return ranges::equal(__first1, __last1, + std::move(__first2), __last2, + std::move(__pred), + std::move(__proj1), std::move(__proj2)); + } + else + // If the haystack is non-forward then it must be sized, in which case + // we already returned via the __n1 != 1 case. + __builtin_unreachable(); + } + + }; + + inline constexpr __ends_with_fn ends_with{}; +#endif // __glibcxx_ranges_starts_ends_with + struct __find_end_fn { template<forward_iterator _Iter1, sentinel_for<_Iter1> _Sent1, @@ -1218,6 +1466,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 +1501,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/semaphore_base.h b/libstdc++-v3/include/bits/semaphore_base.h index 5b5a1c9..3f7a33c 100644 --- a/libstdc++-v3/include/bits/semaphore_base.h +++ b/libstdc++-v3/include/bits/semaphore_base.h @@ -64,69 +64,100 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __semaphore_base(const __semaphore_base&) = delete; __semaphore_base& operator=(const __semaphore_base&) = delete; - static _GLIBCXX_ALWAYS_INLINE __count_type - _S_get_current(__count_type* __counter) noexcept + // Load the current counter value. + _GLIBCXX_ALWAYS_INLINE __count_type + _M_get_current() const noexcept + { return __atomic_impl::load(&_M_counter, memory_order::acquire); } + + // Try to acquire the semaphore (i.e. decrement the counter). + // Returns false if the current counter is zero, or if another thread + // decrements the value first. In the latter case, __cur is set to the + // new value. + _GLIBCXX_ALWAYS_INLINE bool + _M_do_try_acquire(__count_type& __cur) noexcept { - return __atomic_impl::load(__counter, memory_order::acquire); - } - - static _GLIBCXX_ALWAYS_INLINE bool - _S_do_try_acquire(__count_type* __counter, __count_type __old) noexcept - { - if (__old == 0) - return false; + if (__cur == 0) + return false; // Cannot decrement when it's already zero. - return __atomic_impl::compare_exchange_strong(__counter, - __old, __old - 1, + return __atomic_impl::compare_exchange_strong(&_M_counter, + __cur, __cur - 1, memory_order::acquire, memory_order::relaxed); } - _GLIBCXX_ALWAYS_INLINE void + void _M_acquire() noexcept { - auto const __vfn = [this]{ return _S_get_current(&this->_M_counter); }; - auto const __pred = [this](__count_type __cur) { - return _S_do_try_acquire(&this->_M_counter, __cur); + auto const __vfn = [this]{ return _M_get_current(); }; + auto __val = __vfn(); + auto const __pred = [&__val](__count_type __cur) { + if (__cur > 0) + { + __val = __cur; + return true; + } + return false; }; - std::__atomic_wait_address(&_M_counter, __pred, __vfn, true); + while (!_M_do_try_acquire(__val)) + if (__val == 0) + std::__atomic_wait_address(&_M_counter, __pred, __vfn, true); } bool _M_try_acquire() noexcept { - auto const __vfn = [this]{ return _S_get_current(&this->_M_counter); }; - auto const __pred = [this](__count_type __cur) { - return _S_do_try_acquire(&this->_M_counter, __cur); - }; - using __detail::__wait_clock_t; - return std::__atomic_wait_address_for(&_M_counter, __pred, __vfn, - __wait_clock_t::duration(), - true); + // The fastest implementation of this function is just _M_do_try_acquire + // but that can fail under contention even when _M_count > 0. + // Using _M_try_acquire_for(0ns) will retry a few times in a loop. + return _M_try_acquire_for(__detail::__wait_clock_t::duration{}); } template<typename _Clock, typename _Duration> - _GLIBCXX_ALWAYS_INLINE bool + bool _M_try_acquire_until(const chrono::time_point<_Clock, _Duration>& __atime) noexcept { - auto const __vfn = [this]{ return _S_get_current(&this->_M_counter); }; - auto const __pred = [this](__count_type __cur) { - return _S_do_try_acquire(&this->_M_counter, __cur); + auto const __vfn = [this]{ return _M_get_current(); }; + auto __val = __vfn(); + auto const __pred = [&__val](__count_type __cur) { + if (__cur > 0) + { + __val = __cur; + return true; + } + return false; }; - return std::__atomic_wait_address_until(&_M_counter, __pred, __vfn, - __atime, true); + while (!_M_do_try_acquire(__val)) + if (__val == 0) + { + if (!std::__atomic_wait_address_until(&_M_counter, __pred, + __vfn, __atime, true)) + return false; // timed out + } + return true; } template<typename _Rep, typename _Period> - _GLIBCXX_ALWAYS_INLINE bool + bool _M_try_acquire_for(const chrono::duration<_Rep, _Period>& __rtime) noexcept { - auto const __vfn = [this]{ return _S_get_current(&this->_M_counter); }; - auto const __pred = [this](__count_type __cur) { - return _S_do_try_acquire(&this->_M_counter, __cur); + auto const __vfn = [this]{ return _M_get_current(); }; + auto __val = __vfn(); + auto const __pred = [&__val](__count_type __cur) { + if (__cur > 0) + { + __val = __cur; + return true; + } + return false; }; - return std::__atomic_wait_address_for(&_M_counter, __pred, __vfn, - __rtime, true); + while (!_M_do_try_acquire(__val)) + if (__val == 0) + { + if (!std::__atomic_wait_address_for(&_M_counter, __pred, + __vfn, __rtime, true)) + return false; // timed out + } + return true; } _GLIBCXX_ALWAYS_INLINE ptrdiff_t 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..9ab22cc 100644 --- a/libstdc++-v3/include/bits/version.def +++ b/libstdc++-v3/include/bits/version.def @@ -1661,6 +1661,14 @@ ftms = { }; ftms = { + name = ranges_starts_ends_with; + values = { + v = 202106; + cxxmin = 23; + }; +}; + +ftms = { name = constexpr_bitset; values = { v = 202202; @@ -1978,6 +1986,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..371a7ba 100644 --- a/libstdc++-v3/include/bits/version.h +++ b/libstdc++-v3/include/bits/version.h @@ -1848,6 +1848,16 @@ #endif /* !defined(__cpp_lib_ranges_find_last) && defined(__glibcxx_want_ranges_find_last) */ #undef __glibcxx_want_ranges_find_last +#if !defined(__cpp_lib_ranges_starts_ends_with) +# if (__cplusplus >= 202100L) +# define __glibcxx_ranges_starts_ends_with 202106L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_ranges_starts_ends_with) +# define __cpp_lib_ranges_starts_ends_with 202106L +# endif +# endif +#endif /* !defined(__cpp_lib_ranges_starts_ends_with) && defined(__glibcxx_want_ranges_starts_ends_with) */ +#undef __glibcxx_want_ranges_starts_ends_with + #if !defined(__cpp_lib_constexpr_bitset) # if (__cplusplus >= 202100L) && _GLIBCXX_HOSTED && (__cpp_constexpr_dynamic_alloc) # define __glibcxx_constexpr_bitset 202202L @@ -2213,4 +2223,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/algorithm b/libstdc++-v3/include/std/algorithm index 321a5e2..1563cdf 100644 --- a/libstdc++-v3/include/std/algorithm +++ b/libstdc++-v3/include/std/algorithm @@ -74,6 +74,7 @@ #define __glibcxx_want_ranges_contains #define __glibcxx_want_ranges_find_last #define __glibcxx_want_ranges_fold +#define __glibcxx_want_ranges_starts_ends_with #define __glibcxx_want_robust_nonmodifying_seq_ops #define __glibcxx_want_sample #define __glibcxx_want_shift 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..d9a265e 100644 --- a/libstdc++-v3/src/c++23/std.cc.in +++ b/libstdc++-v3/src/c++23/std.cc.in @@ -507,11 +507,14 @@ export namespace std using ranges::find_last_if; using ranges::find_last_if_not; #endif +#if __cpp_lib_ranges_starts_ends_with + using ranges::starts_with; + using ranges::ends_with; +#endif } } // 22.7.2 <any> -#if __cpp_lib_any export namespace std { using std::any; @@ -520,7 +523,6 @@ export namespace std using std::make_any; using std::swap; } -#endif // 24.3.2 <array> export namespace std @@ -698,7 +700,6 @@ export namespace std } // 29.2 <chrono> -#if __cpp_lib_chrono export namespace std { namespace chrono @@ -852,7 +853,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 +864,6 @@ export namespace std } // 17.11.1 <compare> -#if __cpp_lib_three_way_comparison export namespace std { using std::common_comparison_category; @@ -890,7 +889,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 +942,6 @@ export namespace std::inline literals::inline complex_literals } // 18 <concepts> -#if __cpp_lib_concepts export namespace std { using std::assignable_from; @@ -983,7 +980,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/ends_with/1.cc b/libstdc++-v3/testsuite/25_algorithms/ends_with/1.cc new file mode 100644 index 0000000..612c27a --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/ends_with/1.cc @@ -0,0 +1,165 @@ +// { dg-do run { target c++23 } } + +#include <algorithm> +#include <ranges> + +#include <testsuite_hooks.h> +#include <testsuite_iterators.h> + +namespace ranges = std::ranges; + +template<typename Range1, typename Range2> +void +test01() +{ + int n[] = {1,2,3,4,5,6,7,8,9,10}; + + Range1 haystack(n, n+10); + Range2 needle(n+7, n+10); + VERIFY( ranges::ends_with(haystack, needle) ); + + haystack = Range1(n); + needle = Range2(n, n+10); + VERIFY( ranges::ends_with(haystack, needle) ); + + haystack = Range1(n); + needle = Range2(n+6, n+9); + VERIFY( !ranges::ends_with(haystack, needle) ); + + haystack = Range1(n); + needle = Range2(n+6, n+9); + VERIFY( ranges::ends_with(haystack, needle, + [](int n, int m) { return std::abs(n - m) <= 1; }) ); + + haystack = Range1(n); + needle = Range2(n+6, n+9); + VERIFY( ranges::ends_with(haystack, needle, + ranges::equal_to{}, + [](int n) { return n - 1; }) ); + + haystack = Range1(n); + needle = Range2(n+6, n+9); + VERIFY( ranges::ends_with(haystack, needle, + ranges::equal_to{}, + std::identity{}, + [](int n) { return n + 1; }) ); + + haystack = Range1(n, n+5); + needle = Range2(n, n+10); + VERIFY( !ranges::ends_with(haystack, needle) ); +} + +template<typename Range1, typename Range2> +void +test02() +{ + int n[] = {1,2,3,4,5,6,7,8,9,10}; + + Range1 haystack(n, n+10); + Range2 needle(n+7, n+10); + VERIFY( ranges::ends_with(haystack.begin(), haystack.end(), + needle.begin(), needle.end()) ); + + haystack = Range1(n); + needle = Range2(n, n+10); + VERIFY( ranges::ends_with(haystack.begin(), haystack.end(), + needle.begin(), needle.end()) ); + + haystack = Range1(n); + needle = Range2(n+6, n+9); + VERIFY( !ranges::ends_with(haystack.begin(), haystack.end(), + needle.begin(), needle.end()) ); + + haystack = Range1(n); + needle = Range2(n+6, n+9); + VERIFY( ranges::ends_with(haystack.begin(), haystack.end(), + needle.begin(), needle.end(), + [](int n, int m) { return std::abs(n - m) <= 1; }) ); + + haystack = Range1(n); + needle = Range2(n+6, n+9); + VERIFY( ranges::ends_with(haystack.begin(), haystack.end(), + needle.begin(), needle.end(), + ranges::equal_to{}, + [](int n) { return n - 1; }) ); + + haystack = Range1(n); + needle = Range2(n+6, n+9); + VERIFY( ranges::ends_with(haystack.begin(), haystack.end(), + needle.begin(), needle.end(), + ranges::equal_to{}, + std::identity{}, + [](int n) { return n + 1; }) ); + + haystack = Range1(n, n+5); + needle = Range2(n, n+10); + VERIFY( !ranges::ends_with(haystack.begin(), haystack.end(), + needle.begin(), needle.end()) ); + + haystack = Range1(n, n+5); + needle = Range2(n+10, n+10); + VERIFY( ranges::ends_with(haystack.begin(), haystack.end(), + needle.begin(), needle.end()) ); +} + +void +test03() +{ + auto haystack = std::views::iota(0, 10); + auto needle = std::views::iota(5, 10); + +#if __SIZEOF_INT128__ + auto haystack_ict = std::views::iota(__int128(0), __int128(10)); + auto needle_ict = std::views::iota(__int128(5), __int128(10)); +#else + auto haystack_ict = std::views::iota(0ll, 10ll); + auto needle_ict = std::views::iota(5ll, 10ll); +#endif + + VERIFY( ranges::ends_with(haystack, needle_ict) ); + VERIFY( ranges::ends_with(haystack.begin(), haystack.end(), + needle_ict.begin(), needle_ict.end()) ); + + VERIFY( ranges::ends_with(haystack_ict, needle) ); + VERIFY( ranges::ends_with(haystack_ict.begin(), haystack_ict.end(), + needle.begin(), needle.end()) ); + + VERIFY( ranges::ends_with(haystack_ict, needle_ict) ); + VERIFY( ranges::ends_with(haystack_ict.begin(), haystack_ict.end(), + needle_ict.begin(), needle_ict.end()) ); +} + +int +main() +{ + using namespace __gnu_test; + using forward = test_forward_range<int>; + using bidirectional_common = bidirectional_container<int>; + using input_sized = test_input_sized_range<int>; + using input_sized_sent = test_sized_range_sized_sent<int, input_iterator_wrapper>; + using random_access = test_random_access_range<int>; + using random_access_sized = test_random_access_sized_range<int>; + using random_access_sized_sent = test_sized_range_sized_sent<int, random_access_iterator_wrapper>; + + test01<forward, forward>(); + test01<random_access, random_access>(); + test02<forward, forward>(); + test02<random_access, random_access>(); + + test01<bidirectional_common, bidirectional_common>(); + test02<bidirectional_common, bidirectional_common>(); + test01<bidirectional_common, forward>(); + test02<bidirectional_common, forward>(); + + test01<input_sized, input_sized>(); + test01<random_access_sized, random_access_sized>(); + // test02<input_sized, input_sized>(); constraint violation + test02<random_access_sized, random_access_sized>(); + + test01<input_sized_sent, input_sized_sent>(); + test01<random_access_sized_sent, random_access_sized_sent>(); + test02<input_sized_sent, input_sized_sent>(); + test02<random_access_sized_sent, random_access_sized_sent>(); + + test03(); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/starts_with/1.cc b/libstdc++-v3/testsuite/25_algorithms/starts_with/1.cc new file mode 100644 index 0000000..0c288d8 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/starts_with/1.cc @@ -0,0 +1,158 @@ +// { dg-do run { target c++23 } } + +#include <algorithm> +#include <ranges> + +#include <testsuite_hooks.h> +#include <testsuite_iterators.h> + +namespace ranges = std::ranges; + +template<typename Range1, typename Range2> +void +test01() +{ + int n[] = {1,2,3,4,5,6,7,8,9,10}; + + Range1 haystack(n, n+10); + Range2 needle(n, n+3); + VERIFY( ranges::starts_with(haystack, needle) ); + + haystack = Range1(n); + needle = Range2(n, n+10); + VERIFY( ranges::starts_with(haystack, needle) ); + + haystack = Range1(n); + needle = Range2(n+1, n+4); + VERIFY( !ranges::starts_with(haystack, needle) ); + + haystack = Range1(n); + needle = Range2(n+1, n+4); + VERIFY( ranges::starts_with(haystack, needle, + [](int n, int m) { return std::abs(n - m) <= 1; }) ); + + haystack = Range1(n); + needle = Range2(n+1, n+4); + VERIFY( ranges::starts_with(haystack, needle, + ranges::equal_to{}, + [](int n) { return n + 1; }) ); + + haystack = Range1(n); + needle = Range2(n+1, n+4); + VERIFY( ranges::starts_with(haystack, needle, + ranges::equal_to{}, + std::identity{}, + [](int n) { return n - 1; }) ); + + haystack = Range1(n, n+5); + needle = Range2(n, n+10); + VERIFY( !ranges::starts_with(haystack, needle) ); + + haystack = Range1(n, n+5); + needle = Range2(n+10, n+10); + VERIFY( ranges::starts_with(haystack, needle) ); +} + +template<typename Range1, typename Range2> +void +test02() +{ + int n[] = {1,2,3,4,5,6,7,8,9,10}; + + Range1 haystack(n, n+10); + Range2 needle(n, n+3); + VERIFY( ranges::starts_with(haystack.begin(), haystack.end(), + needle.begin(), needle.end()) ); + + haystack = Range1(n); + needle = Range2(n, n+10); + VERIFY( ranges::starts_with(haystack.begin(), haystack.end(), + needle.begin(), needle.end()) ); + + haystack = Range1(n); + needle = Range2(n+1, n+4); + VERIFY( !ranges::starts_with(haystack.begin(), haystack.end(), + needle.begin(), needle.end()) ); + + haystack = Range1(n); + needle = Range2(n+1, n+4); + VERIFY( ranges::starts_with(haystack.begin(), haystack.end(), + needle.begin(), needle.end(), + [](int n, int m) { return std::abs(n - m) <= 1; }) ); + + haystack = Range1(n); + needle = Range2(n+1, n+4); + VERIFY( ranges::starts_with(haystack.begin(), haystack.end(), + needle.begin(), needle.end(), + ranges::equal_to{}, + [](int n) { return n + 1; }) ); + + haystack = Range1(n); + needle = Range2(n+1, n+4); + VERIFY( ranges::starts_with(haystack.begin(), haystack.end(), + needle.begin(), needle.end(), + ranges::equal_to{}, + std::identity{}, + [](int n) { return n - 1; }) ); + + haystack = Range1(n, n+5); + needle = Range2(n, n+10); + VERIFY( !ranges::starts_with(haystack.begin(), haystack.end(), + needle.begin(), needle.end()) ); +} + +void +test03() +{ + auto haystack = std::views::iota(0, 10); + auto needle = std::views::iota(0, 5); + +#if __SIZEOF_INT128__ + auto haystack_ict = std::views::iota(__int128(0), __int128(10)); + auto needle_ict = std::views::iota(__int128(0), __int128(5)); +#else + auto haystack_ict = std::views::iota(0ll, 10ll); + auto needle_ict = std::views::iota(0ll, 5ll); +#endif + + VERIFY( ranges::starts_with(haystack, needle_ict) ); + VERIFY( ranges::starts_with(haystack.begin(), haystack.end(), + needle_ict.begin(), needle_ict.end()) ); + + VERIFY( ranges::starts_with(haystack_ict, needle) ); + VERIFY( ranges::starts_with(haystack_ict.begin(), haystack_ict.end(), + needle.begin(), needle.end()) ); + + VERIFY( ranges::starts_with(haystack_ict, needle_ict) ); + VERIFY( ranges::starts_with(haystack_ict.begin(), haystack_ict.end(), + needle_ict.begin(), needle_ict.end()) ); +} + +int +main() +{ + using namespace __gnu_test; + using input = test_input_range<int>; + using input_sized = test_input_sized_range<int>; + using input_sized_sent = test_sized_range_sized_sent<int, input_iterator_wrapper>; + using random_access = test_random_access_range<int>; + using random_access_sized = test_random_access_sized_range<int>; + using random_access_sized_sent = test_sized_range_sized_sent<int, random_access_iterator_wrapper>; + + test01<input, input>(); + test01<random_access, random_access>(); + test02<input, input>(); + test02<random_access, random_access>(); + + test01<input_sized, input_sized>(); + test01<random_access_sized, random_access_sized>(); + test02<input_sized, input_sized>(); + test02<random_access_sized, random_access_sized>(); + + test01<input_sized_sent, input_sized_sent>(); + test01<random_access_sized_sent, random_access_sized_sent>(); + test02<input_sized_sent, input_sized_sent>(); + test02<random_access_sized_sent, random_access_sized_sent>(); + + test03(); +} 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/30_threads/semaphore/104928-2.cc b/libstdc++-v3/testsuite/30_threads/semaphore/104928-2.cc new file mode 100644 index 0000000..7b90da8 --- /dev/null +++ b/libstdc++-v3/testsuite/30_threads/semaphore/104928-2.cc @@ -0,0 +1,101 @@ +// { dg-do run { target c++20 } } +// { dg-additional-options "-pthread" { target pthread } } +// { dg-require-gthreads "" } +// { dg-add-options libatomic } + +// Bug libstdc++/104928 - std::counting_semaphore on Linux can sleep forever + +#include <semaphore> +#include <thread> +#include <chrono> +#include <atomic> + +std::binary_semaphore t1(1); +std::binary_semaphore sem2(0); +std::atomic<int> room1 = 0; +int room2 = 0; + +std::atomic<bool> run{true}; + +enum class AcquireKind { Acquire, Try, TryFor }; + +template<std::ptrdiff_t N, AcquireKind Kind> +struct Morris +{ + using Semaphore = std::counting_semaphore<N>; + + Semaphore sem1{1}; + Semaphore sem2{0}; + unsigned counter = 0; + + void operator()() + { + while (run) + { + room1 += 1; + + acquire(sem1); + room2 += 1; + room1 -= 1; + if (room1 == 0) + sem2.release(); + else + sem1.release(); + + acquire(sem2); + room2 -= 1; + + // critical region + ++counter; + // end critical region + + if (room2 == 0) + sem1.release(); + else + sem2.release(); + } + } + + void acquire(Semaphore& sem) + { + using enum AcquireKind; + using namespace std::chrono; + if constexpr (Kind == Acquire) + sem.acquire(); + else if constexpr (Kind == Try) + while (!sem.try_acquire()) { } + else if constexpr (Kind == TryFor) + while (!sem.try_acquire_for(1h)) { } + } +}; + +template<std::ptrdiff_t N, AcquireKind Kind> +void +test_morris_kind() +{ + Morris<N, Kind> algo; + std::thread t1(std::ref(algo)); + std::thread t2(std::ref(algo)); + std::this_thread::sleep_for(std::chrono::seconds(2)); + run = false; + t1.join(); + t2.join(); +} + +template<std::ptrdiff_t N> +void +test_morris() +{ + test_morris_kind<N, AcquireKind::Acquire>(); + test_morris_kind<N, AcquireKind::Try>(); + test_morris_kind<N, AcquireKind::TryFor>(); +} + +int main() +{ + test_morris<1>(); // std::binary_semaphore + test_morris<1000>(); // std::counting_semaphore that can use futex +#if PTRDIFF_MAX > INT_MAX + // test_morris<PTRDIFF_MAX>(); // std::counting_semaphore that cannot use futex +#endif +} diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/104928.cc b/libstdc++-v3/testsuite/30_threads/semaphore/104928.cc new file mode 100644 index 0000000..f360da9 --- /dev/null +++ b/libstdc++-v3/testsuite/30_threads/semaphore/104928.cc @@ -0,0 +1,70 @@ +// { dg-do run { target c++20 } } +// { dg-additional-options "-pthread" { target pthread } } +// { dg-require-gthreads "" } +// { dg-add-options libatomic } +// { dg-options "-DSIMULATOR_TEST" { target simulator } } + +// Bug libstdc++/104928 - std::counting_semaphore on Linux can sleep forever + +#include <semaphore> +#include <thread> +#include <chrono> +#include <climits> + +#ifdef SIMULATOR_TEST +const int loop_count = 100; +const int thread_count = 6; +#else +const int loop_count = 1000000; +const int thread_count = 20; +#endif + +template<std::ptrdiff_t N, typename Acquire> +void +test_acquire(Acquire acq_func) +{ + std::counting_semaphore<N * loop_count> s{0}; + std::thread threads[thread_count]; + for (int i = 0; i < thread_count; i += 2) { + threads[i] = std::thread([&s, &acq_func]() { + for (int i = 0; i < loop_count; ++i) + acq_func(s); + }); + threads[i+1] = std::thread([&s]() { + for (int i = 0; i < loop_count; ++i) + s.release(); + }); + } + for (auto& t : threads) + t.join(); +} + +template<typename Acquire> +void +test_all(Acquire f) +{ + const int max = INT_MAX / loop_count; + test_acquire<max>(f); // can use futex +#if PTRDIFF_MAX > INT_MAX + test_acquire<max * 10>(f); // cannot use futex +#endif +} + +int main() +{ + test_all([](auto& sem) { sem.acquire(); }); + + test_all([](auto& sem) { while (!sem.try_acquire()) { } }); + + using namespace std::chrono; + + test_all([](auto& sem) { while (!sem.try_acquire_for(1h)) { } }); + + auto try_acquire_until = [](auto& sem, auto time) { + while (!sem.try_acquire_until(time + 1h)) + { } + }; + test_all([&](auto& sem) { try_acquire_until(sem, system_clock::now()); }); + test_all([&](auto& sem) { try_acquire_until(sem, steady_clock::now()); }); + test_all([&](auto& sem) { try_acquire_until(sem, utc_clock::now()); }); +} 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; + }); +} diff --git a/libstdc++-v3/testsuite/std/time/format/empty_spec.cc b/libstdc++-v3/testsuite/std/time/format/empty_spec.cc index 322faa1..ec57a6f 100644 --- a/libstdc++-v3/testsuite/std/time/format/empty_spec.cc +++ b/libstdc++-v3/testsuite/std/time/format/empty_spec.cc @@ -1,7 +1,9 @@ // { dg-do run { target c++20 } } +// { dg-require-effective-target hosted } // { dg-timeout-factor 2 } #include <chrono> +#include <ranges> #include <sstream> #include <testsuite_hooks.h> @@ -10,6 +12,46 @@ using namespace std::chrono; #define WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S) #define WIDEN(S) WIDEN_(_CharT, S) +template<typename CharT, typename T> +void +test_no_empty_spec() +{ + try + { + T t{}; + + if constexpr (std::is_same_v<CharT, char>) + (void)std::vformat("{}", std::make_format_args(t)); +#ifdef _GLIBCXX_USE_WCHAR_T + else + (void)std::vformat(L"{}", std::make_wformat_args(t)); +#endif // _GLIBCXX_USE_WCHAR_T + VERIFY(false); + } + catch (const std::format_error&) + { + VERIFY(true); + } +} + +template<typename T, typename _CharT> +void verify(const T& t, std::basic_string_view<_CharT> str) +{ + std::basic_string<_CharT> res; + + res = std::format(WIDEN("{}"), t); + VERIFY( res == str ); + + std::basic_stringstream<_CharT> os; + os << t; + res = std::move(os).str(); + VERIFY( res == str ); +} + +template<typename T, typename CharT> +void verify(const T& t, const CharT* str) +{ verify(t, std::basic_string_view<CharT>(str)); } + template<typename _CharT> void test_padding() @@ -35,18 +77,272 @@ test_padding() VERIFY( res == WIDEN("==16 is not a valid month==") ); } -template<typename T, typename _CharT> -void verify(const T& t, const _CharT* str) +template<typename Ret = void> +struct Rep +{ + using Return + = std::conditional_t<std::is_void_v<Ret>, Rep, Ret>; + + Rep(long v = 0) : val(v) {} + + operator long() const + { return val; } + + Return + operator+() const + { return val; } + + Rep + operator-() const + { return -val; } + + friend Rep + operator+(Rep lhs, Rep rhs) + { return lhs.val + rhs.val; } + + friend Rep + operator-(Rep lhs, Rep rhs) + { return lhs.val - rhs.val; } + + friend Rep + operator*(Rep lhs, Rep rhs) + { return lhs.val * rhs.val; } + + friend Rep + operator/(Rep lhs, Rep rhs) + { return lhs.val / rhs.val; } + + friend auto operator<=>(Rep, Rep) = default; + + template<typename _CharT> + friend std::basic_ostream<_CharT>& + operator<<(std::basic_ostream<_CharT>& os, const Rep& t) + { return os << t.val << WIDEN("[via <<]"); } + + long val; +}; + +template<typename Ret, typename Other> + requires std::is_integral_v<Other> +struct std::common_type<Rep<Ret>, Other> +{ + using type = Rep<Ret>; +}; + +template<typename Ret, typename Other> + requires std::is_integral_v<Other> +struct std::common_type<Other, Rep<Ret>> + : std::common_type<Rep<Ret>, Other> +{ }; + +template<typename Ret> +struct std::numeric_limits<Rep<Ret>> + : std::numeric_limits<long> +{ }; + +template<typename Ret, typename _CharT> +struct std::formatter<Rep<Ret>, _CharT> + : std::formatter<long, _CharT> +{ + template<typename Out> + typename std::basic_format_context<Out, _CharT>::iterator + format(const Rep<Ret>& t, std::basic_format_context<Out, _CharT>& ctx) const + { + constexpr std::basic_string_view<_CharT> suffix = WIDEN("[via format]"); + auto out = std::formatter<long, _CharT>::format(t.val, ctx); + return std::ranges::copy(suffix, out).out; + } +}; + +using deciseconds = duration<seconds::rep, std::deci>; + +template<typename _CharT> +void +test_duration() { std::basic_string<_CharT> res; - res = std::format(WIDEN("{}"), t); - VERIFY( res == str ); + const milliseconds di(40); + verify( di, WIDEN("40ms") ); + res = std::format(WIDEN("{:>6}"), di); + VERIFY( res == WIDEN(" 40ms") ); - std::basic_stringstream<_CharT> os; - os << t; - res = std::move(os).str(); - VERIFY( res == str ); + verify( -di, WIDEN("-40ms") ); + res = std::format(WIDEN("{:>6}"), -di); + VERIFY( res == WIDEN(" -40ms") ); + + const duration<double> df(11.22); + verify( df, WIDEN("11.22s") ); + res = std::format(WIDEN("{:=^12}"), df); + VERIFY( res == WIDEN("===11.22s===") ); + + verify( -df, WIDEN("-11.22s") ); + res = std::format(WIDEN("{:=^12}"), -df); + VERIFY( res == WIDEN("==-11.22s===") ); +} + +template<typename _CharT> +void +test_duration_cust() +{ + std::basic_string<_CharT> res; + const duration<char, std::ratio<1, 10>> charRep(123); + verify( charRep, WIDEN("123ds") ); + + // +asLong returns long, so formatted as long + const duration<Rep<long>> asLong(20); + verify( asLong, WIDEN("20s") ); + res = std::format(WIDEN("{:>6}"), asLong); + VERIFY( res == WIDEN(" 20s") ); + + verify( -asLong, WIDEN("-20s") ); + res = std::format(WIDEN("{:>6}"), -asLong); + VERIFY( res == WIDEN(" -20s") ); + + res = std::format(WIDEN("{:%Q}"), asLong); + VERIFY( res == WIDEN("20") ); + res = std::format(WIDEN("{:+<7%Q}"), asLong); + VERIFY( res == WIDEN("20+++++") ); + + // +asRep returns Rep<>, so formatted as Rep<> + const duration<Rep<>> asRep(10); + verify( asRep, WIDEN("10[via <<]s") ); + res = std::format(WIDEN("{:=^15}"), asRep); + VERIFY( res == WIDEN("==10[via <<]s==") ); + + verify( -asRep, WIDEN("-10[via <<]s") ); + res = std::format(WIDEN("{:=^15}"), -asRep); + VERIFY( res == WIDEN("=-10[via <<]s==") ); + + res = std::format(WIDEN("{:%Q}"), asRep); + VERIFY( res == WIDEN("10[via format]") ); + res = std::format(WIDEN("{:=^18%Q}"), asRep); + VERIFY( res == WIDEN("==10[via format]==") ); + + const duration<Rep<>, std::milli> milliRep(10); + verify( milliRep, WIDEN("10[via <<]ms") ); + res = std::format(WIDEN("{:=^15}"), milliRep); + VERIFY( res == WIDEN("=10[via <<]ms==") ); + + verify( -milliRep, WIDEN("-10[via <<]ms") ); + res = std::format(WIDEN("{:=^15}"), -milliRep); + VERIFY( res == WIDEN("=-10[via <<]ms=") ); + + res = std::format(WIDEN("{:%Q}"), milliRep); + VERIFY( res == WIDEN("10[via format]") ); + res = std::format(WIDEN("{:=^18%Q}"), milliRep); + VERIFY( res == WIDEN("==10[via format]==") ); +} + +template<typename Ratio, typename Rep, typename Period> +constexpr auto +hms(const duration<Rep, Period>& d) +{ + using Dur = duration<Rep, typename Ratio::period>; + return hh_mm_ss<Dur>(duration_cast<Dur>(d)); +} + +template<typename _CharT> +void +test_hh_mm_ss() +{ + auto dt = 22h + 24min + 54s + 111222333ns; + verify( hms<nanoseconds>(dt), + WIDEN("22:24:54.111222333") ); + verify( hms<microseconds>(dt), + WIDEN("22:24:54.111222") ); + verify( hms<milliseconds>(dt), + WIDEN("22:24:54.111") ); + verify( hms<deciseconds>(dt), + WIDEN("22:24:54.1") ); + verify( hms<seconds>(dt), + WIDEN("22:24:54") ); + verify( hms<minutes>(dt), + WIDEN("22:24:00") ); + verify( hms<hours>(dt), + WIDEN("22:00:00") ); + verify( hms<nanoseconds>(-dt), + WIDEN("-22:24:54.111222333") ); + verify( hms<microseconds>(-dt), + WIDEN("-22:24:54.111222") ); + verify( hms<milliseconds>(-dt), + WIDEN("-22:24:54.111") ); + verify( hms<deciseconds>(-dt), + WIDEN("-22:24:54.1") ); + verify( hms<seconds>(-dt), + WIDEN("-22:24:54") ); + verify( hms<minutes>(-dt), + WIDEN("-22:24:00") ); + verify( hms<hours>(-dt), + WIDEN("-22:00:00") ); + + verify( hms<nanoseconds>(-dt), + WIDEN("-22:24:54.111222333") ); + + dt += 300h; + verify( hms<nanoseconds>(dt), + WIDEN("322:24:54.111222333") ); + verify( hms<nanoseconds>(-dt), + WIDEN("-322:24:54.111222333") ); + + dt += 14000h; + verify( hms<nanoseconds>(dt), + WIDEN("14322:24:54.111222333") ); + verify( hms<nanoseconds>(-dt), + WIDEN("-14322:24:54.111222333") ); +} + +template<typename _CharT> +void +test_hh_mm_ss_cust() +{ + const duration<char, deciseconds::period> charRep(123); + verify( hms<deciseconds>(charRep), + WIDEN("00:00:12.3") ); + verify( hms<seconds>(charRep), + WIDEN("00:00:12") ); + + auto dt = 22h + 24min + 54s + 123ms; + // +plus returns long, so formatted as long + const duration<Rep<long>, std::milli> asLong(dt.count()); + verify( hms<milliseconds>(asLong), + WIDEN("22:24:54.123[via format]") ); + verify( hms<deciseconds>(asLong), + WIDEN("22:24:54.1[via format]") ); + verify( hms<seconds>(asLong), + WIDEN("22:24:54") ); + verify( hms<milliseconds>(-asLong), + WIDEN("-22:24:54.123[via format]") ); + verify( hms<deciseconds>(-asLong), + WIDEN("-22:24:54.1[via format]") ); + verify( hms<seconds>(-asLong), + WIDEN("-22:24:54") ); + + // +asRep returns Rep<>, so formatted as Rep<> + const duration<Rep<>, std::milli> asRep(dt.count()); + verify( hms<milliseconds>(asRep), + WIDEN("22:24:54.123[via format]") ); + verify( hms<deciseconds>(asRep), + WIDEN("22:24:54.1[via format]") ); + verify( hms<seconds>(asLong), + WIDEN("22:24:54") ); + verify( hms<milliseconds>(-asLong), + WIDEN("-22:24:54.123[via format]") ); + verify( hms<deciseconds>(-asLong), + WIDEN("-22:24:54.1[via format]") ); + verify( hms<seconds>(-asLong), + WIDEN("-22:24:54") ); +} + +template<typename CharT> +void +test_durations() +{ + test_duration<CharT>(); + test_duration_cust<CharT>(); + + test_hh_mm_ss<CharT>(); + test_hh_mm_ss_cust<CharT>(); } template<typename _CharT> @@ -283,12 +579,167 @@ test_calendar() test_year_month_weekday_last<CharT>(); } +template<typename Clock, typename Dur, typename Dur2> +constexpr auto +wall_cast(const local_time<Dur2>& tp) +{ + using TP = time_point<Clock, std::common_type_t<Dur, days>>; + if constexpr (std::is_same_v<Clock, utc_clock> || std::is_same_v<Clock, file_clock>) + return clock_cast<Clock>(wall_cast<system_clock, Dur>(tp)); + else if constexpr (std::is_same_v<Clock, tai_clock>) + return TP(floor<Dur>(tp.time_since_epoch()) + days(4383)); + else if constexpr (std::is_same_v<Clock, gps_clock>) + return TP(floor<Dur>(tp.time_since_epoch()) - days(3657)); + else // system_clock, local_t + return time_point<Clock, Dur>(floor<Dur>(tp.time_since_epoch())); +} + +using decadays = duration<days::rep, std::ratio_multiply<std::deca, days::period>>; +using kilodays = duration<days::rep, std::ratio_multiply<std::kilo, days::period>>; + +template<typename _CharT, typename Clock> +void +test_time_point(bool daysAsTime) +{ + std::basic_string<_CharT> res; + + const auto lt = local_days(2024y/March/22) + 13h + 24min + 54s + 111222333ns; + auto strip_time = [daysAsTime](std::basic_string_view<_CharT> sv) + { return daysAsTime ? sv : sv.substr(0, 10); }; + + verify( wall_cast<Clock, nanoseconds>(lt), + WIDEN("2024-03-22 13:24:54.111222333") ); + verify( wall_cast<Clock, microseconds>(lt), + WIDEN("2024-03-22 13:24:54.111222") ); + verify( wall_cast<Clock, milliseconds>(lt), + WIDEN("2024-03-22 13:24:54.111") ); + verify( wall_cast<Clock, seconds>(lt), + WIDEN("2024-03-22 13:24:54") ); + verify( wall_cast<Clock, minutes>(lt), + WIDEN("2024-03-22 13:24:00") ); + verify( wall_cast<Clock, hours>(lt), + WIDEN("2024-03-22 13:00:00") ); + verify( wall_cast<Clock, days>(lt), + strip_time(WIDEN("2024-03-22 00:00:00")) ); + verify( wall_cast<Clock, decadays>(lt), + strip_time(WIDEN("2024-03-18 00:00:00")) ); + verify( wall_cast<Clock, kilodays>(lt), + strip_time(WIDEN("2022-01-08 00:00:00")) ); +} + +template<typename _CharT> +void +test_leap_second() +{ + std::basic_string<_CharT> res; + + const auto st = sys_days(2012y/June/30) + 23h + 59min + 59s + 111222333ns; + auto tp = clock_cast<utc_clock>(st); + tp += 1s; + + verify( floor<nanoseconds>(tp), + WIDEN("2012-06-30 23:59:60.111222333") ); + verify( floor<microseconds>(tp), + WIDEN("2012-06-30 23:59:60.111222") ); + verify( floor<milliseconds>(tp), + WIDEN("2012-06-30 23:59:60.111") ); + verify( floor<seconds>(tp), + WIDEN("2012-06-30 23:59:60") ); +} + +template<typename Dur, typename Dur2> +auto +make_zoned(const sys_time<Dur2>& st, const time_zone* tz) +{ return zoned_time<Dur>(tz, floor<Dur>(st)); } + +template<typename _CharT> +void +test_zoned_time() +{ + const auto st = sys_days(2024y/March/22) + 13h + 24min + 54s + 111222333ns; + const time_zone* tz = locate_zone("Europe/Sofia"); + VERIFY( tz != nullptr ); + + verify( make_zoned<nanoseconds>(st, tz), + WIDEN("2024-03-22 15:24:54.111222333 EET") ); + verify( make_zoned<microseconds>(st, tz), + WIDEN("2024-03-22 15:24:54.111222 EET") ); + verify( make_zoned<milliseconds>(st, tz), + WIDEN("2024-03-22 15:24:54.111 EET") ); + verify( make_zoned<seconds>(st, tz), + WIDEN("2024-03-22 15:24:54 EET") ); + verify( make_zoned<minutes>(st, tz), + WIDEN("2024-03-22 15:24:00 EET") ); + verify( make_zoned<hours>(st, tz), + WIDEN("2024-03-22 15:00:00 EET") ); + verify( make_zoned<days>(st, tz), + WIDEN("2024-03-22 02:00:00 EET") ); + verify( make_zoned<decadays>(st, tz), + WIDEN("2024-03-18 02:00:00 EET") ); + verify( make_zoned<kilodays>(st, tz), + WIDEN("2022-01-08 02:00:00 EET") ); +} + +template<typename Dur, typename Dur2> +auto +local_fmt(const local_time<Dur2>& lt, std::string* zone) +{ return local_time_format(floor<Dur>(lt), zone); } + +template<typename _CharT> +void +test_local_time_format() +{ + std::basic_string<_CharT> res; + + std::string abbrev = "Zone"; + const auto lt = local_days(2024y/March/22) + 13h + 24min + 54s + 111222333ns; + + res = std::format(WIDEN("{}"), local_fmt<nanoseconds>(lt, &abbrev)); + VERIFY( res == WIDEN("2024-03-22 13:24:54.111222333 Zone") ); + res = std::format(WIDEN("{}"), local_fmt<microseconds>(lt, &abbrev)); + VERIFY( res == WIDEN("2024-03-22 13:24:54.111222 Zone") ); + res = std::format(WIDEN("{}"), local_fmt<milliseconds>(lt, &abbrev)); + VERIFY( res == WIDEN("2024-03-22 13:24:54.111 Zone") ); + res = std::format(WIDEN("{}"), local_fmt<seconds>(lt, &abbrev)); + VERIFY( res == WIDEN("2024-03-22 13:24:54 Zone") ); + res = std::format(WIDEN("{}"), local_fmt<minutes>(lt, &abbrev)); + VERIFY( res == WIDEN("2024-03-22 13:24:00 Zone") ); + res = std::format(WIDEN("{}"), local_fmt<hours>(lt, &abbrev)); + VERIFY( res == WIDEN("2024-03-22 13:00:00 Zone") ); + res = std::format(WIDEN("{}"), local_fmt<days>(lt, &abbrev)); + VERIFY( res == WIDEN("2024-03-22 00:00:00 Zone") ); + res = std::format(WIDEN("{}"), local_fmt<decadays>(lt, &abbrev)); + VERIFY( res == WIDEN("2024-03-18 00:00:00 Zone") ); + res = std::format(WIDEN("{}"), local_fmt<kilodays>(lt, &abbrev)); + VERIFY( res == WIDEN("2022-01-08 00:00:00 Zone") ); +} + +template<typename CharT> +void +test_time_points() +{ + test_time_point<CharT, local_t>(false); + test_time_point<CharT, system_clock>(false); + test_time_point<CharT, utc_clock>(true); + test_time_point<CharT, tai_clock>(true); + test_time_point<CharT, gps_clock>(true); + test_time_point<CharT, file_clock>(true); + test_leap_second<CharT>(); + test_zoned_time<CharT>(); + test_local_time_format<CharT>(); + + test_no_empty_spec<CharT, sys_time<years>>(); + test_no_empty_spec<CharT, sys_time<duration<float>>>(); +} + template<typename CharT> void test_all() { test_padding<CharT>(); + test_durations<CharT>(); test_calendar<CharT>(); + test_time_points<CharT>(); } int main() |