fwprop: Fix single_use_p calculation
Commit efb6bc55a9
("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 <iii@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_use) New
method.
(set_info::single_nondebug_insn_use): Likewise.
(set_info::single_phi_use): Likewise.
* rtl-ssa/member-fns.inl (set_info::single_nondebug_use) New
method.
(set_info::single_nondebug_insn_use): Likewise.
(set_info::single_phi_use): Likewise.
gcc/testsuite/ChangeLog:
* gcc.target/s390/vector/long-double-asm-abi.c: New test.
This commit is contained in:
parent
d1aa5f57db
commit
b61461ac7f
81
gcc/fwprop.c
81
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_use ()),
|
||||
single_ebb_p (use_insn->ebb () == def->ebb ())
|
||||
{
|
||||
should_check_mems = true;
|
||||
should_note_simplifications = true;
|
||||
|
@ -368,24 +368,25 @@ 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
|
||||
If REQUIRE_CONSTANT is true, require all substituted occurrences of SRC
|
||||
to fold to a constant, so that the note does not use any more registers
|
||||
than it did previously. If REQUIRE_CONSTANT is false, also allow the
|
||||
substitution if it's something we'd normally allow for the main
|
||||
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;
|
||||
|
|
|
@ -705,6 +705,19 @@ public:
|
|||
// Return true if at least one phi node uses the set's result.
|
||||
bool has_phi_uses () const;
|
||||
|
||||
// If there is exactly one nondebug use of the set's result, return that use,
|
||||
// otherwise return null. The use might be in an instruction or in a phi
|
||||
// node.
|
||||
use_info *single_nondebug_use () 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;
|
||||
|
||||
// If exactly one phi node uses the set's result, return the use by that phi
|
||||
// node, otherwise return null.
|
||||
use_info *single_phi_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.
|
||||
|
|
|
@ -250,6 +250,34 @@ 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_use () const
|
||||
{
|
||||
if (!has_phi_uses ())
|
||||
return single_nondebug_insn_use ();
|
||||
if (!has_nondebug_insn_uses ())
|
||||
return single_phi_use ();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
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 use_info *
|
||||
set_info::single_phi_use () const
|
||||
{
|
||||
use_info *last = last_phi_use ();
|
||||
if (last && !last->prev_phi_use ())
|
||||
return last;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inline bool
|
||||
set_info::is_local_to_ebb () const
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
Loading…
Reference in New Issue