diff --git a/gcc/ChangeLog b/gcc/ChangeLog index d2d239191580..fb9b2fea6973 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,106 @@ +2025-11-03 Jeff Law + + Backported from master: + 2025-11-01 Jeff Law + + PR rtl-optimization/122321 + * lra-constraints.cc (update_equiv): Make sure REGNO is in + ira_reg_equiv before trying to update ira_reg_equiv. + +2025-11-03 Andrew Pinski + + Backported from master: + 2025-10-26 Andrew Pinski + + PR target/122270 + * config/riscv/riscv-vector-builtins-bases.cc (vset::fold): Use the + unshare_expr for the statement that will be added seperately rather + the one which will be used for the replacement. + +2025-11-02 Georg-Johann Lay + + Backported from master: + 2025-11-02 Georg-Johann Lay + + PR target/122527 + * config/avr/avr.cc (avr_load_libgcc_p): Return false if + the address-space is not ADDR_SPACE_FLASH. + (avr_out_lpm_no_lpmx [addr=REG]): Handle sizes of 3 and 4 bytes. + +2025-11-02 Georg-Johann Lay + + Backported from master: + 2025-11-02 Georg-Johann Lay + + PR tree-optimization/118012 + PR tree-optimization/122505 + * config/avr/avr.md (mulpsi3): Also allow the insn condition + in the case where avropt_pr118012 && !AVR_TINY. + (*mulpsi3): Handle split for the !AVR_HAVE_MUL case. + (*mulpsi3-nomul.libgcc_split, *mulpsi3-nomul.libgcc): New insns. + +2025-10-31 Tamar Christina + + Backported from master: + 2025-10-27 Tamar Christina + + PR tree-optimization/122408 + * tree-vect-slp-patterns.cc (vect_validate_multiplication): Cleanup and + document interface. + (complex_mul_pattern::matches, complex_fms_pattern::matches): Update to + new interface. + +2025-10-31 Jinyang He + + Backported from master: + 2025-10-30 Jinyang He + Peng Fan + + * config/loongarch/loongarch.cc + (loongarch_expand_conditional_move): Only allow valid binary + op when optimize conditional move. + +2025-10-30 Guo Jie + + Backported from master: + 2025-10-30 Guo Jie + + * config/loongarch/lasx.md (fnma4): Remove. + * config/loongarch/lsx.md (fnma4): Remove. + * config/loongarch/simd.md (fnma4): Simplify and correct. + +2025-10-27 Jakub Jelinek + + PR tree-optimization/122394 + * tree-ssa-phiopt.cc (spaceship_replacement): Use + build_debug_expr_decl instead of manually building DEBUG_EXPR_DECL + and getting SET_DECL_MODE wrong. + +2025-10-27 Jeff Law + + Backported from master: + 2025-10-13 Jeff Law + + PR target/120674 + * config/riscv/riscv.cc (riscv_dwarf_poly_indeterminite_value): Do not + set FACTOR to zero, for that case use one instead. + +2025-10-27 Tamar Christina + + Backported from master: + 2025-10-17 Tamar Christina + Jennifer Schmitz + + PR target/121604 + * config/aarch64/aarch64-sve-builtins-shapes.cc (apply_predication): + Store gp_index. + (struct pmov_to_vector_lane_def): Mark instruction as has no GP. + * config/aarch64/aarch64-sve-builtins.h (function_instance::gp_value, + function_instance::inactive_values, function_instance::gp_index, + function_shape::has_gp_argument_p): New. + * config/aarch64/aarch64-sve-builtins.cc (gimple_folder::fold_pfalse): + Simplify code and use GP helpers. + 2025-10-26 LIU Hao Backported from master: diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 6e95effb6d93..7b0f631f939e 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20251027 +20251105 diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 9401a29c06ad..abfd31509254 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,14 @@ +2025-11-04 Bob Duff + + PR ada/118208 + * exp_ch5.adb + (Expand_Assign_With_Target_Names.Replace_Target): + Remove code setting Entity to Empty. + * sinfo.ads (Has_Target_Names): + Improve comment: add "@" to clarify what "target name" + means, and remove the content-free phrase "and must + be expanded accordingly." + 2025-10-24 Eric Botcazou PR ada/118782 diff --git a/gcc/ada/exp_ch5.adb b/gcc/ada/exp_ch5.adb index 3d8a542c24e0..bdd7d19dcc0e 100644 --- a/gcc/ada/exp_ch5.adb +++ b/gcc/ada/exp_ch5.adb @@ -2254,7 +2254,8 @@ package body Exp_Ch5 is function Replace_Target (N : Node_Id) return Traverse_Result; -- Replace occurrences of the target name by the proper entity: either -- the entity of the LHS in simple cases, or the formal of the - -- constructed procedure otherwise. + -- constructed procedure otherwise. Mark all nodes as Analyzed=False + -- so reanalysis will occur. -------------------- -- Replace_Target -- @@ -2264,20 +2265,6 @@ package body Exp_Ch5 is begin if Nkind (N) = N_Target_Name then Rewrite (N, New_Occurrence_Of (Ent, Sloc (N))); - - -- The expression will be reanalyzed when the enclosing assignment - -- is reanalyzed, so reset the entity, which may be a temporary - -- created during analysis, e.g. a loop variable for an iterated - -- component association. However, if entity is callable then - -- resolution has established its proper identity (including in - -- rewritten prefixed calls) so we must preserve it. - - elsif Is_Entity_Name (N) then - if Present (Entity (N)) - and then not Is_Overloadable (Entity (N)) - then - Set_Entity (N, Empty); - end if; end if; Set_Analyzed (N, False); diff --git a/gcc/ada/sinfo.ads b/gcc/ada/sinfo.ads index d22f1030d427..1ad81715a2bc 100644 --- a/gcc/ada/sinfo.ads +++ b/gcc/ada/sinfo.ads @@ -1477,7 +1477,7 @@ package Sinfo is -- Has_Target_Names -- Present in assignment statements. Indicates that the RHS contains - -- target names (see AI12-0125-3) and must be expanded accordingly. + -- target names ("@" -- see AI12-0125-3). -- Has_Wide_Character -- Present in string literals, set if any wide character (i.e. character diff --git a/gcc/config/aarch64/aarch64-sve-builtins-shapes.cc b/gcc/config/aarch64/aarch64-sve-builtins-shapes.cc index af23a154d0e8..8349221797b3 100644 --- a/gcc/config/aarch64/aarch64-sve-builtins-shapes.cc +++ b/gcc/config/aarch64/aarch64-sve-builtins-shapes.cc @@ -21,7 +21,10 @@ #include "system.h" #include "coretypes.h" #include "tm.h" +#include "basic-block.h" #include "tree.h" +#include "function.h" +#include "gimple.h" #include "rtl.h" #include "tm_p.h" #include "memmodel.h" @@ -68,23 +71,36 @@ za_group_is_pure_overload (const function_group_info &group) types in ARGUMENT_TYPES. RETURN_TYPE is the type returned by the function. */ static void -apply_predication (const function_instance &instance, tree return_type, +apply_predication (function_instance &instance, tree return_type, vec &argument_types) { + /* Initially mark the function as not being predicated. */ + instance.gp_index = -1; + /* There are currently no SME ZA instructions that have both merging and unpredicated forms, so for simplicity, the predicates are always included in the original format string. */ if (instance.pred != PRED_none && instance.pred != PRED_za_m) { argument_types.quick_insert (0, instance.gp_type ()); + instance.gp_index = 0; /* For unary merge operations, the first argument is a vector with the same type as the result. For unary_convert_narrowt it also provides the "bottom" half of active elements, and is present for all types of predication. */ auto nargs = argument_types.length () - 1; if (instance.shape->has_merge_argument_p (instance, nargs)) - argument_types.quick_insert (0, return_type); + { + argument_types.quick_insert (0, return_type); + instance.gp_index = 1; + } } + + /* In this case the predicate type we added above is a non-governing + predicate operand (and there is no GP), so update the gp_index value + accordingly. */ + if (!instance.shape->has_gp_argument_p (instance)) + instance.gp_index = -1; } /* Parse and move past an element type in FORMAT and return it as a type @@ -3301,6 +3317,14 @@ struct pmov_to_vector_lane_def : public overloaded_base<0> but it doesn't currently have the necessary information. */ return c.require_immediate_range (1, 1, bytes - 1); } + + /* This function has a predicate argument, and is a merging instruction, but + the predicate is not a GP. */ + bool + has_gp_argument_p (const function_instance &) const override + { + return false; + } }; SHAPE (pmov_to_vector_lane) diff --git a/gcc/config/aarch64/aarch64-sve-builtins.cc b/gcc/config/aarch64/aarch64-sve-builtins.cc index 24feb7ce1578..ad0d38934e21 100644 --- a/gcc/config/aarch64/aarch64-sve-builtins.cc +++ b/gcc/config/aarch64/aarch64-sve-builtins.cc @@ -3630,24 +3630,22 @@ gimple_folder::redirect_pred_x () gimple * gimple_folder::fold_pfalse () { - if (pred == PRED_none) + tree gp = gp_value (call); + /* If there isn't a GP then we can't do any folding as the instruction isn't + predicated. */ + if (!gp) return nullptr; - tree arg0 = gimple_call_arg (call, 0); + if (pred == PRED_m) { - /* Unary function shapes with _m predication are folded to the - inactive vector (arg0), while other function shapes are folded - to op1 (arg1). */ - tree arg1 = gimple_call_arg (call, 1); - if (is_pfalse (arg1)) - return fold_call_to (arg0); - if (is_pfalse (arg0)) - return fold_call_to (arg1); + tree val = inactive_values (call); + if (is_pfalse (gp)) + return fold_call_to (val); return nullptr; } - if ((pred == PRED_x || pred == PRED_z) && is_pfalse (arg0)) + if ((pred == PRED_x || pred == PRED_z) && is_pfalse (gp)) return fold_call_to (build_zero_cst (TREE_TYPE (lhs))); - if (pred == PRED_implicit && is_pfalse (arg0)) + if (pred == PRED_implicit && is_pfalse (gp)) { unsigned int flags = call_properties (); /* Folding to lhs = {0, ...} is not appropriate for intrinsics with diff --git a/gcc/config/aarch64/aarch64-sve-builtins.h b/gcc/config/aarch64/aarch64-sve-builtins.h index c145b8065ae3..7e1539a0c722 100644 --- a/gcc/config/aarch64/aarch64-sve-builtins.h +++ b/gcc/config/aarch64/aarch64-sve-builtins.h @@ -402,6 +402,8 @@ public: bool could_trap_p () const; vector_type_index gp_type_index () const; + tree gp_value (gcall *) const; + tree inactive_values (gcall *) const; tree gp_type () const; unsigned int vectors_per_tuple () const; @@ -435,6 +437,7 @@ public: group_suffix_index group_suffix_id; predication_index pred; fpm_mode_index fpm_mode; + int gp_index; }; class registered_function; @@ -800,6 +803,8 @@ public: virtual bool has_merge_argument_p (const function_instance &, unsigned int) const; + virtual bool has_gp_argument_p (const function_instance &) const; + virtual bool explicit_type_suffix_p (unsigned int) const = 0; /* True if the group suffix is present in overloaded names. @@ -948,6 +953,33 @@ function_instance::gp_type () const return acle_vector_types[0][gp_type_index ()]; } +/* Return the tree value that should be used as the governing predicate of + this function. If none then return NULL_TREE. */ +inline tree +function_instance::gp_value (gcall *call) const +{ + if (gp_index < 0) + return NULL_TREE; + + return gimple_call_arg (call, gp_index); +} + +/* Return the tree value that should be used for the inactive lanes should this + function be a predicated function with a gp. Otherwise return NULL_TREE. */ +inline tree +function_instance::inactive_values (gcall *call) const +{ + if (gp_index < 0) + return NULL_TREE; + + /* Function is unary with m predicate. */ + if (gp_index == 1) + return gimple_call_arg (call, 0); + + /* Else the inactive values are the next element. */ + return gimple_call_arg (call, 1); +} + /* If the function operates on tuples of vectors, return the number of vectors in the tuples, otherwise return 1. */ inline unsigned int @@ -1122,6 +1154,14 @@ function_shape::has_merge_argument_p (const function_instance &instance, return nargs == 1 && instance.pred == PRED_m; } +/* Return true if INSTANCE has an predicate argument that can be used as the global + predicate. */ +inline bool +function_shape::has_gp_argument_p (const function_instance &instance) const +{ + return instance.pred != PRED_none; +} + /* Return the mode of the result of a call. */ inline machine_mode function_expander::result_mode () const diff --git a/gcc/config/avr/avr.cc b/gcc/config/avr/avr.cc index cf80d5a15551..2b625e637170 100644 --- a/gcc/config/avr/avr.cc +++ b/gcc/config/avr/avr.cc @@ -3293,7 +3293,8 @@ avr_load_libgcc_p (rtx op) return (n_bytes > 2 && !AVR_HAVE_LPMX - && avr_mem_flash_p (op)); + && avr_mem_flash_p (op) + && MEM_ADDR_SPACE (op) == ADDR_SPACE_FLASH); } @@ -3645,6 +3646,46 @@ avr_out_lpm_no_lpmx (rtx_insn *insn, rtx *xop, int *plen) avr_asm_len ("sbiw %2,1", xop, plen, 1); break; /* 2 */ + + /* cases 3 and 4 are only needed with ELPM but no ELPMx. */ + + case 3: + if (REGNO (dest) == REG_Z - 2 + && !reg_unused_after (insn, all_regs_rtx[REG_31])) + avr_asm_len ("push r31", xop, plen, 1); + + avr_asm_len ("%4lpm $ mov %A0,%3 $ adiw %2,1", xop, plen, 3); + avr_asm_len ("%4lpm $ mov %B0,%3 $ adiw %2,1", xop, plen, 3); + avr_asm_len ("%4lpm $ mov %C0,%3", xop, plen, 2); + + if (REGNO (dest) == REG_Z - 2) + { + if (!reg_unused_after (insn, all_regs_rtx[REG_31])) + avr_asm_len ("pop r31", xop, plen, 1); + } + else if (!reg_unused_after (insn, addr)) + avr_asm_len ("sbiw %2,2", xop, plen, 1); + + break; /* 3 */ + + case 4: + avr_asm_len ("%4lpm $ mov %A0,%3 $ adiw %2,1", xop, plen, 3); + avr_asm_len ("%4lpm $ mov %B0,%3 $ adiw %2,1", xop, plen, 3); + if (REGNO (dest) != REG_Z - 2) + { + avr_asm_len ("%4lpm $ mov %C0,%3 $ adiw %2,1", xop, plen, 3); + avr_asm_len ("%4lpm $ mov %D0,%3", xop, plen, 2); + if (!reg_unused_after (insn, addr)) + avr_asm_len ("sbiw %2,3", xop, plen, 1); + } + else + { + avr_asm_len ("%4lpm $ push %3 $ adiw %2,1", xop, plen, 3); + avr_asm_len ("%4lpm $ mov %D0,%3", xop, plen, 2); + avr_asm_len ("pop $C0", xop, plen, 1); + } + + break; /* 4 */ } break; /* REG */ diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md index 3ca0efbbe759..6788e9d82a1d 100644 --- a/gcc/config/avr/avr.md +++ b/gcc/config/avr/avr.md @@ -4091,9 +4091,17 @@ (match_operand:PSI 2 "nonmemory_operand" ""))) (clobber (reg:HI 26)) (clobber (reg:DI 18))])] - "AVR_HAVE_MUL" + "AVR_HAVE_MUL + || (avropt_pr118012 + /* AVR_TINY passes args on the stack, so we cannot work + around PR118012 like this. */ + && ! AVR_TINY)" { - if (s8_operand (operands[2], PSImode)) + if (!AVR_HAVE_MUL) + { + operands[2] = force_reg (PSImode, operands[2]); + } + else if (s8_operand (operands[2], PSImode)) { rtx reg = force_reg (QImode, gen_int_mode (INTVAL (operands[2]), QImode)); emit_insn (gen_mulsqipsi3 (operands[0], reg, operands[1])); @@ -4198,7 +4206,9 @@ (match_operand:PSI 2 "pseudo_register_or_const_int_operand" "rn"))) (clobber (reg:HI 26)) (clobber (reg:DI 18))] - "AVR_HAVE_MUL && !reload_completed" + "!reload_completed + && (AVR_HAVE_MUL + || (avropt_pr118012 && !AVR_TINY))" { gcc_unreachable(); } "&& 1" [(set (reg:PSI 18) @@ -4208,13 +4218,30 @@ (parallel [(set (reg:PSI 22) (mult:PSI (reg:PSI 22) (reg:PSI 18))) - (clobber (reg:QI 21)) - (clobber (reg:QI 25)) - (clobber (reg:HI 26))]) + (clobber (match_dup 3)) + (clobber (match_dup 4)) + (clobber (match_dup 5))]) (set (match_dup 0) (reg:PSI 22))] { - if (s8_operand (operands[2], PSImode)) + if (AVR_HAVE_MUL) + { + operands[3] = gen_rtx_REG (QImode, REG_21); + operands[4] = gen_rtx_REG (QImode, REG_25); + operands[5] = gen_rtx_REG (HImode, REG_26); + } + else + { + operands[3] = gen_rtx_REG (SImode, REG_18); + operands[4] = gen_rtx_SCRATCH (QImode); + operands[5] = gen_rtx_SCRATCH (HImode); + } + + if (!AVR_HAVE_MUL) + { + operands[2] = force_reg (PSImode, operands[2]); + } + else if (s8_operand (operands[2], PSImode)) { rtx reg = force_reg (QImode, gen_int_mode (INTVAL (operands[2]), QImode)); emit_insn (gen_mulsqipsi3 (operands[0], reg, operands[1])); @@ -4273,6 +4300,37 @@ "%~call __mulpsi3" [(set_attr "type" "xcall")]) +(define_insn_and_split "*mulpsi3-nomul.libgcc_split" + [(set (reg:PSI 22) + (mult:PSI (reg:PSI 22) + (reg:PSI 18))) + (clobber (reg:SI 18)) + (clobber (scratch:QI)) + (clobber (scratch:HI))] + "!AVR_HAVE_MUL && avropt_pr118012 && !AVR_TINY" + "#" + "&& reload_completed" + [(parallel [(set (reg:PSI 22) + (mult:PSI (reg:PSI 22) + (reg:PSI 18))) + (clobber (reg:SI 18)) + (clobber (scratch:QI)) + (clobber (scratch:HI)) + (clobber (reg:CC REG_CC))])]) + +(define_insn "*mulpsi3-nomul.libgcc" + [(set (reg:PSI 22) + (mult:PSI (reg:PSI 22) + (reg:PSI 18))) + (clobber (reg:SI 18)) + (clobber (scratch:QI)) + (clobber (scratch:HI)) + (clobber (reg:CC REG_CC))] + "reload_completed + && !AVR_HAVE_MUL && avropt_pr118012 && !AVR_TINY" + "%~call __mulpsi3" + [(set_attr "type" "xcall")]) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; 24-bit signed/unsigned division and modulo. diff --git a/gcc/config/loongarch/lasx.md b/gcc/config/loongarch/lasx.md index 3d71f30a54be..9df572beb9e1 100644 --- a/gcc/config/loongarch/lasx.md +++ b/gcc/config/loongarch/lasx.md @@ -993,16 +993,6 @@ [(set_attr "type" "simd_fmadd") (set_attr "mode" "")]) -(define_insn "fnma4" - [(set (match_operand:FLASX 0 "register_operand" "=f") - (fma:FLASX (neg:FLASX (match_operand:FLASX 1 "register_operand" "f")) - (match_operand:FLASX 2 "register_operand" "f") - (match_operand:FLASX 3 "register_operand" "0")))] - "ISA_HAS_LASX" - "xvfnmsub.\t%u0,%u1,%u2,%u0" - [(set_attr "type" "simd_fmadd") - (set_attr "mode" "")]) - (define_expand "sqrt2" [(set (match_operand:FLASX 0 "register_operand") (sqrt:FLASX (match_operand:FLASX 1 "register_operand")))] diff --git a/gcc/config/loongarch/loongarch.cc b/gcc/config/loongarch/loongarch.cc index 3cfc0cf1b829..b3189f3101de 100644 --- a/gcc/config/loongarch/loongarch.cc +++ b/gcc/config/loongarch/loongarch.cc @@ -5437,12 +5437,32 @@ loongarch_expand_conditional_move (rtx *operands) } } + auto is_binary_op_0_keep_orig = [](enum rtx_code code) + { + switch (code) + { + case PLUS: + case MINUS: + case IOR: + case XOR: + case ROTATE: + case ROTATERT: + case ASHIFT: + case ASHIFTRT: + case LSHIFTRT: + return true; + default: + return false; + } + }; + /* Check if the optimization conditions are met. */ if (value_if_true_insn && value_if_false_insn - /* Make sure that value_if_false and var are the same. */ - && BINARY_P (value_if_true_insn_src - = SET_SRC (single_set (value_if_true_insn))) + /* Make sure that the orig value OP 0 keep orig. */ + && (value_if_true_insn_src + = SET_SRC (single_set (value_if_true_insn))) + && is_binary_op_0_keep_orig ( GET_CODE (value_if_true_insn_src)) /* Make sure that both value_if_true and value_if_false has the same var. */ && rtx_equal_p (XEXP (value_if_true_insn_src, 0), diff --git a/gcc/config/loongarch/lsx.md b/gcc/config/loongarch/lsx.md index fb0236ba0f1b..cf48a16b69ea 100644 --- a/gcc/config/loongarch/lsx.md +++ b/gcc/config/loongarch/lsx.md @@ -852,16 +852,6 @@ [(set_attr "type" "simd_fmadd") (set_attr "mode" "")]) -(define_insn "fnma4" - [(set (match_operand:FLSX 0 "register_operand" "=f") - (fma:FLSX (neg:FLSX (match_operand:FLSX 1 "register_operand" "f")) - (match_operand:FLSX 2 "register_operand" "f") - (match_operand:FLSX 3 "register_operand" "0")))] - "ISA_HAS_LSX" - "vfnmsub.\t%w0,%w1,%w2,%w0" - [(set_attr "type" "simd_fmadd") - (set_attr "mode" "")]) - (define_expand "sqrt2" [(set (match_operand:FLSX 0 "register_operand") (sqrt:FLSX (match_operand:FLSX 1 "register_operand")))] diff --git a/gcc/config/loongarch/simd.md b/gcc/config/loongarch/simd.md index 4156b269f9ad..88ab138a8c66 100644 --- a/gcc/config/loongarch/simd.md +++ b/gcc/config/loongarch/simd.md @@ -431,6 +431,17 @@ [(set_attr "type" "simd_int_arith") (set_attr "mode" "")]) +;; vfnmsub.{s/d} +(define_insn "fnma4" + [(set (match_operand:FVEC 0 "register_operand" "=f") + (fma:FVEC (neg:FVEC (match_operand:FVEC 1 "register_operand" "f")) + (match_operand:FVEC 2 "register_operand" "f") + (match_operand:FVEC 3 "register_operand" "f")))] + "!HONOR_SIGNED_ZEROS (mode)" + "vfnmsub.\t%0,%1,%2,%3" + [(set_attr "type" "simd_fmadd") + (set_attr "mode" "")]) + ;; vfcmp.*.{s/d} with defined RTX code ;; There are no fcmp.{sugt/suge/cgt/cge}.{s/d} menmonics in GAS, so we have ;; to reverse the operands ourselves :(. diff --git a/gcc/config/riscv/riscv-vector-builtins-bases.cc b/gcc/config/riscv/riscv-vector-builtins-bases.cc index bf5172c6e041..5ccb872df639 100644 --- a/gcc/config/riscv/riscv-vector-builtins-bases.cc +++ b/gcc/config/riscv/riscv-vector-builtins-bases.cc @@ -1792,12 +1792,13 @@ public: The fold routines expect the replacement statement to have the same lhs as the original call, so return the copy statement rather than the field update. */ - gassign *copy = gimple_build_assign (unshare_expr (f.lhs), rhs_tuple); + gassign *copy = gimple_build_assign (f.lhs, rhs_tuple); /* Get a reference to the individual vector. */ tree field = tuple_type_field (TREE_TYPE (f.lhs)); tree lhs_array - = build3 (COMPONENT_REF, TREE_TYPE (field), f.lhs, field, NULL_TREE); + = build3 (COMPONENT_REF, TREE_TYPE (field), unshare_expr (f.lhs), + field, NULL_TREE); tree lhs_vector = build4 (ARRAY_REF, TREE_TYPE (rhs_vector), lhs_array, index, NULL_TREE, NULL_TREE); gassign *update = gimple_build_assign (lhs_vector, rhs_vector); diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index 472c2e60d9f5..314524ac1c87 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -11809,6 +11809,13 @@ riscv_dwarf_poly_indeterminate_value (unsigned int i, unsigned int *factor, */ gcc_assert (i == 1); *factor = BYTES_PER_RISCV_VECTOR.coeffs[1]; + + /* The factor will be zero if vector is not enabled. That ultimately + causes problems in the dwarf2 emitter as the factor is used for + a division, causing a divide by zero. */ + if (*factor == 0) + *factor = 1; + *offset = 1; return RISCV_DWARF_VLENB; } diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 92be4b2ba451..70a0a5cc0afc 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,66 @@ +2025-11-04 Nathaniel Shead + + Backported from master: + 2025-11-04 Nathaniel Shead + + PR c++/122253 + * decl2.cc (min_vis_expr_r): Don't mark no-linkage declarations + as VISIBILITY_ANON. + +2025-11-02 Nathaniel Shead + + Backported from master: + 2025-11-02 Nathaniel Shead + + PR c++/122421 + * module.cc (trees_in::read_var_def): Don't handle class-scope + variables anymore. + (trees_in::read_class_def): Handle them here instead. + +2025-11-01 Nathaniel Shead + + Backported from master: + 2025-11-01 Nathaniel Shead + + PR c++/122381 + * module.cc (trees_out::core_vals): Write BASELINK_OPTYPE (aka + TREE_CHAIN). + (trees_in::core_vals): Read it. + +2025-10-28 Patrick Palka + + Backported from master: + 2025-10-14 Patrick Palka + + PR c++/122192 + * parser.cc (cp_parser_mem_initializer_id): Pass class_type + instead of typename_type to cp_parser_class_name in the + nested-name-specifier case. + +2025-10-28 Patrick Palka + + Backported from master: + 2025-10-10 Patrick Palka + + PR c++/122192 + * decl.cc (make_typename_type): Document base-specifier as + another type-only lookup case. + * parser.cc (cp_parser_class_name): Propagate tag_type to + make_typename_type instead of hardcoding typename_type. + (cp_parser_base_specifier): Pass class_type instead of + typename_type as tag_type to cp_parser_class_name. + +2025-10-28 Nathaniel Shead + + Backported from master: + 2025-10-27 Nathaniel Shead + + PR c++/122310 + * module.cc (get_keyed_decl_scope): New function. + (trees_out::get_merge_kind): Use it. + (trees_out::key_mergeable): Use it. + (maybe_key_decl): Key to the containing type for all members. + 2025-10-14 Jason Merrill Backported from master: diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index 9b20e45f3bd2..f77bfe699308 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -4546,7 +4546,9 @@ make_typename_type (tree context, tree name, enum tag_types tag_type, - the tag corresponds to a class-key or 'enum' so [basic.lookup.elab] applies, or - the tag corresponds to scope_type or tf_qualifying_scope is - set so [basic.lookup.qual]/1 applies. + set so [basic.lookup.qual]/1 applies, or + - we're inside a base-specifier so [class.derived.general]/2 applies; + the tag will already be class_type in that case. TODO: If we'd set/track the scope_type tag thoroughly on all TYPENAME_TYPEs that are followed by :: then we wouldn't need the tf_qualifying_scope flag. */ diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc index fb2801c60184..f29e8b75c624 100644 --- a/gcc/cp/decl2.cc +++ b/gcc/cp/decl2.cc @@ -2867,7 +2867,12 @@ min_vis_expr_r (tree *tp, int */*walk_subtrees*/, void *data) break; } addressable: - if (! TREE_PUBLIC (t)) + if (decl_linkage (t) == lk_none) + tpvis = type_visibility (TREE_TYPE (t)); + /* Decls that have had their visibility constrained will report + as external linkage, but we still want to transitively constrain + if we refer to them, so just check TREE_PUBLIC instead. */ + else if (!TREE_PUBLIC (t)) tpvis = VISIBILITY_ANON; else tpvis = DECL_VISIBILITY (t); diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 2f19b2b485dd..eed84706686b 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -2789,6 +2789,8 @@ vec *post_load_decls; typedef hash_map> keyed_map_t; static keyed_map_t *keyed_table; +static tree get_keyed_decl_scope (tree); + /* Instantiations of temploid friends imported from another module need to be attached to the same module as the temploid. This maps these decls to the temploid they are instantiated from, as there is @@ -6688,6 +6690,7 @@ trees_out::core_vals (tree t) WT (((lang_tree_node *)t)->baselink.binfo); WT (((lang_tree_node *)t)->baselink.functions); WT (((lang_tree_node *)t)->baselink.access_binfo); + WT (((lang_tree_node *)t)->baselink.common.chain); break; case CONSTRAINT_INFO: @@ -7257,6 +7260,7 @@ trees_in::core_vals (tree t) RT (((lang_tree_node *)t)->baselink.binfo); RTU (((lang_tree_node *)t)->baselink.functions); RT (((lang_tree_node *)t)->baselink.access_binfo); + RT (((lang_tree_node *)t)->baselink.common.chain); break; case CONSTRAINT_INFO: @@ -11275,20 +11279,12 @@ trees_out::get_merge_kind (tree decl, depset *dep) if (DECL_IMPLICIT_TYPEDEF_P (STRIP_TEMPLATE (decl)) && LAMBDA_TYPE_P (TREE_TYPE (decl))) { - if (tree scope = LAMBDA_TYPE_EXTRA_SCOPE (TREE_TYPE (decl))) - { - /* Lambdas attached to fields are keyed to its class. */ - if (TREE_CODE (scope) == FIELD_DECL) - scope = TYPE_NAME (DECL_CONTEXT (scope)); - if (DECL_LANG_SPECIFIC (scope) - && DECL_MODULE_KEYED_DECLS_P (scope)) - { - mk = MK_keyed; - break; - } - } - /* Lambdas not attached to any mangling scope are TU-local. */ - mk = MK_unique; + if (get_keyed_decl_scope (decl)) + mk = MK_keyed; + else + /* Lambdas not attached to any mangling scope are TU-local + and so cannot be deduplicated. */ + mk = MK_unique; break; } @@ -11589,16 +11585,9 @@ trees_out::key_mergeable (int tag, merge_kind mk, tree decl, tree inner, case MK_keyed: { - gcc_checking_assert (LAMBDA_TYPE_P (TREE_TYPE (inner))); - tree scope = LAMBDA_TYPE_EXTRA_SCOPE (TREE_TYPE (inner)); - gcc_checking_assert (TREE_CODE (scope) == VAR_DECL - || TREE_CODE (scope) == FIELD_DECL - || TREE_CODE (scope) == PARM_DECL - || TREE_CODE (scope) == TYPE_DECL - || TREE_CODE (scope) == CONCEPT_DECL); - /* Lambdas attached to fields are keyed to the class. */ - if (TREE_CODE (scope) == FIELD_DECL) - scope = TYPE_NAME (DECL_CONTEXT (scope)); + tree scope = get_keyed_decl_scope (inner); + gcc_checking_assert (scope); + auto *root = keyed_table->get (scope); unsigned ix = root->length (); /* If we don't find it, we'll write a really big number @@ -12859,12 +12848,11 @@ trees_in::read_var_def (tree decl, tree maybe_template) if (DECL_EXPLICIT_INSTANTIATION (decl) && !DECL_EXTERNAL (decl)) setup_explicit_instantiation_definition_linkage (decl); - if (DECL_IMPLICIT_INSTANTIATION (decl) - || (DECL_EXPLICIT_INSTANTIATION (decl) - && !DECL_EXTERNAL (decl)) - || (DECL_CLASS_SCOPE_P (decl) - && !DECL_VTABLE_OR_VTT_P (decl) - && !DECL_TEMPLATE_INFO (decl))) + /* Class static data members are handled in read_class_def. */ + if (!DECL_CLASS_SCOPE_P (decl) + && (DECL_IMPLICIT_INSTANTIATION (decl) + || (DECL_EXPLICIT_INSTANTIATION (decl) + && !DECL_EXTERNAL (decl)))) note_vague_linkage_variable (decl); } if (!dyn_init) @@ -13278,6 +13266,10 @@ trees_in::read_class_def (tree defn, tree maybe_template) DECL_ACCESS (d) = tree_cons (type, access, list); } } + + if (TREE_CODE (decl) == VAR_DECL + && TREE_CODE (maybe_template) != TEMPLATE_DECL) + note_vague_linkage_variable (decl); } } @@ -20916,9 +20908,21 @@ maybe_key_decl (tree ctx, tree decl) && TREE_CODE (ctx) != CONCEPT_DECL) return; - /* For fields, key it to the containing type to handle deduplication - correctly. */ - if (TREE_CODE (ctx) == FIELD_DECL) + /* For members, key it to the containing type to handle deduplication + correctly. For fields, this is necessary as FIELD_DECLs have no + dep and so would only be streamed after the lambda type, defeating + our ability to merge them. + + Other class-scope key decls might depend on the type of the lambda + but be within the same cluster; we need to ensure that we never + first see the key decl while streaming the lambda type as merging + would then fail when comparing the partially-streamed lambda type + of the key decl with the existing (PR c++/122310). + + Perhaps sort_cluster can be adjusted to handle this better, but + this is a simple workaround (and might down on the number of + entries in keyed_table as a bonus). */ + while (DECL_CLASS_SCOPE_P (ctx)) ctx = TYPE_NAME (DECL_CONTEXT (ctx)); if (!keyed_table) @@ -20933,6 +20937,30 @@ maybe_key_decl (tree ctx, tree decl) vec.safe_push (decl); } +/* Find the scope that the lambda DECL is keyed to, if any. */ + +static tree +get_keyed_decl_scope (tree decl) +{ + gcc_checking_assert (LAMBDA_TYPE_P (TREE_TYPE (decl))); + tree scope = LAMBDA_TYPE_EXTRA_SCOPE (TREE_TYPE (decl)); + if (!scope) + return NULL_TREE; + + gcc_checking_assert (TREE_CODE (scope) == VAR_DECL + || TREE_CODE (scope) == FIELD_DECL + || TREE_CODE (scope) == PARM_DECL + || TREE_CODE (scope) == TYPE_DECL + || TREE_CODE (scope) == CONCEPT_DECL); + + while (DECL_CLASS_SCOPE_P (scope)) + scope = TYPE_NAME (DECL_CONTEXT (scope)); + + gcc_checking_assert (DECL_LANG_SPECIFIC (scope) + && DECL_MODULE_KEYED_DECLS_P (scope)); + return scope; +} + /* DECL is an instantiated friend that should be attached to the same module that ORIG is. */ diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 9cd5d7cb27ff..e671b92b6e92 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -18509,7 +18509,7 @@ cp_parser_mem_initializer_id (cp_parser* parser) return cp_parser_class_name (parser, /*typename_keyword_p=*/true, /*template_keyword_p=*/template_p, - typename_type, + class_type, /*check_dependency_p=*/true, /*class_head_p=*/false, /*is_declaration=*/true); @@ -27809,8 +27809,7 @@ cp_parser_class_name (cp_parser *parser, /* If this is a typename, create a TYPENAME_TYPE. */ if (typename_p && decl != error_mark_node) { - decl = make_typename_type (scope, decl, typename_type, - /*complain=*/tf_error); + decl = make_typename_type (scope, decl, tag_type, /*complain=*/tf_error); if (decl != error_mark_node) decl = TYPE_NAME (decl); } @@ -30203,7 +30202,7 @@ cp_parser_base_specifier (cp_parser* parser) type = cp_parser_class_name (parser, class_scope_p, template_p, - typename_type, + class_type, /*check_dependency_p=*/true, /*class_head_p=*/false, /*is_declaration=*/true); diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 5e36c6bdd41e..4e8a3e7c0aa8 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,26 @@ +2025-11-01 Harald Anlauf + + Backported from master: + 2025-10-25 Harald Anlauf + + PR fortran/114023 + * trans-expr.cc (gfc_trans_pointer_assignment): Always set dtype + when remapping a pointer. For unlimited polymorphic LHS use + elem_len from RHS. + * trans-intrinsic.cc (gfc_conv_is_contiguous_expr): Extend inline + generated code for IS_CONTIGUOUS for pointer arguments to detect + when span differs from the element size. + +2025-11-01 Harald Anlauf + + Backported from master: + 2025-10-24 Harald Anlauf + + PR fortran/122386 + * dependency.cc (gfc_ref_needs_temporary_p): Revert r16-518. + * trans-intrinsic.cc (gfc_conv_intrinsic_transfer): Force temporary + for SOURCE not being a simply-contiguous array. + 2025-10-25 Harald Anlauf Backported from master: diff --git a/gcc/fortran/dependency.cc b/gcc/fortran/dependency.cc index aa8a57a80e0e..57c0c49391bd 100644 --- a/gcc/fortran/dependency.cc +++ b/gcc/fortran/dependency.cc @@ -944,12 +944,8 @@ gfc_ref_needs_temporary_p (gfc_ref *ref) types), not in characters. */ return subarray_p; - case REF_INQUIRY: - /* Within an array reference, inquiry references of complex - variables generally need a temporary. */ - return subarray_p; - case REF_COMPONENT: + case REF_INQUIRY: break; } diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc index 9ebadb1db264..683f2f1ae8e9 100644 --- a/gcc/fortran/trans-expr.cc +++ b/gcc/fortran/trans-expr.cc @@ -11232,21 +11232,33 @@ gfc_trans_pointer_assignment (gfc_expr * expr1, gfc_expr * expr2) int dim; gcc_assert (remap->u.ar.dimen == expr1->rank); + /* Always set dtype. */ + tree dtype = gfc_conv_descriptor_dtype (desc); + tmp = gfc_get_dtype (TREE_TYPE (desc)); + gfc_add_modify (&block, dtype, tmp); + + /* For unlimited polymorphic LHS use elem_len from RHS. */ + if (UNLIMITED_POLY (expr1) && expr2->ts.type != BT_CLASS) + { + tree elem_len; + tmp = TYPE_SIZE_UNIT (gfc_typenode_for_spec (&expr2->ts)); + elem_len = fold_convert (gfc_array_index_type, tmp); + elem_len = gfc_evaluate_now (elem_len, &block); + tmp = gfc_conv_descriptor_elem_len (desc); + gfc_add_modify (&block, tmp, + fold_convert (TREE_TYPE (tmp), elem_len)); + } + if (rank_remap) { /* Do rank remapping. We already have the RHS's descriptor converted in rse and now have to build the correct LHS descriptor for it. */ - tree dtype, data, span; + tree data, span; tree offs, stride; tree lbound, ubound; - /* Set dtype. */ - dtype = gfc_conv_descriptor_dtype (desc); - tmp = gfc_get_dtype (TREE_TYPE (desc)); - gfc_add_modify (&block, dtype, tmp); - /* Copy data pointer. */ data = gfc_conv_descriptor_data_get (rse.expr); gfc_conv_descriptor_data_set (&block, desc, data); diff --git a/gcc/fortran/trans-intrinsic.cc b/gcc/fortran/trans-intrinsic.cc index d748dd72569b..4b68f5759488 100644 --- a/gcc/fortran/trans-intrinsic.cc +++ b/gcc/fortran/trans-intrinsic.cc @@ -2315,10 +2315,14 @@ gfc_conv_is_contiguous_expr (gfc_se *se, gfc_expr *arg) int i; tree fncall0; gfc_array_spec *as; + gfc_symbol *sym = NULL; if (arg->ts.type == BT_CLASS) gfc_add_class_array_ref (arg); + if (arg->expr_type == EXPR_VARIABLE) + sym = arg->symtree->n.sym; + ss = gfc_walk_expr (arg); gcc_assert (ss != gfc_ss_terminator); gfc_init_se (&argse, NULL); @@ -2341,7 +2345,7 @@ gfc_conv_is_contiguous_expr (gfc_se *se, gfc_expr *arg) fncall0 = build_call_expr_loc (input_location, gfor_fndecl_is_contiguous0, 1, desc); se->expr = fncall0; - se->expr = convert (logical_type_node, se->expr); + se->expr = convert (boolean_type_node, se->expr); } else { @@ -2373,6 +2377,22 @@ gfc_conv_is_contiguous_expr (gfc_se *se, gfc_expr *arg) } se->expr = cond; } + + /* A pointer that does not have the CONTIGUOUS attribute needs to be checked + if it points to an array whose span differs from the element size. */ + if (as && sym && IS_POINTER(sym) && !sym->attr.contiguous) + { + tree span = gfc_conv_descriptor_span_get (desc); + tmp = fold_convert (TREE_TYPE (span), + gfc_conv_descriptor_elem_len (desc)); + cond = fold_build2_loc (input_location, EQ_EXPR, boolean_type_node, + span, tmp); + se->expr = fold_build2_loc (input_location, TRUTH_ANDIF_EXPR, + boolean_type_node, cond, + convert (boolean_type_node, se->expr)); + } + + gfc_free_ss_chain (ss); } @@ -8541,13 +8561,18 @@ gfc_conv_intrinsic_transfer (gfc_se * se, gfc_expr * expr) } else { + bool simply_contiguous = gfc_is_simply_contiguous (arg->expr, + false, true); argse.want_pointer = 0; + /* A non-contiguous SOURCE needs packing. */ + if (!simply_contiguous) + argse.force_tmp = 1; gfc_conv_expr_descriptor (&argse, arg->expr); source = gfc_conv_descriptor_data_get (argse.expr); source_type = gfc_get_element_type (TREE_TYPE (argse.expr)); /* Repack the source if not simply contiguous. */ - if (!gfc_is_simply_contiguous (arg->expr, false, true)) + if (!simply_contiguous) { tmp = gfc_build_addr_expr (NULL_TREE, argse.expr); diff --git a/gcc/lra-constraints.cc b/gcc/lra-constraints.cc index 0cc9b3dbcb27..ed0fdcab14e4 100644 --- a/gcc/lra-constraints.cc +++ b/gcc/lra-constraints.cc @@ -522,6 +522,11 @@ update_equiv (int regno) { rtx x; + /* If REGNO is beyond the length of the equivalence array structure, + then there's nothing to update. */ + if (regno >= ira_reg_equiv_len) + return; + if ((x = ira_reg_equiv[regno].memory) != NULL_RTX) ira_reg_equiv[regno].memory = simplify_replace_fn_rtx (x, NULL_RTX, loc_equivalence_callback, diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 89f374afaf80..b0478074412c 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,145 @@ +2025-11-04 Nathaniel Shead + + Backported from master: + 2025-11-04 Nathaniel Shead + + PR c++/122253 + * g++.dg/modules/internal-16.C: New test. + +2025-11-03 Jeff Law + + Backported from master: + 2025-11-01 Jeff Law + + PR rtl-optimization/122321 + * gcc.target/riscv/rvv/autovec/pr122321.c: New test. + +2025-11-03 Andrew Pinski + + Backported from master: + 2025-10-26 Andrew Pinski + + PR target/122270 + * gcc.target/riscv/rvv/base/pr122270-1.c: New test. + +2025-11-02 Nathaniel Shead + + Backported from master: + 2025-11-02 Nathaniel Shead + + PR c++/122421 + * g++.dg/modules/inst-6_a.C: New test. + * g++.dg/modules/inst-6_b.C: New test. + +2025-11-01 Harald Anlauf + + Backported from master: + 2025-10-25 Harald Anlauf + + PR fortran/114023 + * gfortran.dg/is_contiguous_5.f90: New test. + +2025-11-01 Harald Anlauf + + Backported from master: + 2025-10-24 Harald Anlauf + + PR fortran/122386 + * gfortran.dg/transfer_array_subref_2.f90: New test. + +2025-11-01 Nathaniel Shead + + Backported from master: + 2025-11-01 Nathaniel Shead + + PR c++/122381 + * g++.dg/modules/convop-2_a.H: New test. + * g++.dg/modules/convop-2_b.C: New test. + +2025-10-31 Tamar Christina + + Backported from master: + 2025-10-27 Tamar Christina + + PR tree-optimization/122408 + * gfortran.target/aarch64/pr122408_1.f90: New test. + * gfortran.target/aarch64/pr122408_2.f90: New test. + +2025-10-31 Jinyang He + + Backported from master: + 2025-10-30 Jinyang He + Peng Fan + + * gcc.target/loongarch/conditional-move-opt-1.c: Remove mul. + * gcc.target/loongarch/conditional-move-opt-2.c: Remove and. + * gcc.target/loongarch/conditional-move-opt-3.c: New test. + +2025-10-30 Guo Jie + + Backported from master: + 2025-10-30 Guo Jie + + * gcc.target/loongarch/fnmam4-vec.c: New test. + +2025-10-28 Patrick Palka + + Backported from master: + 2025-10-14 Patrick Palka + + PR c++/122192 + * g++.dg/template/dependent-base6.C: Verify mem-initializer-id + qualified name lookup is type-only too. + +2025-10-28 Patrick Palka + + Backported from master: + 2025-10-10 Patrick Palka + + PR c++/122192 + * g++.dg/template/dependent-base6.C: New test. + +2025-10-28 Nathaniel Shead + + Backported from master: + 2025-10-27 Nathaniel Shead + + PR c++/122310 + * g++.dg/modules/lambda-12.h: New test. + * g++.dg/modules/lambda-12_a.H: New test. + * g++.dg/modules/lambda-12_b.C: New test. + +2025-10-27 Jakub Jelinek + + PR tree-optimization/122394 + * g++.dg/opt/pr122394.C: New test. + +2025-10-27 Jeff Law + + Backported from master: + 2025-10-13 Jeff Law + + PR target/120674 + * gcc.target/riscv/pr120674.c: New test. + +2025-10-27 Tamar Christina + + Backported from master: + 2025-10-17 Tamar Christina + Jennifer Schmitz + + PR target/121604 + * gcc.target/aarch64/sve/pr121604_brk.c: New test. + * gcc.target/aarch64/sve2/pr121604_pmov.c: New test. + +2025-10-27 H.J. Lu + + Backported from master: + 2025-10-27 H.J. Lu + + PR target/122323 + * gcc.target/i386/builtin-copysign-8b.c: Add -mtune=generic. + 2025-10-26 Alexandre Oliva Backported from master: diff --git a/gcc/testsuite/g++.dg/modules/convop-2_a.H b/gcc/testsuite/g++.dg/modules/convop-2_a.H new file mode 100644 index 000000000000..62bb2101f691 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/convop-2_a.H @@ -0,0 +1,10 @@ +// PR c++/122381 +// { dg-additional-options "-fmodule-header" } +// { dg-module-cmi {} } + +template struct color_ref { + operator int() const { return 0; } + int foo(color_ref x) { + return x.operator int(); + } +}; diff --git a/gcc/testsuite/g++.dg/modules/convop-2_b.C b/gcc/testsuite/g++.dg/modules/convop-2_b.C new file mode 100644 index 000000000000..d1e829ec70ca --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/convop-2_b.C @@ -0,0 +1,5 @@ +// PR c++/122381 +// { dg-additional-options "-fmodules" } + +import "convop-2_a.H"; +template struct color_ref; diff --git a/gcc/testsuite/g++.dg/modules/inst-6_a.C b/gcc/testsuite/g++.dg/modules/inst-6_a.C new file mode 100644 index 000000000000..7f35cc161bfc --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/inst-6_a.C @@ -0,0 +1,14 @@ +// PR c++/122421 +// { dg-additional-options "-fmodules" } +// { dg-module-cmi M } + +export module M; + +export template struct Type { + static const int arr[3]; +}; + +extern template const int Type::arr[3]; +template const int Type::arr[] = { 42, 43, 44 }; + +export Type ti; diff --git a/gcc/testsuite/g++.dg/modules/inst-6_b.C b/gcc/testsuite/g++.dg/modules/inst-6_b.C new file mode 100644 index 000000000000..5a8092ccb148 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/inst-6_b.C @@ -0,0 +1,12 @@ +// PR c++/122421 +// { dg-additional-options "-fmodules" } + +import M; + +int main() { + const int& a = Type::arr[0]; + const int& b = Type::arr[0]; +} + +// { dg-final { scan-assembler {_ZNW1M4TypeIiE3arrE:} } } +// { dg-final { scan-assembler-not {_ZNW1M4TypeIdE3arrE:} } } diff --git a/gcc/testsuite/g++.dg/modules/internal-16.C b/gcc/testsuite/g++.dg/modules/internal-16.C new file mode 100644 index 000000000000..4a928ae801bb --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/internal-16.C @@ -0,0 +1,30 @@ +// PR c++/122253 +// { dg-additional-options "-fmodules -Wtemplate-names-tu-local" } + +export module M; + +template struct ic {}; +struct S { + constexpr operator int() const { return 5; } + constexpr int operator&() const { return 8; } +}; + +template inline void a(T) { + T a; + static T b; + ic{}; + ic{}; + ic<&a>{}; + ic<&b>{}; +} + +template inline auto b(T x) { + return [&](auto y) { + return [=](auto z) { + return ic<(int)x + (int)&y + (int)z>{}; + }; + }; +} + +template void a(S); +ic<5 + 8 + 5> x = b(S{})(S{})(S{}); diff --git a/gcc/testsuite/g++.dg/modules/lambda-12.h b/gcc/testsuite/g++.dg/modules/lambda-12.h new file mode 100644 index 000000000000..4dd329d47605 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/lambda-12.h @@ -0,0 +1,27 @@ +// PR c++/122310 +struct Foo { + constexpr static inline auto do_nothing = [](auto && ...){}; + using TNothing = decltype(do_nothing); +}; + +template +struct X { + struct Inner { + union MoreInner { + static constexpr auto x = []{}; +#if __cplusplus >= 202002L + static decltype([]{}) y; +#endif + }; + }; + + using A = decltype(Inner::MoreInner::x); +#if __cplusplus >= 202002L + using B = decltype(Inner::MoreInner::y); +#endif +}; + +inline X::A* a{}; +#if __cplusplus >= 202002L +inline X::B* b{}; +#endif diff --git a/gcc/testsuite/g++.dg/modules/lambda-12_a.H b/gcc/testsuite/g++.dg/modules/lambda-12_a.H new file mode 100644 index 000000000000..83f5d150367f --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/lambda-12_a.H @@ -0,0 +1,5 @@ +// PR c++/122310 +// { dg-additional-options "-fmodule-header" } +// { dg-module-cmi {} } + +#include "lambda-12.h" diff --git a/gcc/testsuite/g++.dg/modules/lambda-12_b.C b/gcc/testsuite/g++.dg/modules/lambda-12_b.C new file mode 100644 index 000000000000..c24d9398a45d --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/lambda-12_b.C @@ -0,0 +1,5 @@ +// PR c++/122310 +// { dg-additional-options "-fmodules -fno-module-lazy" } + +#include "lambda-12.h" +import "lambda-12_a.H"; diff --git a/gcc/testsuite/g++.dg/opt/pr122394.C b/gcc/testsuite/g++.dg/opt/pr122394.C new file mode 100644 index 000000000000..1f84bebd74c2 --- /dev/null +++ b/gcc/testsuite/g++.dg/opt/pr122394.C @@ -0,0 +1,20 @@ +// PR tree-optimization/122394 +// { dg-do compile { target c++23 } } +// { dg-options "-O1 -g" } + +#include + +struct A { + friend auto operator<=> (A, A) = default; + double a; +}; +void foo (); +A b, c; + +void +bar () +{ + bool d = c >= b; + if (d) + foo (); +} diff --git a/gcc/testsuite/g++.dg/template/dependent-base6.C b/gcc/testsuite/g++.dg/template/dependent-base6.C new file mode 100644 index 000000000000..9f2a7a23923f --- /dev/null +++ b/gcc/testsuite/g++.dg/template/dependent-base6.C @@ -0,0 +1,14 @@ +// PR c++/122192 +// Verify name lookup within a base-specifier is type-only. + +struct A { + int B; + struct B { }; +}; + +struct S1 : A::B { }; // OK + +template struct S2 : T::B { // OK, used to fail + S2() : T::B() { } // Also OK +}; +template struct S2; diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pr121604_brk.c b/gcc/testsuite/gcc.target/aarch64/sve/pr121604_brk.c new file mode 100644 index 000000000000..a474a20554d3 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/pr121604_brk.c @@ -0,0 +1,25 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-final { check-function-bodies "**" "" "" } } */ + +#include + +/* +** foo: +** ptrue p0\.b, all +** brkb p0\.b, p0/z, p0\.b +** ret +*/ +svbool_t foo () { + return svbrkb_b_m (svpfalse (), svptrue_b8 (), svptrue_b8 ()); +} + +/* +** bar: +** ptrue p0\.b, all +** brka p0\.b, p0/z, p0\.b +** ret +*/ +svbool_t bar () { + return svbrka_b_m (svpfalse (), svptrue_b8 (), svptrue_b8 ()); +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve2/pr121604_pmov.c b/gcc/testsuite/gcc.target/aarch64/sve2/pr121604_pmov.c new file mode 100644 index 000000000000..16844ee4add3 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve2/pr121604_pmov.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -march=armv8.2-a+sve2p1" } */ +/* { dg-final { check-function-bodies "**" "" "" } } */ + +#include + +/* +** f: +** pfalse p([0-7]+)\.b +** mov z0\.b, #-1 +** pmov z0\[1\], p\1\.d +** ret +*/ +svuint64_t f () { + return svpmov_lane_u64_m (svdup_u64 (~0UL), svpfalse (), 1); +} diff --git a/gcc/testsuite/gcc.target/i386/builtin-copysign-8b.c b/gcc/testsuite/gcc.target/i386/builtin-copysign-8b.c index 8f0cb27a2464..dc9e46121de0 100644 --- a/gcc/testsuite/gcc.target/i386/builtin-copysign-8b.c +++ b/gcc/testsuite/gcc.target/i386/builtin-copysign-8b.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -mno-avx512f -mavx" } */ +/* { dg-options "-O2 -mno-avx512f -mavx -mtune=generic" } */ /* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */ /* { dg-final { check-function-bodies "**" "" "" { target { ! ia32 } } {^\t?\.} } } */ diff --git a/gcc/testsuite/gcc.target/loongarch/conditional-move-opt-1.c b/gcc/testsuite/gcc.target/loongarch/conditional-move-opt-1.c index ed13471aa90a..47802aa9688d 100644 --- a/gcc/testsuite/gcc.target/loongarch/conditional-move-opt-1.c +++ b/gcc/testsuite/gcc.target/loongarch/conditional-move-opt-1.c @@ -27,7 +27,7 @@ void test_lt () { if (lm < ln) - lr *= (1 << 16); + lr += (1 << 16); lr += lm; } @@ -35,7 +35,7 @@ void test_le () { if (lm <= ln) - lr = lm * ((long)1 << 32); + lr = lm + ((long)1 << 32); else lr = lm; lr += lm; diff --git a/gcc/testsuite/gcc.target/loongarch/conditional-move-opt-2.c b/gcc/testsuite/gcc.target/loongarch/conditional-move-opt-2.c index ac72d4d933ad..743fd5e670e2 100644 --- a/gcc/testsuite/gcc.target/loongarch/conditional-move-opt-2.c +++ b/gcc/testsuite/gcc.target/loongarch/conditional-move-opt-2.c @@ -29,7 +29,7 @@ void test_lez () { if (lm <= 0) - lr &= (1 << 16); + lr |= (1 << 16); lr += lm; } diff --git a/gcc/testsuite/gcc.target/loongarch/conditional-move-opt-3.c b/gcc/testsuite/gcc.target/loongarch/conditional-move-opt-3.c new file mode 100644 index 000000000000..95887980cc5f --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/conditional-move-opt-3.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-final { scan-assembler "maskeqz" } } */ +/* { dg-final { scan-assembler "masknez" } } */ + +extern long lm, ln, lr; + +void +test_and () +{ + if (lm < 0) + lr &= (1 << 16); + lr += lm; +} diff --git a/gcc/testsuite/gcc.target/loongarch/fnmam4-vec.c b/gcc/testsuite/gcc.target/loongarch/fnmam4-vec.c new file mode 100644 index 000000000000..09693039deb3 --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/fnmam4-vec.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-Ofast -mlasx -ftree-vectorize" } */ +/* { dg-require-effective-target loongarch_asx } */ + +void +foo (float *u, float x, float *y, float z) +{ + int i; + for (i = 0; i < 1024; i++) + *(u++) = (x - y[i] * z); +} + +/* { dg-final { scan-assembler-not "\tvori.b"} } */ +/* { dg-final { scan-assembler-not "\txvori.b"} } */ diff --git a/gcc/testsuite/gcc.target/riscv/pr120674.c b/gcc/testsuite/gcc.target/riscv/pr120674.c new file mode 100644 index 000000000000..ec8835feb24d --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/pr120674.c @@ -0,0 +1,6 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-g -w -march=rv32gcv -mabi=ilp32" { target rv32 } } */ +/* { dg-additional-options "-g -w -march=rv64gcv -mabi=lp64d" { target rv64 } } */ + +#pragma riscv intrinsic "vector" +void GB_AxB_saxpy5_unrolled_rvv() { vfloat64m8_t vc; } diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr122321.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr122321.c new file mode 100644 index 000000000000..0e34bc1f1f5a --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr122321.c @@ -0,0 +1,150 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv -mabi=lp64d -w -O0" { target rv64 } } */ +/* { dg-options "-march=rv32gcv -mabi=ilp32 -w -O0" { target rv32 } } */ + + +typedef int a; +typedef signed char b; +typedef char c; +typedef short d; +typedef unsigned short e; +typedef a f; +typedef unsigned g; +typedef long h; +h j, k, l, m, n, o; +int p, q, r, s; +short t; +volatile a u; +a v[]; +char w, x; +a *y, *z; +a **aa; +__attribute__((always_inline)) b __attribute__((vector_size(16))) +ab(f __attribute__((vector_size(8 * sizeof(f)))), d ac, + d __attribute__((vector_size(2 * sizeof(d)))), d) { + return __builtin_shufflevector( + (b __attribute__((vector_size(16)))) __builtin_convertvector( + (d __attribute__((vector_size(16 *sizeof(d))))){ + ac, ac, ac, ac, ac, ac, ac, ac, ac, ac, ac, ac, ac}, + c __attribute__((vector_size(16)))) | + __builtin_convertvector( + (d __attribute__((vector_size(16 *sizeof(d))))){ + ac, ac, ac, ac, ac, ac, ac, ac, ac, ac, ac, ac, ac}, + c __attribute__((vector_size(16)))), + __builtin_convertvector( + (d __attribute__((vector_size(16 *sizeof(d))))){ + ac, ac, ac, ac, ac, ac, ac, ac, ac, ac, ac, ac, ac}, + b __attribute__((vector_size(16)))), + 3, 21, 0, 2, 2, 7, 1, 8, 4, 0, 8, 0, 8, 9, 5, 6); +} +__attribute__((always_inline)) g +ad(d ae, h __attribute__((vector_size(32 * sizeof(h))))) { + g f = 6318; + return (8 ? ae / 786856318u : 0) & ae; +} +a(af)(a, int); +void(ag)(long); +char(ah)(char, char); +char(ai)(char); +short(aj)(short, short); +int ak(long, int *, int *, char, int); +void al(signed, a *, int *, long); +char am(int *, short, short); +void an(int *, long, int); +void ao(int, int *, a *); +a ap() { + int *aq, *ar, *as; + short at; + char au, av, aw = 2; + long ax, ay, az = j; + int ba, i; + g __attribute__((vector_size(16 * sizeof(g)))) bb = {80}; + b __attribute__((vector_size(4))) bc = {6}; + int bd[1]; + char *be = &w; + int bf, bg = q; + a **bh[] = { + &y, &z, &z, &y, &y, &y, &y, &y, &z, &z, &y, &z, &y, &y, &y, &y, &z, &y, + &z, &y, &y, &y, &z, &z, &z, &y, &z, &z, &z, &y, &z, &z, &y, &z, &z, &y, + &z, &z, &z, &y, 0, &z, 0, &y, 0, &y, &y, &z, &z, &y, &y, 0, &z, 0, + &z, 0, &y, &z, &z, 0, &z, 0, &z, &z, &z, &y, &z, &z, &y, &z, &z, &y, + 0, &z, 0, &z, &z, &y, 0, &z, 0, &y, 0, &y, &y, &z, &z, &y, &y, 0, + &z, 0, &z, 0, &y, &z, &z, 0, &z, 0, &z, &z, &z, &y, &z, &z, &y, &z, + &z, &y, 0, &z, 0, &z, &z, &y, 0, &z, 0, &y, 0, &y, &y, &z, &z, &y, + &y, 0, &z, 0, &z, 0, &y, &z, &z, 0, &z, 0, &z, &z, &z, &y, &z, &z, + &y, &z, &z, &y, 0, &z, 0, &z, &z, &y, 0, &z, 0, &y, 0, &y, &y, &z, + &z, &y, &y, 0, &z, 0, &z, 0, &y, &z, &z, 0, 0, &z, 0, &z, &z, &z, + &y, &z, &z, &y, &z, &z, &y, 0, &z, 0, 0, &z, &z}; + for (; i; i++) + bd[i] = p; + h __attribute__((vector_size(32 * sizeof(h)))) + bi = {2681, 2681, 2681, 2681, 2681, 2681, 2681, 2681, 2681, 2681, 2681, + 2681, 2681, 2681, 2681, 2681, 2681, 2681, 2681, 2681, 2681, 2681, + 2681, 2681, 2681, 2681, 2681, 2681, 2681, 2681, 2681, 2681}, + bj = __builtin_convertvector( + (c __attribute__((vector_size(32)))){ + aw, aw, aw, aw, aw, aw, aw, aw, aw, aw, aw, aw, aw, aw, aw, aw, + aw, aw, aw, aw, aw, aw, aw, aw, aw, aw, aw, aw, aw, aw, aw, aw}, + h __attribute__((vector_size(32 * sizeof(h))))), + bk = __builtin_convertvector( + __builtin_shufflevector(bb, bb, 4, 8, 7, 9, 1, 10, 4, 7, 0, 4, 3, 5, 6, 7, + 6, 2, 2, 20, 6, 4, 7, 7, 9, 7, 4, 9, 8, 6, 1, 0, + 6, 9), + h __attribute__((vector_size(32 * sizeof(h))))); + bb = __builtin_convertvector( + ab(__builtin_shufflevector( + __builtin_shufflevector( + __builtin_convertvector( + __builtin_shufflevector(bb, bb, 1, 31, 8, 2, 3, 7, 4, 0, 7, + 3, 4, 6, 7, 1, 9, 3, 8, 7, 1, 8, 5, + 3, 9, 9, 0, 3, 2, 8, 5, 2, 5, 3), + f __attribute__((vector_size(32 * sizeof(f))))), + (f __attribute__((vector_size(32 * sizeof(f))))){ + 800761418310502961587690471176286910032020044212442466872080013589354162852207417903424527024812447907811618435019152886919380169872910001752451018659493155196043018716516518746289614523948734758456011127254301274351182132760058399143431214610613191313926994549901191890929084305862034120561651877003645}, + 32, 44), + (f __attribute__((vector_size(2 * sizeof(f))))){o}, 1, 0, 3, 0, 2, + 1, 3, 3), + ad(__builtin_clzg((g)aw, (f)bb[9]), + (h __attribute__((vector_size(32 * sizeof(h))))){ + bi[0] ?: bk[0], bi[1] ? 1 : bk[1], bi[2] ? 2 : bk[2], + bi[3] ? 3 : bk[3], bi[4] ? 4 : bk[4], bi[5] ? 5 : bk[5], + bi[6] ? 6 : bk[6], bi[7] ? 7 : bk[7], bi[8] ? 8 : bk[8], + bi[9] ? 9 : bk[9], bi[0] ? 10 : bk[0], bi[1] ? 1 : bk[1], + bi[2] ? 2 : bk[2], bi[3] ? 3 : bk[3], bi[4] ? 4 : bk[4], + bi[5] ? 5 : bk[5], bi[6] ? 6 : bk[6], bi[7] ? 7 : bk[7], + bi[8] ? 8 : bk[8], bi[9] ? 9 : bk[9], bi[0] ? 20 : bk[0], + bi[1] ? 1 : bk[1], bi[2] ? 2 : bk[2], bi[3] ? 3 : bk[3], + bi[4] ? bj[4] : 4, bi[5] ?: 5, bi[6] ?: 6, + bi[7] ? 0 : 7, bi[8] ?: 8, bi[9] ? 0 : 9, + bi[0] ? 0 : 30, bi[1] ?: 1}), + (d __attribute__((vector_size(2 * sizeof(d))))) + __builtin_shufflevector( + __builtin_convertvector( + __builtin_shufflevector(bb, bb, 2, 7, 21, 6), + e __attribute__((vector_size(4 * sizeof(e))))), + __builtin_convertvector( + (c __attribute__((vector_size(4)))){aw, aw}, + e __attribute__((vector_size(4 * sizeof(e))))), + 5, 1) + + (__builtin_convertvector( + __builtin_shufflevector(bb, bb, 4, 5), + e __attribute__((vector_size(2 * sizeof(e))))) <= + __builtin_convertvector( + (c __attribute__((vector_size(2)))){aw}, + e __attribute__((vector_size(2 * sizeof(e)))))), + n ? bb[5] << n : aw), + g __attribute__((vector_size(16 * sizeof(g))))); + ag(aw & t); + at = aj(aw, v[1]); + au = ah(at, aw); + ba = af((1 == ax != aw) <= aw <= au, aw); + ao(0, &bd[0], &r); + o = ay; + an(aq, aw, k); + av = am(ar, l, k); + *be = ai(*be); + al(x, as, &bd[0], aw); + bg = ak(u, &s, &bf, aw, aw); + as = *aa; + return m; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/pr122270-1.c b/gcc/testsuite/gcc.target/riscv/rvv/base/pr122270-1.c new file mode 100644 index 000000000000..a026a7e16d7e --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/pr122270-1.c @@ -0,0 +1,10 @@ +/* { dg-options "" } */ +/* { dg-do compile } */ +/* { dg-add-options riscv_v } */ +/* PR target/122270 */ + +#include "riscv_vector.h" + +void a(vfloat32m1_t b, vfloat32m1x4_t *c) { + *c = __riscv_vset_v_f32m1_f32m1x4(*c, 3, b); +} diff --git a/gcc/testsuite/gfortran.dg/is_contiguous_5.f90 b/gcc/testsuite/gfortran.dg/is_contiguous_5.f90 new file mode 100644 index 000000000000..091e43b55c2d --- /dev/null +++ b/gcc/testsuite/gfortran.dg/is_contiguous_5.f90 @@ -0,0 +1,126 @@ +! { dg-do run } +! PR fortran/114023 - IS_CONTIGUOUS and pointers to non-contiguous targets +! +! Based on testcase by Federico Perini + +program main + implicit none + complex, parameter :: cvals(*) = [(1,-1),(2,-2),(3,-3)] + complex , target :: cref(size(cvals)) = cvals ! Reference + complex, allocatable, target :: carr(:) ! Test + + type cx + real :: re, im + end type cx + type(cx), parameter :: tvals(*) = [cx(1,-1),cx(2,-2),cx(3,-3)] + real, parameter :: expect(*) = tvals% re + type(cx) , target :: tref(size(cvals)) = tvals ! Reference + type(cx), allocatable, target :: tarr(:) + + real, pointer :: rr1(:), rr2(:), rr3(:), rr4(:) + class(*), pointer :: cp1(:), cp2(:), cp3(:), cp4(:) + + carr = cvals + tarr = tvals + + if (any (expect /= [1,2,3])) error stop 90 + + ! REAL pointer to non-contiguous effective target + rr1(1:3) => cref%re + rr2 => cref%re + rr3(1:3) => carr%re + rr4 => carr%re + + if (is_contiguous (rr1)) stop 1 + if (my_contiguous_real (rr1)) stop 2 + if (is_contiguous (cref(1:3)%re)) stop 3 +! if (my_contiguous_real (cref(1:3)%re)) stop 4 ! pr122397 + + if (is_contiguous (rr3)) stop 6 + if (my_contiguous_real (rr3)) stop 7 + if (is_contiguous (carr(1:3)%re)) stop 8 +! if (my_contiguous_real (carr(1:3)%re)) stop 9 + + if (is_contiguous (rr2)) stop 11 + if (my_contiguous_real (rr2)) stop 12 + if (is_contiguous (cref%re)) stop 13 +! if (my_contiguous_real (cref%re)) stop 14 + + if (is_contiguous (rr4)) stop 16 + if (my_contiguous_real (rr4)) stop 17 + if (is_contiguous (carr%re)) stop 18 +! if (my_contiguous_real (carr%re)) stop 19 + + rr1(1:3) => tref%re + rr2 => tref%re + rr3(1:3) => tarr%re + rr4 => tarr%re + + if (is_contiguous (rr1)) stop 21 + if (my_contiguous_real (rr1)) stop 22 + if (is_contiguous (tref(1:3)%re)) stop 23 +! if (my_contiguous_real (tref(1:3)%re)) stop 24 + + if (is_contiguous (rr3)) stop 26 + if (my_contiguous_real (rr3)) stop 27 + if (is_contiguous (tarr(1:3)%re)) stop 28 +! if (my_contiguous_real (tarr(1:3)%re)) stop 29 + + if (is_contiguous (rr2)) stop 31 + if (my_contiguous_real (rr2)) stop 32 + if (is_contiguous (tref%re)) stop 33 +! if (my_contiguous_real (tref%re)) stop 34 + + if (is_contiguous (rr4)) stop 36 + if (my_contiguous_real (rr4)) stop 37 + if (is_contiguous (tarr%re)) stop 38 +! if (my_contiguous_real (tarr%re)) stop 39 + + ! Unlimited polymorphic pointer to non-contiguous effective target + cp1(1:3) => cref%re + cp2 => cref%re + cp3(1:3) => carr%re + cp4 => carr%re + + if (is_contiguous (cp1)) stop 41 + if (my_contiguous_poly (cp1)) stop 42 + if (is_contiguous (cp2)) stop 43 + if (my_contiguous_poly (cp2)) stop 44 + if (is_contiguous (cp3)) stop 45 + if (my_contiguous_poly (cp3)) stop 46 + if (is_contiguous (cp4)) stop 47 + if (my_contiguous_poly (cp4)) stop 48 + + cp1(1:3) => tref%re + cp2 => tref%re + cp3(1:3) => tarr%re + cp4 => tarr%re + + if (is_contiguous (cp1)) stop 51 + if (my_contiguous_poly (cp1)) stop 52 + if (is_contiguous (cp2)) stop 53 + if (my_contiguous_poly (cp2)) stop 54 + if (is_contiguous (cp3)) stop 55 + if (my_contiguous_poly (cp3)) stop 56 + if (is_contiguous (cp4)) stop 57 + if (my_contiguous_poly (cp4)) stop 58 + + deallocate (carr, tarr) +contains + pure logical function my_contiguous_real (x) result (res) + real, pointer, intent(in) :: x(:) + res = is_contiguous (x) + if (any (x /= expect)) error stop 97 + end function my_contiguous_real + + pure logical function my_contiguous_poly (x) result (res) + class(*), pointer, intent(in) :: x(:) + res = is_contiguous (x) + select type (x) + type is (real) + if (any (x /= expect)) error stop 98 + class default + error stop 99 + end select + end function my_contiguous_poly +end diff --git a/gcc/testsuite/gfortran.dg/transfer_array_subref_2.f90 b/gcc/testsuite/gfortran.dg/transfer_array_subref_2.f90 new file mode 100644 index 000000000000..9ff519866dc8 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/transfer_array_subref_2.f90 @@ -0,0 +1,52 @@ +! { dg-do run } +! { dg-additional-options "-O2 -fdump-tree-optimized" } +! +! PR fortran/122386 - passing of component ref of nested DT array to TRANSFER + +program main + implicit none + integer, parameter :: dp = 4 + + type cx + real(dp) :: re, im + end type cx + + type complex_wrap1 + type(cx) :: z(2) + end type complex_wrap1 + + type complex_wrap2 + type(cx), dimension(:), allocatable :: z + end type complex_wrap2 + + type(complex_wrap1) :: x = complex_wrap1([cx(1,2), cx(3,4)]) + type(complex_wrap2) :: w + + w%z = x%z + + ! The following statements should get optimized away... + if (size (transfer ( x%z%re ,[1.0_dp])) /= 2) error stop 1 + if (size (transfer ((x%z%re),[1.0_dp])) /= 2) error stop 2 + if (size (transfer ([x%z%re],[1.0_dp])) /= 2) error stop 3 + if (size (transfer ( x%z%im ,[1.0_dp])) /= 2) error stop 4 + if (size (transfer ((x%z%im),[1.0_dp])) /= 2) error stop 5 + if (size (transfer ([x%z%im],[1.0_dp])) /= 2) error stop 6 + + ! ... while the following may not: + if (any (transfer ( x%z%re ,[1.0_dp]) /= x%z%re)) stop 7 + if (any (transfer ( x%z%im ,[1.0_dp]) /= x%z%im)) stop 8 + + if (size (transfer ( w%z%re ,[1.0_dp])) /= 2) stop 11 + if (size (transfer ((w%z%re),[1.0_dp])) /= 2) stop 12 + if (size (transfer ([w%z%re],[1.0_dp])) /= 2) stop 13 + if (size (transfer ( w%z%im ,[1.0_dp])) /= 2) stop 14 + if (size (transfer ((w%z%im),[1.0_dp])) /= 2) stop 15 + if (size (transfer ([w%z%im],[1.0_dp])) /= 2) stop 16 + + if (any (transfer ( w%z%re ,[1.0_dp]) /= x%z%re)) stop 17 + if (any (transfer ( w%z%im ,[1.0_dp]) /= x%z%im)) stop 18 + + deallocate (w%z) +end program main + +! { dg-final { scan-tree-dump-not "_gfortran_error_stop_numeric" "optimized" } } diff --git a/gcc/testsuite/gfortran.target/aarch64/pr122408_1.f90 b/gcc/testsuite/gfortran.target/aarch64/pr122408_1.f90 new file mode 100644 index 000000000000..8a3416231ff1 --- /dev/null +++ b/gcc/testsuite/gfortran.target/aarch64/pr122408_1.f90 @@ -0,0 +1,61 @@ +! { dg-do compile } +! { dg-additional-options "-O2 -march=armv8.3-a" } + +subroutine c_add_ab(n, a, c, b) ! C += A * B + use iso_fortran_env, only: real64 + implicit none + !GCC$ ATTRIBUTES noinline :: c_add_ab + integer, intent(in) :: n + complex(real64), intent(in) :: a + complex(real64), intent(inout) :: c(*) + complex(real64), intent(in) :: b(*) + integer :: k + do k = 1, n + c(k) = c(k) + a * b(k) + end do +end subroutine c_add_ab + +subroutine c_sub_ab(n, a, c, b) ! C -= A * B + use iso_fortran_env, only: real64 + implicit none + !GCC$ ATTRIBUTES noinline :: c_sub_ab + integer, intent(in) :: n + complex(real64), intent(in) :: a + complex(real64), intent(inout) :: c(*) + complex(real64), intent(in) :: b(*) + integer :: k + do k = 1, n + c(k) = c(k) - a * b(k) + end do +end subroutine c_sub_ab + +subroutine c_add_a_conjb(n, a, c, b) ! C += A * conj(B) + use iso_fortran_env, only: real64 + implicit none + !GCC$ ATTRIBUTES noinline :: c_add_a_conjb + integer, intent(in) :: n + complex(real64), intent(in) :: a + complex(real64), intent(inout) :: c(*) + complex(real64), intent(in) :: b(*) + integer :: k + do k = 1, n + c(k) = c(k) + a * conjg(b(k)) + end do +end subroutine c_add_a_conjb + +subroutine c_sub_a_conjb(n, a, c, b) ! C -= A * conj(B) + use iso_fortran_env, only: real64 + implicit none + !GCC$ ATTRIBUTES noinline :: c_sub_a_conjb + integer, intent(in) :: n + complex(real64), intent(in) :: a + complex(real64), intent(inout) :: c(*) + complex(real64), intent(in) :: b(*) + integer :: k + do k = 1, n + c(k) = c(k) - a * conjg(b(k)) + end do +end subroutine c_sub_a_conjb + +! { dg-final { scan-assembler-times {fcmla\s+v[0-9]+.2d, v[0-9]+.2d, v[0-9]+.2d, #0} 2 } } +! { dg-final { scan-assembler-times {fcmla\s+v[0-9]+.2d, v[0-9]+.2d, v[0-9]+.2d, #270} 2 } } diff --git a/gcc/testsuite/gfortran.target/aarch64/pr122408_2.f90 b/gcc/testsuite/gfortran.target/aarch64/pr122408_2.f90 new file mode 100644 index 000000000000..feb6dc14af8a --- /dev/null +++ b/gcc/testsuite/gfortran.target/aarch64/pr122408_2.f90 @@ -0,0 +1,140 @@ +! { dg-do run } +! { dg-additional-options "-O2" } +! { dg-additional-options "-O2 -march=armv8.3-a" { target arm_v8_3a_complex_neon_hw } } + +module util + use iso_fortran_env, only: real64, int64 + implicit none +contains + pure logical function bitwise_eq(x, y) + complex(real64), intent(in) :: x, y + integer(int64) :: xr, xi, yr, yi + xr = transfer(real(x,kind=real64), 0_int64) + xi = transfer(aimag(x), 0_int64) + yr = transfer(real(y,kind=real64), 0_int64) + yi = transfer(aimag(y), 0_int64) + bitwise_eq = (xr == yr) .and. (xi == yi) + end function bitwise_eq + + subroutine check_equal(tag, got, ref, nfail) + character(*), intent(in) :: tag + complex(real64), intent(in) :: got(:), ref(:) + integer, intent(inout) :: nfail + integer :: i + do i = 1, size(got) + if (.not. bitwise_eq(got(i), ref(i))) then + nfail = nfail + 1 + write(*,'(A,": mismatch at i=",I0, " got=",2ES16.8," ref=",2ES16.8)') & + trim(tag), i, real(got(i)), aimag(got(i)), real(ref(i)), aimag(ref(i)) + end if + end do + end subroutine check_equal +end module util + +module fcmla_ops + use iso_fortran_env, only: real64 + implicit none +contains + subroutine c_add_ab(n, a, c, b) ! C += A * B + !GCC$ ATTRIBUTES noinline :: c_add_ab + integer, intent(in) :: n + complex(real64), intent(in) :: a + complex(real64), intent(inout) :: c(*) + complex(real64), intent(in) :: b(*) + integer :: k + do k = 1, n + c(k) = c(k) + a * b(k) + end do + end subroutine c_add_ab + + subroutine c_sub_ab(n, a, c, b) ! C -= A * B + !GCC$ ATTRIBUTES noinline :: c_sub_ab + integer, intent(in) :: n + complex(real64), intent(in) :: a + complex(real64), intent(inout) :: c(*) + complex(real64), intent(in) :: b(*) + integer :: k + do k = 1, n + c(k) = c(k) - a * b(k) + end do + end subroutine c_sub_ab + + subroutine c_add_a_conjb(n, a, c, b) ! C += A * conj(B) + !GCC$ ATTRIBUTES noinline :: c_add_a_conjb + integer, intent(in) :: n + complex(real64), intent(in) :: a + complex(real64), intent(inout) :: c(*) + complex(real64), intent(in) :: b(*) + integer :: k + do k = 1, n + c(k) = c(k) + a * conjg(b(k)) + end do + end subroutine c_add_a_conjb + + subroutine c_sub_a_conjb(n, a, c, b) ! C -= A * conj(B) + !GCC$ ATTRIBUTES noinline :: c_sub_a_conjb + integer, intent(in) :: n + complex(real64), intent(in) :: a + complex(real64), intent(inout) :: c(*) + complex(real64), intent(in) :: b(*) + integer :: k + do k = 1, n + c(k) = c(k) - a * conjg(b(k)) + end do + end subroutine c_sub_a_conjb +end module fcmla_ops + +program fcmla_accum_pairs + use iso_fortran_env, only: real64 + use util + use fcmla_ops + implicit none + + integer, parameter :: n = 4 + complex(real64) :: a, b(n), c0(n) + complex(real64) :: c_add_ab_got(n), c_add_ab_ref(n) + complex(real64) :: c_sub_ab_got(n), c_sub_ab_ref(n) + complex(real64) :: c_add_conjb_got(n), c_add_conjb_ref(n) + complex(real64) :: c_sub_conjb_got(n), c_sub_conjb_ref(n) + integer :: i, fails + + ! Constants (include a signed-zero lane) + a = cmplx( 2.0_real64, -3.0_real64, kind=real64) + b(1) = cmplx( 1.5_real64, -2.0_real64, kind=real64) + b(2) = cmplx(-4.0_real64, 5.0_real64, kind=real64) + b(3) = cmplx(-0.0_real64, 0.0_real64, kind=real64) + b(4) = cmplx( 0.25_real64, 3.0_real64, kind=real64) + + c0(1) = cmplx( 1.0_real64, -2.0_real64, kind=real64) + c0(2) = cmplx( 3.0_real64, -4.0_real64, kind=real64) + c0(3) = cmplx(-5.0_real64, 6.0_real64, kind=real64) + c0(4) = cmplx( 0.0_real64, 0.0_real64, kind=real64) + + ! Run each form + c_add_ab_got = c0; call c_add_ab (n, a, c_add_ab_got, b) + c_sub_ab_got = c0; call c_sub_ab (n, a, c_sub_ab_got, b) + c_add_conjb_got = c0; call c_add_a_conjb(n, a, c_add_conjb_got, b) + c_sub_conjb_got = c0; call c_sub_a_conjb(n, a, c_sub_conjb_got, b) + + ! Scalar references + do i = 1, n + c_add_ab_ref(i) = c0(i) + a * b(i) + c_sub_ab_ref(i) = c0(i) - a * b(i) + c_add_conjb_ref(i) = c0(i) + a * conjg(b(i)) + c_sub_conjb_ref(i) = c0(i) - a * conjg(b(i)) + end do + + ! Bitwise checks + fails = 0 + call check_equal("C += A*B ", c_add_ab_got, c_add_ab_ref, fails) + call check_equal("C -= A*B ", c_sub_ab_got, c_sub_ab_ref, fails) + call check_equal("C += A*conj(B) ", c_add_conjb_got, c_add_conjb_ref, fails) + call check_equal("C -= A*conj(B) ", c_sub_conjb_got, c_sub_conjb_ref, fails) + + if (fails == 0) then + stop 0 + else + stop 1 + end if +end program fcmla_accum_pairs + diff --git a/gcc/tree-ssa-phiopt.cc b/gcc/tree-ssa-phiopt.cc index aaebae6b38c0..3e0ad9d3bb09 100644 --- a/gcc/tree-ssa-phiopt.cc +++ b/gcc/tree-ssa-phiopt.cc @@ -2995,10 +2995,8 @@ spaceship_replacement (basic_block cond_bb, basic_block middle_bb, if (has_cast_debug_uses || (HONOR_NANS (TREE_TYPE (lhs1)) && !is_cast)) { - tree temp3 = make_node (DEBUG_EXPR_DECL); - DECL_ARTIFICIAL (temp3) = 1; - TREE_TYPE (temp3) = TREE_TYPE (orig_use_lhs); - SET_DECL_MODE (temp3, TYPE_MODE (type)); + tree temp3 + = build_debug_expr_decl (TREE_TYPE (orig_use_lhs)); if (has_cast_debug_uses) t = fold_convert (TREE_TYPE (temp3), temp2); else diff --git a/gcc/tree-vect-slp-patterns.cc b/gcc/tree-vect-slp-patterns.cc index c0dff90d9baf..cebd9aa1c13c 100644 --- a/gcc/tree-vect-slp-patterns.cc +++ b/gcc/tree-vect-slp-patterns.cc @@ -847,15 +847,23 @@ compatible_complex_nodes_p (slp_compat_nodes_map_t *compat_cache, return true; } + +/* Check to see if the oprands to two multiplies, 2 each in LEFT_OP and + RIGHT_OP match a complex multiplication or complex multiply-and-accumulate + or complex multiply-and-subtract pattern. Do this using the permute cache + PERM_CACHE and the combination compatibility list COMPAT_CACHE. If + the operation is successful the macthing operands are returned in OPS and + _STATUS indicates if the operation matched includes a conjugate of one of the + operands. If the operation succeeds True is returned, otherwise False and + the values in ops are meaningless. */ static inline bool vect_validate_multiplication (slp_tree_to_load_perm_map_t *perm_cache, slp_compat_nodes_map_t *compat_cache, - vec &left_op, - vec &right_op, - bool subtract, + const vec &left_op, + const vec &right_op, + bool subtract, vec &ops, enum _conj_status *_status) { - auto_vec ops; enum _conj_status stats = CONJ_NONE; /* The complex operations can occur in two layouts and two permute sequences @@ -886,31 +894,31 @@ vect_validate_multiplication (slp_tree_to_load_perm_map_t *perm_cache, bool neg0 = vect_match_expression_p (right_op[0], NEGATE_EXPR); bool neg1 = vect_match_expression_p (right_op[1], NEGATE_EXPR); + /* Create the combined inputs after remapping and flattening. */ + ops.create (4); + ops.safe_splice (left_op); + ops.safe_splice (right_op); + /* Determine which style we're looking at. We only have different ones whenever a conjugate is involved. */ if (neg0 && neg1) ; else if (neg0) { - right_op[0] = SLP_TREE_CHILDREN (right_op[0])[0]; + ops[2] = SLP_TREE_CHILDREN (right_op[0])[0]; stats = CONJ_FST; if (subtract) perm = 0; } else if (neg1) { - right_op[1] = SLP_TREE_CHILDREN (right_op[1])[0]; + ops[3] = SLP_TREE_CHILDREN (right_op[1])[0]; stats = CONJ_SND; perm = 1; } *_status = stats; - /* Flatten the inputs after we've remapped them. */ - ops.create (4); - ops.safe_splice (left_op); - ops.safe_splice (right_op); - /* Extract out the elements to check. */ slp_tree op0 = ops[styles[style][0]]; slp_tree op1 = ops[styles[style][1]]; @@ -1073,15 +1081,16 @@ complex_mul_pattern::matches (complex_operation_t op, return IFN_LAST; enum _conj_status status; + auto_vec res_ops; if (!vect_validate_multiplication (perm_cache, compat_cache, left_op, - right_op, false, &status)) + right_op, false, res_ops, &status)) { /* Try swapping the order and re-trying since multiplication is commutative. */ std::swap (left_op[0], left_op[1]); std::swap (right_op[0], right_op[1]); if (!vect_validate_multiplication (perm_cache, compat_cache, left_op, - right_op, false, &status)) + right_op, false, res_ops, &status)) return IFN_LAST; } @@ -1109,24 +1118,24 @@ complex_mul_pattern::matches (complex_operation_t op, if (add0) ops->quick_push (add0); - complex_perm_kinds_t kind = linear_loads_p (perm_cache, left_op[0]); + complex_perm_kinds_t kind = linear_loads_p (perm_cache, res_ops[0]); if (kind == PERM_EVENODD || kind == PERM_TOP) { - ops->quick_push (left_op[1]); - ops->quick_push (right_op[1]); - ops->quick_push (left_op[0]); + ops->quick_push (res_ops[1]); + ops->quick_push (res_ops[3]); + ops->quick_push (res_ops[0]); } else if (kind == PERM_EVENEVEN && status != CONJ_SND) { - ops->quick_push (left_op[0]); - ops->quick_push (right_op[0]); - ops->quick_push (left_op[1]); + ops->quick_push (res_ops[0]); + ops->quick_push (res_ops[2]); + ops->quick_push (res_ops[1]); } else { - ops->quick_push (left_op[0]); - ops->quick_push (right_op[1]); - ops->quick_push (left_op[1]); + ops->quick_push (res_ops[0]); + ops->quick_push (res_ops[3]); + ops->quick_push (res_ops[1]); } return ifn; @@ -1298,15 +1307,17 @@ complex_fms_pattern::matches (complex_operation_t op, return IFN_LAST; enum _conj_status status; + auto_vec res_ops; if (!vect_validate_multiplication (perm_cache, compat_cache, right_op, - left_op, true, &status)) + left_op, true, res_ops, &status)) { /* Try swapping the order and re-trying since multiplication is commutative. */ std::swap (left_op[0], left_op[1]); std::swap (right_op[0], right_op[1]); + auto_vec res_ops; if (!vect_validate_multiplication (perm_cache, compat_cache, right_op, - left_op, true, &status)) + left_op, true, res_ops, &status)) return IFN_LAST; } @@ -1321,20 +1332,20 @@ complex_fms_pattern::matches (complex_operation_t op, ops->truncate (0); ops->create (4); - complex_perm_kinds_t kind = linear_loads_p (perm_cache, right_op[0]); + complex_perm_kinds_t kind = linear_loads_p (perm_cache, res_ops[2]); if (kind == PERM_EVENODD) { ops->quick_push (l0node[0]); - ops->quick_push (right_op[0]); - ops->quick_push (right_op[1]); - ops->quick_push (left_op[1]); + ops->quick_push (res_ops[2]); + ops->quick_push (res_ops[3]); + ops->quick_push (res_ops[1]); } else { ops->quick_push (l0node[0]); - ops->quick_push (right_op[1]); - ops->quick_push (right_op[0]); - ops->quick_push (left_op[0]); + ops->quick_push (res_ops[3]); + ops->quick_push (res_ops[2]); + ops->quick_push (res_ops[0]); } return ifn;