Commit 73049af5 by Jakub Jelinek Committed by Jakub Jelinek

re PR tree-optimization/63464 (compare one character to many: faster)

	PR tree-optimization/63464
	* gimple.h (gimple_seq_discard): New prototype.
	* gimple.c: Include stringpool.h and tree-ssanames.h.
	(gimple_seq_discard): New function.
	* optabs.h (lshift_cheap_p): New prototype.
	* optabs.c (lshift_cheap_p): New function, moved from...
	* tree-switch-conversion.c (lshift_cheap_p): ... here.
	* tree-ssa-reassoc.c: Include gimplify.h and optabs.h.
	(reassoc_branch_fixups): New variable.
	(update_range_test): Add otherrangep and seq arguments.
	Unshare exp.  If otherrange is NULL, use for other ranges
	array of pointers pointed by otherrangep instead.
	Emit seq before gimplified statements for tem.
	(optimize_range_tests_diff): Adjust update_range_test
	caller.
	(optimize_range_tests_xor): Likewise.  Fix up comment.
	(extract_bit_test_mask, optimize_range_tests_to_bit_test): New
	functions.
	(optimize_range_tests): Adjust update_range_test caller.
	Call optimize_range_tests_to_bit_test.
	(branch_fixup): New function.
	(execute_reassoc): Call branch_fixup.

	* gcc.dg/torture/pr63464.c: New test.
	* gcc.dg/tree-ssa/reassoc-37.c: New test.
	* gcc.dg/tree-ssa/reassoc-38.c: New test.

From-SVN: r216393
parent 4eb4a256
2014-10-17 Jakub Jelinek <jakub@redhat.com> 2014-10-17 Jakub Jelinek <jakub@redhat.com>
PR tree-optimization/63464
* gimple.h (gimple_seq_discard): New prototype.
* gimple.c: Include stringpool.h and tree-ssanames.h.
(gimple_seq_discard): New function.
* optabs.h (lshift_cheap_p): New prototype.
* optabs.c (lshift_cheap_p): New function, moved from...
* tree-switch-conversion.c (lshift_cheap_p): ... here.
* tree-ssa-reassoc.c: Include gimplify.h and optabs.h.
(reassoc_branch_fixups): New variable.
(update_range_test): Add otherrangep and seq arguments.
Unshare exp. If otherrange is NULL, use for other ranges
array of pointers pointed by otherrangep instead.
Emit seq before gimplified statements for tem.
(optimize_range_tests_diff): Adjust update_range_test
caller.
(optimize_range_tests_xor): Likewise. Fix up comment.
(extract_bit_test_mask, optimize_range_tests_to_bit_test): New
functions.
(optimize_range_tests): Adjust update_range_test caller.
Call optimize_range_tests_to_bit_test.
(branch_fixup): New function.
(execute_reassoc): Call branch_fixup.
PR tree-optimization/63302 PR tree-optimization/63302
* tree-ssa-reassoc.c (optimize_range_tests_xor, * tree-ssa-reassoc.c (optimize_range_tests_xor,
optimize_range_tests_diff): Use !integer_pow2p () instead of optimize_range_tests_diff): Use !integer_pow2p () instead of
...@@ -47,6 +47,8 @@ along with GCC; see the file COPYING3. If not see ...@@ -47,6 +47,8 @@ along with GCC; see the file COPYING3. If not see
#include "demangle.h" #include "demangle.h"
#include "langhooks.h" #include "langhooks.h"
#include "bitmap.h" #include "bitmap.h"
#include "stringpool.h"
#include "tree-ssanames.h"
/* All the tuples have their operand vector (if present) at the very bottom /* All the tuples have their operand vector (if present) at the very bottom
...@@ -2826,3 +2828,19 @@ gimple_seq_set_location (gimple_seq seq, location_t loc) ...@@ -2826,3 +2828,19 @@ gimple_seq_set_location (gimple_seq seq, location_t loc)
for (gimple_stmt_iterator i = gsi_start (seq); !gsi_end_p (i); gsi_next (&i)) for (gimple_stmt_iterator i = gsi_start (seq); !gsi_end_p (i); gsi_next (&i))
gimple_set_location (gsi_stmt (i), loc); gimple_set_location (gsi_stmt (i), loc);
} }
/* Release SSA_NAMEs in SEQ as well as the GIMPLE statements. */
void
gimple_seq_discard (gimple_seq seq)
{
gimple_stmt_iterator gsi;
for (gsi = gsi_start (seq); !gsi_end_p (gsi); )
{
gimple stmt = gsi_stmt (gsi);
gsi_remove (&gsi, true);
release_defs (stmt);
ggc_free (stmt);
}
}
...@@ -1269,9 +1269,10 @@ extern bool gimple_asm_clobbers_memory_p (const_gimple); ...@@ -1269,9 +1269,10 @@ extern bool gimple_asm_clobbers_memory_p (const_gimple);
extern void dump_decl_set (FILE *, bitmap); extern void dump_decl_set (FILE *, bitmap);
extern bool nonfreeing_call_p (gimple); extern bool nonfreeing_call_p (gimple);
extern bool infer_nonnull_range (gimple, tree, bool, bool); extern bool infer_nonnull_range (gimple, tree, bool, bool);
extern void sort_case_labels (vec<tree> ); extern void sort_case_labels (vec<tree>);
extern void preprocess_case_label_vec_for_gimple (vec<tree> , tree, tree *); extern void preprocess_case_label_vec_for_gimple (vec<tree>, tree, tree *);
extern void gimple_seq_set_location (gimple_seq , location_t); extern void gimple_seq_set_location (gimple_seq, location_t);
extern void gimple_seq_discard (gimple_seq);
/* Formal (expression) temporary table handling: multiple occurrences of /* Formal (expression) temporary table handling: multiple occurrences of
the same scalar expression are evaluated into the same temporary. */ the same scalar expression are evaluated into the same temporary. */
......
...@@ -8630,4 +8630,31 @@ get_best_mem_extraction_insn (extraction_insn *insn, ...@@ -8630,4 +8630,31 @@ get_best_mem_extraction_insn (extraction_insn *insn,
struct_bits, field_mode); struct_bits, field_mode);
} }
/* Determine whether "1 << x" is relatively cheap in word_mode. */
bool
lshift_cheap_p (bool speed_p)
{
/* FIXME: This should be made target dependent via this "this_target"
mechanism, similar to e.g. can_copy_init_p in gcse.c. */
static bool init[2] = { false, false };
static bool cheap[2] = { true, true };
/* If the targer has no lshift in word_mode, the operation will most
probably not be cheap. ??? Does GCC even work for such targets? */
if (optab_handler (ashl_optab, word_mode) == CODE_FOR_nothing)
return false;
if (!init[speed_p])
{
rtx reg = gen_raw_REG (word_mode, 10000);
int cost = set_src_cost (gen_rtx_ASHIFT (word_mode, const1_rtx, reg),
speed_p);
cheap[speed_p] = cost < COSTS_N_INSNS (3);
init[speed_p] = true;
}
return cheap[speed_p];
}
#include "gt-optabs.h" #include "gt-optabs.h"
...@@ -538,5 +538,6 @@ extern void gen_satfractuns_conv_libfunc (convert_optab, const char *, ...@@ -538,5 +538,6 @@ extern void gen_satfractuns_conv_libfunc (convert_optab, const char *,
enum machine_mode, enum machine_mode,
enum machine_mode); enum machine_mode);
extern void init_tree_optimization_optabs (tree); extern void init_tree_optimization_optabs (tree);
extern bool lshift_cheap_p (bool);
#endif /* GCC_OPTABS_H */ #endif /* GCC_OPTABS_H */
2014-10-17 Jakub Jelinek <jakub@redhat.com> 2014-10-17 Jakub Jelinek <jakub@redhat.com>
PR tree-optimization/63464
* gcc.dg/torture/pr63464.c: New test.
* gcc.dg/tree-ssa/reassoc-37.c: New test.
* gcc.dg/tree-ssa/reassoc-38.c: New test.
PR tree-optimization/63302 PR tree-optimization/63302
* gcc.c-torture/execute/pr63302.c: New test. * gcc.c-torture/execute/pr63302.c: New test.
......
/* PR tree-optimization/63464 */
/* { dg-do run { target int32plus } } */
int cnt;
__attribute__((noinline, noclone)) void
bar (int x, int y)
{
cnt++;
switch (y)
{
case 1:
if ((unsigned) x < 24U && ((1U << x) & 0x860c0cU) != 0)
__builtin_abort ();
break;
case 2:
if ((unsigned) x >= 24U || ((1U << x) & 0x860c0cU) == 0)
__builtin_abort ();
break;
case 3:
if ((unsigned) x - 43U < 40U && ((1ULL << (x - 43U)) & 0x8f0000004fULL) != 0)
__builtin_abort ();
break;
case 4:
if ((unsigned) x - 43U >= 40U || ((1ULL << (x - 43U)) & 0x8f0000004fULL) == 0)
__builtin_abort ();
break;
default:
__builtin_abort ();
}
}
__attribute__((noinline, noclone)) void
f1 (int x)
{
if (x != 2 && x != 3 && x != 10 && x != 11 && x != 17 && x != 18 && x != 23)
bar (x, 1);
}
__attribute__((noinline, noclone)) void
f2 (int x)
{
if (x == 2 || x == 3 || x == 10 || x == 11 || x == 17 || x == 18 || x == 23)
bar (x, 2);
}
__attribute__((noinline, noclone)) void
f3 (int x)
{
if (x != 43 && x != 76 && x != 44 && x != 78 && x != 49
&& x != 77 && x != 46 && x != 75 && x != 45 && x != 82)
bar (x, 3);
}
__attribute__((noinline, noclone)) void
f4 (int x)
{
if (x == 43 || x == 76 || x == 44 || x == 78 || x == 49
|| x == 77 || x == 46 || x == 75 || x == 45 || x == 82)
bar (x, 4);
}
int
main ()
{
int i;
f1 (-__INT_MAX__ - 1);
for (i = -3; i < 92; i++)
f1 (i);
f1 (__INT_MAX__);
if (cnt != 97 - 7)
__builtin_abort ();
f2 (-__INT_MAX__ - 1);
for (i = -3; i < 92; i++)
f2 (i);
f2 (__INT_MAX__);
if (cnt != 97)
__builtin_abort ();
f3 (-__INT_MAX__ - 1);
for (i = -3; i < 92; i++)
f3 (i);
f3 (__INT_MAX__);
if (cnt != 97 * 2 - 10)
__builtin_abort ();
f4 (-__INT_MAX__ - 1);
for (i = -3; i < 92; i++)
f4 (i);
f4 (__INT_MAX__);
if (cnt != 97 * 2)
__builtin_abort ();
return 0;
}
/* PR tree-optimization/63464 */
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-optimized" } */
void bar (void);
void
foo (int x)
{
if (x != 2 && x != 3 && x != 10 && x != 11 && x != 17 && x != 18 && x != 23)
bar ();
}
/* Check if the tests have been folded into a bit test. */
/* { dg-final { scan-tree-dump "(8784908|0x0*860c0c)" "optimized" { target i?86-*-* x86_64-*-* } } } */
/* { dg-final { scan-tree-dump "(<<|>>)" "optimized" { target i?86-*-* x86_64-*-* } } } */
/* { dg-final { cleanup-tree-dump "optimized" } } */
/* PR tree-optimization/63464 */
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-optimized" } */
void bar (void);
void
foo (int x)
{
if (x == 43 || x == 76 || x == 44 || x == 78 || x == 49
|| x == 77 || x == 46 || x == 75 || x == 45 || x == 82)
bar ();
}
/* Check if the tests have been folded into a bit test. */
/* { dg-final { scan-tree-dump "(614180323407|0x0*8f0000004f)" "optimized" { target { { i?86-*-* x86_64-*-* } && { ! { ia32 } } } } } } */
/* { dg-final { scan-tree-dump "(<<|>>)" "optimized" { target { { i?86-*-* x86_64-*-* } && { ! { ia32 } } } } } } */
/* { dg-final { cleanup-tree-dump "optimized" } } */
...@@ -125,35 +125,6 @@ hoist_edge_and_branch_if_true (gimple_stmt_iterator *gsip, ...@@ -125,35 +125,6 @@ hoist_edge_and_branch_if_true (gimple_stmt_iterator *gsip,
} }
/* Determine whether "1 << x" is relatively cheap in word_mode. */
/* FIXME: This is the function that we need rtl.h and optabs.h for.
This function (and similar RTL-related cost code in e.g. IVOPTS) should
be moved to some kind of interface file for GIMPLE/RTL interactions. */
static bool
lshift_cheap_p (bool speed_p)
{
/* FIXME: This should be made target dependent via this "this_target"
mechanism, similar to e.g. can_copy_init_p in gcse.c. */
static bool init[2] = {false, false};
static bool cheap[2] = {true, true};
/* If the targer has no lshift in word_mode, the operation will most
probably not be cheap. ??? Does GCC even work for such targets? */
if (optab_handler (ashl_optab, word_mode) == CODE_FOR_nothing)
return false;
if (!init[speed_p])
{
rtx reg = gen_raw_REG (word_mode, 10000);
int cost = set_src_cost (gen_rtx_ASHIFT (word_mode, const1_rtx, reg),
speed_p);
cheap[speed_p] = cost < COSTS_N_INSNS (MAX_CASE_BIT_TESTS);
init[speed_p] = true;
}
return cheap[speed_p];
}
/* Return true if a switch should be expanded as a bit test. /* Return true if a switch should be expanded as a bit test.
RANGE is the difference between highest and lowest case. RANGE is the difference between highest and lowest case.
UNIQ is number of unique case node targets, not counting the default case. UNIQ is number of unique case node targets, not counting the default case.
......
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