Commit d7840b47 by Kyrylo Tkachov Committed by Michael Collison

compare-elim.c: Include emit-rtl.h.

2017-10-14  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>
	    Michael Collison <michael.collison@arm.com>

	* compare-elim.c: Include emit-rtl.h.
	(can_merge_compare_into_arith): New function.
	(try_validate_parallel): Likewise.
	(try_merge_compare): Likewise.
	(try_eliminate_compare): Call the above when no previous clobber
	is available.
	(execute_compare_elim_after_reload): Add DF_UD_CHAIN and DF_DU_CHAIN
	dataflow problems.

2017-10-14  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>
	    Michael Collison <michael.collison@arm.com>

	* gcc.target/aarch64/cmpelim_mult_uses_1.c: New test.


Co-Authored-By: Michael Collison <michael.collison@arm.com>

From-SVN: r253764
parent c97b789c
2017-10-14 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
Michael Collison <michael.collison@arm.com>
* compare-elim.c: Include emit-rtl.h.
(can_merge_compare_into_arith): New function.
(try_validate_parallel): Likewise.
(try_merge_compare): Likewise.
(try_eliminate_compare): Call the above when no previous clobber
is available.
(execute_compare_elim_after_reload): Add DF_UD_CHAIN and DF_DU_CHAIN
dataflow problems.
2017-10-14 Jakub Jelinek <jakub@redhat.com>
PR middle-end/62263
......@@ -65,6 +65,7 @@ along with GCC; see the file COPYING3. If not see
#include "tm_p.h"
#include "insn-config.h"
#include "recog.h"
#include "emit-rtl.h"
#include "cfgrtl.h"
#include "tree-pass.h"
#include "domwalk.h"
......@@ -579,6 +580,143 @@ equivalent_reg_at_start (rtx reg, rtx_insn *end, rtx_insn *start)
return reg;
}
/* Return true if it is okay to merge the comparison CMP_INSN with
the instruction ARITH_INSN. Both instructions are assumed to be in the
same basic block with ARITH_INSN appearing before CMP_INSN. This checks
that there are no uses or defs of the condition flags or control flow
changes between the two instructions. */
static bool
can_merge_compare_into_arith (rtx_insn *cmp_insn, rtx_insn *arith_insn)
{
for (rtx_insn *insn = PREV_INSN (cmp_insn);
insn && insn != arith_insn;
insn = PREV_INSN (insn))
{
if (!NONDEBUG_INSN_P (insn))
continue;
/* Bail if there are jumps or calls in between. */
if (!NONJUMP_INSN_P (insn))
return false;
/* Bail on old-style asm statements because they lack
data flow information. */
if (GET_CODE (PATTERN (insn)) == ASM_INPUT)
return false;
df_ref ref;
/* Find a USE of the flags register. */
FOR_EACH_INSN_USE (ref, insn)
if (DF_REF_REGNO (ref) == targetm.flags_regnum)
return false;
/* Find a DEF of the flags register. */
FOR_EACH_INSN_DEF (ref, insn)
if (DF_REF_REGNO (ref) == targetm.flags_regnum)
return false;
}
return true;
}
/* Given two SET expressions, SET_A and SET_B determine whether they form
a recognizable pattern when emitted in parallel. Return that parallel
if so. Otherwise return NULL. */
static rtx
try_validate_parallel (rtx set_a, rtx set_b)
{
rtx par
= gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, set_a, set_b));
rtx_insn *insn;
insn = gen_rtx_INSN (VOIDmode, 0, 0, 0, par, 0, -1, 0);
return recog_memoized (insn) > 0 ? par : NULL_RTX;
}
/* For a comparison instruction described by CMP check if it compares a
register with zero i.e. it is of the form CC := CMP R1, 0.
If it is, find the instruction defining R1 (say I1) and try to create a
PARALLEL consisting of I1 and the comparison, representing a flag-setting
arithmetic instruction. Example:
I1: R1 := R2 + R3
<instructions that don't read the condition register>
I2: CC := CMP R1 0
I2 can be merged with I1 into:
I1: { R1 := R2 + R3 ; CC := CMP (R2 + R3) 0 }
This catches cases where R1 is used between I1 and I2 and therefore
combine and other RTL optimisations will not try to propagate it into
I2. Return true if we succeeded in merging CMP. */
static bool
try_merge_compare (struct comparison *cmp)
{
rtx_insn *cmp_insn = cmp->insn;
if (!REG_P (cmp->in_a) || cmp->in_b != const0_rtx)
return false;
rtx in_a = cmp->in_a;
df_ref use;
FOR_EACH_INSN_USE (use, cmp_insn)
if (DF_REF_REGNO (use) == REGNO (in_a))
break;
if (!use)
return false;
/* Validate the data flow information before attempting to
find the instruction that defines in_a. */
struct df_link *ref_chain;
ref_chain = DF_REF_CHAIN (use);
if (!ref_chain || !ref_chain->ref
|| !DF_REF_INSN_INFO (ref_chain->ref) || ref_chain->next != NULL)
return false;
rtx_insn *def_insn = DF_REF_INSN (ref_chain->ref);
/* We found the insn that defines in_a. Only consider the cases where
it is in the same block as the comparison. */
if (BLOCK_FOR_INSN (cmp_insn) != BLOCK_FOR_INSN (def_insn))
return false;
rtx set = single_set (def_insn);
if (!set)
return false;
if (!can_merge_compare_into_arith (cmp_insn, def_insn))
return false;
rtx src = SET_SRC (set);
rtx flags = maybe_select_cc_mode (cmp, src, CONST0_RTX (GET_MODE (src)));
if (!flags)
{
/* We may already have a change group going through maybe_select_cc_mode.
Discard it properly. */
cancel_changes (0);
return false;
}
rtx flag_set
= gen_rtx_SET (flags, gen_rtx_COMPARE (GET_MODE (flags),
copy_rtx (src),
CONST0_RTX (GET_MODE (src))));
rtx arith_set = copy_rtx (PATTERN (def_insn));
rtx par = try_validate_parallel (flag_set, arith_set);
if (!par)
{
/* We may already have a change group going through maybe_select_cc_mode.
Discard it properly. */
cancel_changes (0);
return false;
}
if (!apply_change_group ())
return false;
emit_insn_after (par, def_insn);
delete_insn (def_insn);
delete_insn (cmp->insn);
return true;
}
/* Attempt to replace a comparison with a prior arithmetic insn that can
compute the same flags value as the comparison itself. Return true if
successful, having made all rtl modifications necessary. */
......@@ -588,7 +726,9 @@ try_eliminate_compare (struct comparison *cmp)
{
rtx flags, in_a, in_b, cmp_src;
/* We must have found an interesting "clobber" preceding the compare. */
if (try_merge_compare (cmp))
return true;
if (cmp->prev_clobber == NULL)
return false;
......@@ -714,6 +854,7 @@ try_eliminate_compare (struct comparison *cmp)
static unsigned int
execute_compare_elim_after_reload (void)
{
df_chain_add_problem (DF_UD_CHAIN + DF_DU_CHAIN);
df_analyze ();
gcc_checking_assert (!all_compares.exists ());
......
2017-10-14 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
Michael Collison <michael.collison@arm.com>
* gcc.target/aarch64/cmpelim_mult_uses_1.c: New test.
2017-10-14 Paolo Carlini <paolo.carlini@oracle.com>
PR c++/80908
......
/* { dg-do compile } */
/* { dg-options "-O2" } */
/* X is both compared against zero and used. Make sure we can still
generate an ADDS and avoid an explicit comparison against zero. */
int
foo (int x, int y)
{
x += y;
if (x != 0)
x = x + 2;
return x;
}
/* { dg-final { scan-assembler-times "adds\\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+" 1 } } */
/* { dg-final { scan-assembler-not "cmp\\tw\[0-9\]+, 0" } } */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment