mirror of git://gcc.gnu.org/git/gcc.git
[3/3][RTL ifcvt] PR middle-end/37780: Conditional expression with __builtin_clz() should be optimized out
PR middle-end/37780 * ifcvt.c (noce_try_ifelse_collapse): New function. Declare prototype. (noce_process_if_block): Call noce_try_ifelse_collapse. * simplify-rtx.c (simplify_cond_clz_ctz): New function. (simplify_ternary_operation): Use the above to simplify conditional CLZ/CTZ expressions. * gcc.c-torture/execute/pr37780.c: New test. * gcc.target/aarch64/pr37780_1.c: Likewise. * gcc.target/arm/pr37780_1.c: Likewise. From-SVN: r237141
This commit is contained in:
parent
e8536e2b9f
commit
36f9ad6933
|
|
@ -1,3 +1,13 @@
|
||||||
|
2016-06-06 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
|
||||||
|
|
||||||
|
PR middle-end/37780
|
||||||
|
* ifcvt.c (noce_try_ifelse_collapse): New function.
|
||||||
|
Declare prototype.
|
||||||
|
(noce_process_if_block): Call noce_try_ifelse_collapse.
|
||||||
|
* simplify-rtx.c (simplify_cond_clz_ctz): New function.
|
||||||
|
(simplify_ternary_operation): Use the above to simplify
|
||||||
|
conditional CLZ/CTZ expressions.
|
||||||
|
|
||||||
2016-06-06 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
|
2016-06-06 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
|
||||||
|
|
||||||
PR middle-end/37780
|
PR middle-end/37780
|
||||||
|
|
|
||||||
34
gcc/ifcvt.c
34
gcc/ifcvt.c
|
|
@ -817,6 +817,7 @@ struct noce_if_info
|
||||||
|
|
||||||
static rtx noce_emit_store_flag (struct noce_if_info *, rtx, int, int);
|
static rtx noce_emit_store_flag (struct noce_if_info *, rtx, int, int);
|
||||||
static int noce_try_move (struct noce_if_info *);
|
static int noce_try_move (struct noce_if_info *);
|
||||||
|
static int noce_try_ifelse_collapse (struct noce_if_info *);
|
||||||
static int noce_try_store_flag (struct noce_if_info *);
|
static int noce_try_store_flag (struct noce_if_info *);
|
||||||
static int noce_try_addcc (struct noce_if_info *);
|
static int noce_try_addcc (struct noce_if_info *);
|
||||||
static int noce_try_store_flag_constants (struct noce_if_info *);
|
static int noce_try_store_flag_constants (struct noce_if_info *);
|
||||||
|
|
@ -1120,6 +1121,37 @@ noce_try_move (struct noce_if_info *if_info)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Try forming an IF_THEN_ELSE (cond, b, a) and collapsing that
|
||||||
|
through simplify_rtx. Sometimes that can eliminate the IF_THEN_ELSE.
|
||||||
|
If that is the case, emit the result into x. */
|
||||||
|
|
||||||
|
static int
|
||||||
|
noce_try_ifelse_collapse (struct noce_if_info * if_info)
|
||||||
|
{
|
||||||
|
if (!noce_simple_bbs (if_info))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
machine_mode mode = GET_MODE (if_info->x);
|
||||||
|
rtx if_then_else = simplify_gen_ternary (IF_THEN_ELSE, mode, mode,
|
||||||
|
if_info->cond, if_info->b,
|
||||||
|
if_info->a);
|
||||||
|
|
||||||
|
if (GET_CODE (if_then_else) == IF_THEN_ELSE)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
rtx_insn *seq;
|
||||||
|
start_sequence ();
|
||||||
|
noce_emit_move_insn (if_info->x, if_then_else);
|
||||||
|
seq = end_ifcvt_sequence (if_info);
|
||||||
|
if (!seq)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
emit_insn_before_setloc (seq, if_info->jump,
|
||||||
|
INSN_LOCATION (if_info->insn_a));
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Convert "if (test) x = 1; else x = 0".
|
/* Convert "if (test) x = 1; else x = 0".
|
||||||
|
|
||||||
Only try 0 and STORE_FLAG_VALUE here. Other combinations will be
|
Only try 0 and STORE_FLAG_VALUE here. Other combinations will be
|
||||||
|
|
@ -3497,6 +3529,8 @@ noce_process_if_block (struct noce_if_info *if_info)
|
||||||
|
|
||||||
if (noce_try_move (if_info))
|
if (noce_try_move (if_info))
|
||||||
goto success;
|
goto success;
|
||||||
|
if (noce_try_ifelse_collapse (if_info))
|
||||||
|
goto success;
|
||||||
if (noce_try_store_flag (if_info))
|
if (noce_try_store_flag (if_info))
|
||||||
goto success;
|
goto success;
|
||||||
if (noce_try_bitop (if_info))
|
if (noce_try_bitop (if_info))
|
||||||
|
|
|
||||||
|
|
@ -5267,6 +5267,49 @@ simplify_const_relational_operation (enum rtx_code code,
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Recognize expressions of the form (X CMP 0) ? VAL : OP (X)
|
||||||
|
where OP is CLZ or CTZ and VAL is the value from CLZ_DEFINED_VALUE_AT_ZERO
|
||||||
|
or CTZ_DEFINED_VALUE_AT_ZERO respectively and return OP (X) if the expression
|
||||||
|
can be simplified to that or NULL_RTX if not.
|
||||||
|
Assume X is compared against zero with CMP_CODE and the true
|
||||||
|
arm is TRUE_VAL and the false arm is FALSE_VAL. */
|
||||||
|
|
||||||
|
static rtx
|
||||||
|
simplify_cond_clz_ctz (rtx x, rtx_code cmp_code, rtx true_val, rtx false_val)
|
||||||
|
{
|
||||||
|
if (cmp_code != EQ && cmp_code != NE)
|
||||||
|
return NULL_RTX;
|
||||||
|
|
||||||
|
/* Result on X == 0 and X !=0 respectively. */
|
||||||
|
rtx on_zero, on_nonzero;
|
||||||
|
if (cmp_code == EQ)
|
||||||
|
{
|
||||||
|
on_zero = true_val;
|
||||||
|
on_nonzero = false_val;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
on_zero = false_val;
|
||||||
|
on_nonzero = true_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
rtx_code op_code = GET_CODE (on_nonzero);
|
||||||
|
if ((op_code != CLZ && op_code != CTZ)
|
||||||
|
|| !rtx_equal_p (XEXP (on_nonzero, 0), x)
|
||||||
|
|| !CONST_INT_P (on_zero))
|
||||||
|
return NULL_RTX;
|
||||||
|
|
||||||
|
HOST_WIDE_INT op_val;
|
||||||
|
machine_mode mode = GET_MODE (on_nonzero);
|
||||||
|
if (((op_code == CLZ && CLZ_DEFINED_VALUE_AT_ZERO (mode, op_val))
|
||||||
|
|| (op_code == CTZ && CTZ_DEFINED_VALUE_AT_ZERO (mode, op_val)))
|
||||||
|
&& op_val == INTVAL (on_zero))
|
||||||
|
return on_nonzero;
|
||||||
|
|
||||||
|
return NULL_RTX;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Simplify CODE, an operation with result mode MODE and three operands,
|
/* Simplify CODE, an operation with result mode MODE and three operands,
|
||||||
OP0, OP1, and OP2. OP0_MODE was the mode of OP0 before it became
|
OP0, OP1, and OP2. OP0_MODE was the mode of OP0 before it became
|
||||||
|
|
@ -5400,6 +5443,19 @@ simplify_ternary_operation (enum rtx_code code, machine_mode mode,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Convert x == 0 ? N : clz (x) into clz (x) when
|
||||||
|
CLZ_DEFINED_VALUE_AT_ZERO is defined to N for the mode of x.
|
||||||
|
Similarly for ctz (x). */
|
||||||
|
if (COMPARISON_P (op0) && !side_effects_p (op0)
|
||||||
|
&& XEXP (op0, 1) == const0_rtx)
|
||||||
|
{
|
||||||
|
rtx simplified
|
||||||
|
= simplify_cond_clz_ctz (XEXP (op0, 0), GET_CODE (op0),
|
||||||
|
op1, op2);
|
||||||
|
if (simplified)
|
||||||
|
return simplified;
|
||||||
|
}
|
||||||
|
|
||||||
if (COMPARISON_P (op0) && ! side_effects_p (op0))
|
if (COMPARISON_P (op0) && ! side_effects_p (op0))
|
||||||
{
|
{
|
||||||
machine_mode cmp_mode = (GET_MODE (XEXP (op0, 0)) == VOIDmode
|
machine_mode cmp_mode = (GET_MODE (XEXP (op0, 0)) == VOIDmode
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,10 @@
|
||||||
|
2016-06-06 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
|
||||||
|
|
||||||
|
PR middle-end/37780
|
||||||
|
* gcc.c-torture/execute/pr37780.c: New test.
|
||||||
|
* gcc.target/aarch64/pr37780_1.c: Likewise.
|
||||||
|
* gcc.target/arm/pr37780_1.c: Likewise.
|
||||||
|
|
||||||
2016-06-06 Marek Polacek <polacek@redhat.com>
|
2016-06-06 Marek Polacek <polacek@redhat.com>
|
||||||
|
|
||||||
* c-c++-common/attr-may-alias-1.c: New test.
|
* c-c++-common/attr-may-alias-1.c: New test.
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
/* PR middle-end/37780. */
|
||||||
|
|
||||||
|
#define VAL (8 * sizeof (int))
|
||||||
|
|
||||||
|
int __attribute__ ((noinline, noclone))
|
||||||
|
fooctz (int i)
|
||||||
|
{
|
||||||
|
return (i == 0) ? VAL : __builtin_ctz (i);
|
||||||
|
}
|
||||||
|
|
||||||
|
int __attribute__ ((noinline, noclone))
|
||||||
|
fooctz2 (int i)
|
||||||
|
{
|
||||||
|
return (i != 0) ? __builtin_ctz (i) : VAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int __attribute__ ((noinline, noclone))
|
||||||
|
fooctz3 (unsigned int i)
|
||||||
|
{
|
||||||
|
return (i > 0) ? __builtin_ctz (i) : VAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int __attribute__ ((noinline, noclone))
|
||||||
|
fooclz (int i)
|
||||||
|
{
|
||||||
|
return (i == 0) ? VAL : __builtin_clz (i);
|
||||||
|
}
|
||||||
|
|
||||||
|
int __attribute__ ((noinline, noclone))
|
||||||
|
fooclz2 (int i)
|
||||||
|
{
|
||||||
|
return (i != 0) ? __builtin_clz (i) : VAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int __attribute__ ((noinline, noclone))
|
||||||
|
fooclz3 (unsigned int i)
|
||||||
|
{
|
||||||
|
return (i > 0) ? __builtin_clz (i) : VAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main (void)
|
||||||
|
{
|
||||||
|
if (fooctz (0) != VAL || fooctz2 (0) != VAL || fooctz3 (0) != VAL
|
||||||
|
|| fooclz (0) != VAL || fooclz2 (0) != VAL || fooclz3 (0) != VAL)
|
||||||
|
__builtin_abort ();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
/* Test that we can remove the conditional move due to CLZ
|
||||||
|
and CTZ being defined at zero. */
|
||||||
|
|
||||||
|
/* { dg-do compile } */
|
||||||
|
/* { dg-options "-O2" } */
|
||||||
|
|
||||||
|
int
|
||||||
|
fooctz (int i)
|
||||||
|
{
|
||||||
|
return (i == 0) ? 32 : __builtin_ctz (i);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
fooctz2 (int i)
|
||||||
|
{
|
||||||
|
return (i != 0) ? __builtin_ctz (i) : 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int
|
||||||
|
fooctz3 (unsigned int i)
|
||||||
|
{
|
||||||
|
return (i > 0) ? __builtin_ctz (i) : 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* { dg-final { scan-assembler-times "rbit\t*" 3 } } */
|
||||||
|
|
||||||
|
int
|
||||||
|
fooclz (int i)
|
||||||
|
{
|
||||||
|
return (i == 0) ? 32 : __builtin_clz (i);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
fooclz2 (int i)
|
||||||
|
{
|
||||||
|
return (i != 0) ? __builtin_clz (i) : 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int
|
||||||
|
fooclz3 (unsigned int i)
|
||||||
|
{
|
||||||
|
return (i > 0) ? __builtin_clz (i) : 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* { dg-final { scan-assembler-times "clz\t" 6 } } */
|
||||||
|
/* { dg-final { scan-assembler-not "cmp\t.*0" } } */
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
/* Test that we can remove the conditional move due to CLZ
|
||||||
|
being defined at zero. */
|
||||||
|
|
||||||
|
/* { dg-do compile } */
|
||||||
|
/* { dg-require-effective-target arm_arch_v5_ok } */
|
||||||
|
/* { dg-options "-O2" } */
|
||||||
|
|
||||||
|
int
|
||||||
|
fooctz (int i)
|
||||||
|
{
|
||||||
|
return (i == 0) ? 32 : __builtin_ctz (i);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
fooctz2 (int i)
|
||||||
|
{
|
||||||
|
return (i != 0) ? __builtin_ctz (i) : 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int
|
||||||
|
fooctz3 (unsigned int i)
|
||||||
|
{
|
||||||
|
return (i > 0) ? __builtin_ctz (i) : 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* { dg-final { scan-assembler-times "rbit\t*" 3 } } */
|
||||||
|
|
||||||
|
int
|
||||||
|
fooclz (int i)
|
||||||
|
{
|
||||||
|
return (i == 0) ? 32 : __builtin_clz (i);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
fooclz2 (int i)
|
||||||
|
{
|
||||||
|
return (i != 0) ? __builtin_clz (i) : 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int
|
||||||
|
fooclz3 (unsigned int i)
|
||||||
|
{
|
||||||
|
return (i > 0) ? __builtin_clz (i) : 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* { dg-final { scan-assembler-times "clz\t" 6 } } */
|
||||||
|
/* { dg-final { scan-assembler-not "cmp\t.*0" } } */
|
||||||
Loading…
Reference in New Issue