Bootstrapped and regtested on x86_64-redhat-linux, ppc64le-redhat-linux and s390x-redhat-linux. Ok for master?
v1: https://gcc.gnu.org/pipermail/gcc-patches/2021-March/566127.html v1 -> v2: Pass a set_info instead of a def_info around. Add single_nondebug_insn_use () - maybe this could be improved further? [1] Simplify def->insn ()->ebb (). Improve formatting. [1] https://gcc.gnu.org/pipermail/gcc-patches/2021-March/567118.html --- Commit efb6bc55a93a ("fwprop: Allow (subreg (mem)) simplifications") introduced a check that was supposed to look at the propagated def's number of uses. It uses insn_info::num_uses (), which in reality returns the number of uses def's insn has. The whole change therefore works only by accident. Fix by looking at set_info's uses instead of insn_info's uses. This requires passing around set_info instead of insn_info. gcc/ChangeLog: 2021-03-02 Ilya Leoshkevich <i...@linux.ibm.com> * fwprop.c (fwprop_propagation::fwprop_propagation): Look at set_info's uses. (try_fwprop_subst_note): Use set_info instead of insn_info. (try_fwprop_subst_pattern): Likewise. (try_fwprop_subst_notes): Likewise. (try_fwprop_subst): Likewise. (forward_propagate_subreg): Likewise. (forward_propagate_and_simplify): Likewise. (forward_propagate_into): Likewise. * rtl-ssa/accesses.h (set_info::single_nondebug_insn_use): New method. * rtl-ssa/member-fns.inl (set_info::single_nondebug_insn_use): Likewise. gcc/testsuite/ChangeLog: * gcc.target/s390/vector/long-double-asm-abi.c: New test. --- gcc/fwprop.c | 79 +++++++++---------- gcc/rtl-ssa/accesses.h | 4 + gcc/rtl-ssa/member-fns.inl | 9 +++ .../s390/vector/long-double-asm-abi.c | 26 ++++++ 4 files changed, 78 insertions(+), 40 deletions(-) create mode 100644 gcc/testsuite/gcc.target/s390/vector/long-double-asm-abi.c diff --git a/gcc/fwprop.c b/gcc/fwprop.c index 4b8a554e823..6173c9248eb 100644 --- a/gcc/fwprop.c +++ b/gcc/fwprop.c @@ -175,7 +175,7 @@ namespace static const uint16_t CONSTANT = FIRST_SPARE_RESULT << 1; static const uint16_t PROFITABLE = FIRST_SPARE_RESULT << 2; - fwprop_propagation (insn_info *, insn_info *, rtx, rtx); + fwprop_propagation (insn_info *, set_info *, rtx, rtx); bool changed_mem_p () const { return result_flags & CHANGED_MEM; } bool folded_to_constants_p () const; @@ -191,13 +191,13 @@ namespace }; } -/* Prepare to replace FROM with TO in INSN. */ +/* Prepare to replace FROM with TO in USE_INSN. */ fwprop_propagation::fwprop_propagation (insn_info *use_insn, - insn_info *def_insn, rtx from, rtx to) + set_info *def, rtx from, rtx to) : insn_propagation (use_insn->rtl (), from, to), - single_use_p (def_insn->num_uses () == 1), - single_ebb_p (use_insn->ebb () == def_insn->ebb ()) + single_use_p (def->single_nondebug_insn_use () && !def->has_phi_uses ()), + single_ebb_p (use_insn->ebb () == def->ebb ()) { should_check_mems = true; should_note_simplifications = true; @@ -368,9 +368,9 @@ contains_paradoxical_subreg_p (rtx x) return false; } -/* Try to substitute (set DEST SRC) from DEF_INSN into note NOTE of USE_INSN. - Return the number of substitutions on success, otherwise return -1 and - leave USE_INSN unchanged. +/* Try to substitute (set DEST SRC), which defines DEF, into note NOTE of + USE_INSN. Return the number of substitutions on success, otherwise return + -1 and leave USE_INSN unchanged. If REQUIRE_CONSTANT is true, require all substituted occurences of SRC to fold to a constant, so that the note does not use any more registers @@ -379,13 +379,14 @@ contains_paradoxical_subreg_p (rtx x) instruction pattern. */ static int -try_fwprop_subst_note (insn_info *use_insn, insn_info *def_insn, +try_fwprop_subst_note (insn_info *use_insn, set_info *def, rtx note, rtx dest, rtx src, bool require_constant) { rtx_insn *use_rtl = use_insn->rtl (); + insn_info *def_insn = def->insn (); insn_change_watermark watermark; - fwprop_propagation prop (use_insn, def_insn, dest, src); + fwprop_propagation prop (use_insn, def, dest, src); if (!prop.apply_to_rvalue (&XEXP (note, 0))) { if (dump_file && (dump_flags & TDF_DETAILS)) @@ -436,19 +437,20 @@ try_fwprop_subst_note (insn_info *use_insn, insn_info *def_insn, return prop.num_replacements; } -/* Try to substitute (set DEST SRC) from DEF_INSN into location LOC of +/* Try to substitute (set DEST SRC), which defines DEF, into location LOC of USE_INSN's pattern. Return true on success, otherwise leave USE_INSN unchanged. */ static bool try_fwprop_subst_pattern (obstack_watermark &attempt, insn_change &use_change, - insn_info *def_insn, rtx *loc, rtx dest, rtx src) + set_info *def, rtx *loc, rtx dest, rtx src) { insn_info *use_insn = use_change.insn (); rtx_insn *use_rtl = use_insn->rtl (); + insn_info *def_insn = def->insn (); insn_change_watermark watermark; - fwprop_propagation prop (use_insn, def_insn, dest, src); + fwprop_propagation prop (use_insn, def, dest, src); if (!prop.apply_to_pattern (loc)) { if (dump_file && (dump_flags & TDF_DETAILS)) @@ -538,8 +540,7 @@ try_fwprop_subst_pattern (obstack_watermark &attempt, insn_change &use_change, { if ((REG_NOTE_KIND (note) == REG_EQUAL || REG_NOTE_KIND (note) == REG_EQUIV) - && try_fwprop_subst_note (use_insn, def_insn, note, - dest, src, false) < 0) + && try_fwprop_subst_note (use_insn, def, note, dest, src, false) < 0) { *note_ptr = XEXP (note, 1); free_EXPR_LIST_node (note); @@ -554,20 +555,19 @@ try_fwprop_subst_pattern (obstack_watermark &attempt, insn_change &use_change, return true; } -/* Try to substitute (set DEST SRC) from DEF_INSN into USE_INSN's notes, +/* Try to substitute (set DEST SRC), which defines DEF, into USE_INSN's notes, given that it was not possible to do this for USE_INSN's main pattern. Return true on success, otherwise leave USE_INSN unchanged. */ static bool -try_fwprop_subst_notes (insn_info *use_insn, insn_info *def_insn, +try_fwprop_subst_notes (insn_info *use_insn, set_info *def, rtx dest, rtx src) { rtx_insn *use_rtl = use_insn->rtl (); for (rtx note = REG_NOTES (use_rtl); note; note = XEXP (note, 1)) if ((REG_NOTE_KIND (note) == REG_EQUAL || REG_NOTE_KIND (note) == REG_EQUIV) - && try_fwprop_subst_note (use_insn, def_insn, note, - dest, src, true) > 0) + && try_fwprop_subst_note (use_insn, def, note, dest, src, true) > 0) { confirm_change_group (); return true; @@ -576,7 +576,7 @@ try_fwprop_subst_notes (insn_info *use_insn, insn_info *def_insn, return false; } -/* Check whether we could validly substitute (set DEST SRC) from DEF_INSN +/* Check whether we could validly substitute (set DEST SRC), which defines DEF, into USE. If so, first try performing the substitution in location LOC of USE->insn ()'s pattern. If that fails, try instead to substitute into the notes. @@ -584,10 +584,11 @@ try_fwprop_subst_notes (insn_info *use_insn, insn_info *def_insn, Return true on success, otherwise leave USE_INSN unchanged. */ static bool -try_fwprop_subst (use_info *use, insn_info *def_insn, +try_fwprop_subst (use_info *use, set_info *def, rtx *loc, rtx dest, rtx src) { insn_info *use_insn = use->insn (); + insn_info *def_insn = def->insn (); auto attempt = crtl->ssa->new_change_attempt (); use_array src_uses = remove_note_accesses (attempt, def_insn->uses ()); @@ -622,9 +623,8 @@ try_fwprop_subst (use_info *use, insn_info *def_insn, if (!restrict_movement (use_change)) return false; - return (try_fwprop_subst_pattern (attempt, use_change, def_insn, - loc, dest, src) - || try_fwprop_subst_notes (use_insn, def_insn, dest, src)); + return (try_fwprop_subst_pattern (attempt, use_change, def, loc, dest, src) + || try_fwprop_subst_notes (use_insn, def, dest, src)); } /* For the given single_set INSN, containing SRC known to be a @@ -671,7 +671,7 @@ free_load_extend (rtx src, insn_info *insn) in REF. The other parameters are the same. */ static bool -forward_propagate_subreg (use_info *use, insn_info *def_insn, +forward_propagate_subreg (use_info *use, set_info *def, rtx dest, rtx src, df_ref ref) { scalar_int_mode int_use_mode, src_mode; @@ -697,8 +697,7 @@ forward_propagate_subreg (use_info *use, insn_info *def_insn, && REGNO (SUBREG_REG (src)) >= FIRST_PSEUDO_REGISTER && GET_MODE (SUBREG_REG (src)) == use_mode && subreg_lowpart_p (src)) - return try_fwprop_subst (use, def_insn, loc, - use_reg, SUBREG_REG (src)); + return try_fwprop_subst (use, def, loc, use_reg, SUBREG_REG (src)); } /* If this is a SUBREG of a ZERO_EXTEND or SIGN_EXTEND, and the SUBREG @@ -725,22 +724,21 @@ forward_propagate_subreg (use_info *use, insn_info *def_insn, && REG_P (XEXP (src, 0)) && REGNO (XEXP (src, 0)) >= FIRST_PSEUDO_REGISTER && GET_MODE (XEXP (src, 0)) == use_mode - && !free_load_extend (src, def_insn) + && !free_load_extend (src, def->insn ()) && (targetm.mode_rep_extended (int_use_mode, src_mode) != (int) GET_CODE (src))) - return try_fwprop_subst (use, def_insn, loc, use_reg, XEXP (src, 0)); + return try_fwprop_subst (use, def, loc, use_reg, XEXP (src, 0)); } return false; } -/* Try to substitute (set DEST SRC) from DEF_INSN into USE and simplify +/* Try to substitute (set DEST SRC), which defines DEF, into USE and simplify the result, handling cases where DEST is used in a subreg and where applying that subreg to SRC results in a useful simplification. */ static bool -forward_propagate_subreg (use_info *use, insn_info *def_insn, - rtx dest, rtx src) +forward_propagate_subreg (use_info *use, set_info *def, rtx dest, rtx src) { if (!use->includes_subregs () || !REG_P (dest)) return false; @@ -755,26 +753,27 @@ forward_propagate_subreg (use_info *use, insn_info *def_insn, FOR_EACH_INSN_USE (ref, use_rtl) if (DF_REF_REGNO (ref) == use->regno () - && forward_propagate_subreg (use, def_insn, dest, src, ref)) + && forward_propagate_subreg (use, def, dest, src, ref)) return true; FOR_EACH_INSN_EQ_USE (ref, use_rtl) if (DF_REF_REGNO (ref) == use->regno () - && forward_propagate_subreg (use, def_insn, dest, src, ref)) + && forward_propagate_subreg (use, def, dest, src, ref)) return true; return false; } -/* Try to substitute (set DEST SRC) from DEF_INSN into USE and +/* Try to substitute (set DEST SRC), which defines DEF, into USE and simplify the result. */ static bool -forward_propagate_and_simplify (use_info *use, insn_info *def_insn, +forward_propagate_and_simplify (use_info *use, set_info *def, rtx dest, rtx src) { insn_info *use_insn = use->insn (); rtx_insn *use_rtl = use_insn->rtl (); + insn_info *def_insn = def->insn (); /* ??? This check seems unnecessary. We should be able to propagate into any kind of instruction, regardless of whether it's a single set. @@ -820,7 +819,7 @@ forward_propagate_and_simplify (use_info *use, insn_info *def_insn, /* ??? Unconditionally propagating into PATTERN would work better for instructions that have match_dups. */ rtx *loc = need_single_set ? &use_set : &PATTERN (use_rtl); - return try_fwprop_subst (use, def_insn, loc, dest, src); + return try_fwprop_subst (use, def, loc, dest, src); } /* Given a use USE of an insn, if it has a single reaching @@ -836,7 +835,7 @@ forward_propagate_into (use_info *use, bool reg_prop_only = false) return false; /* Disregard uninitialized uses. */ - def_info *def = use->def (); + set_info *def = use->def (); if (!def) return false; @@ -880,8 +879,8 @@ forward_propagate_into (use_info *use, bool reg_prop_only = false) && find_reg_note (use_rtl, REG_NON_LOCAL_GOTO, NULL_RTX)) return false; - if (forward_propagate_and_simplify (use, def_insn, dest, src) - || forward_propagate_subreg (use, def_insn, dest, src)) + if (forward_propagate_and_simplify (use, def, dest, src) + || forward_propagate_subreg (use, def, dest, src)) return true; return false; diff --git a/gcc/rtl-ssa/accesses.h b/gcc/rtl-ssa/accesses.h index 09ae583f993..ae76162805d 100644 --- a/gcc/rtl-ssa/accesses.h +++ b/gcc/rtl-ssa/accesses.h @@ -705,6 +705,10 @@ public: // Return true if at least one phi node uses the set's result. bool has_phi_uses () const; + // If exactly one nondebug instruction uses the set's result, return + // the use by that instruction, otherwise return null. + use_info *single_nondebug_insn_use () const; + // Return true if the set and its uses are contained within a single // extended basic block, with the set coming first. This implies // that all uses are by instructions rather than phi nodes. diff --git a/gcc/rtl-ssa/member-fns.inl b/gcc/rtl-ssa/member-fns.inl index e1ab7d1ba84..37fffb050ff 100644 --- a/gcc/rtl-ssa/member-fns.inl +++ b/gcc/rtl-ssa/member-fns.inl @@ -250,6 +250,15 @@ set_info::has_phi_uses () const return m_first_use && m_first_use->last_use ()->is_in_phi (); } +inline use_info * +set_info::single_nondebug_insn_use () const +{ + use_info *first = first_nondebug_insn_use (); + if (first && !first->next_nondebug_insn_use ()) + return first; + return nullptr; +} + inline bool set_info::is_local_to_ebb () const { diff --git a/gcc/testsuite/gcc.target/s390/vector/long-double-asm-abi.c b/gcc/testsuite/gcc.target/s390/vector/long-double-asm-abi.c new file mode 100644 index 00000000000..f9f2d1286e2 --- /dev/null +++ b/gcc/testsuite/gcc.target/s390/vector/long-double-asm-abi.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -march=z14 -mzarch --save-temps" } */ +/* { dg-do run { target { s390_z14_hw } } } */ +#include <assert.h> +#include <stdint.h> + +__attribute__ ((noipa)) static long double +xsqrt (long double x) +{ + long double res; + asm("sqxbr\t%0,%1" : "=f"(res) : "f"(x)); + return res; +} + +/* Check that the generated code is very small and straightforward. In + particular, there must be no unnecessary copying and no stack frame. */ +/* { dg-final { scan-assembler {\n\tld\t[^\n]*\n\tld\t[^\n]*\n(#[^\n]*\n)*\tsqxbr\t.*\n(#[^\n]*\n)*\tstd\t[^\n]*\n\tstd\t[^\n]*\n\tbr\t%r14\n} } } */ + +int +main (void) +{ + long double res, x = 0x1.0000000000001p+0L, + exp = 1.00000000000000011102230246251564788e+0L; + res = xsqrt (x); + assert (res == exp); +} -- 2.29.2