+2017-12-12 Jeff Law <law@redhat.com>
+
+ PR tree-optimization/83298
+ PR tree-optimization/83362
+ PR tree-optimization/83383
+ * gimple-ssa-evrp-analyze.h (class evrp_range_analyzer): Make
+ push_value_range a public interface. Add new argument to
+ record_ranges_from_stmt.
+ * gimple-ssa-evrp-analyze.c
+ (evrp_range_analyzer::record_ranges_from_stmt): Add new argument.
+ Update comments. Handle recording temporary equivalences.
+ * tree-ssa-dom.c (dom_opt_opt_walker::before_dom_children): Add
+ new argument to call to evrp_range_analyzer::record_ranges_from_stmt.
+ * gimple-ssa-evrp.c (evrp_dom_walker::before_dom_children): Likewise.
+ * tree-ssa-threadedge.c: Include alloc-pool.h, vr-values.h and
+ gimple-ssa-evrp-analyze.h.
+ (record_temporary_equivalences_from_phis): Add new argument. When
+ the PHI arg is an SSA_NAME, set the result's range to the range
+ of the PHI arg.
+ (record_temporary_equivalences_from_stmts_at_dest): Record ranges
+ from statements too.
+ (thread_through_normal_block): Accept new argument, evrp_range_analyzer.
+ Pass it down to children as needed.
+ (thread_outgoing_edges): Likewise.
+ (thread_across_edge): Likewise. Push/pop range state as needed.
+ * tree-ssa-threadedge.h (thread_outgoing_edges): Update prototype.
+
2017-12-12 Julia Koval <julia.koval@intel.com>
* config/i386/i386.c (PTA_SKYLAKE_AVX512): Add PTA_CLWB.
vr_values = new class vr_values;
}
+/* Push an unwinding marker onto the unwinding stack. */
+
void
-evrp_range_analyzer::enter (basic_block bb)
+evrp_range_analyzer::push_marker ()
{
stack.safe_push (std::make_pair (NULL_TREE, (value_range *)NULL));
+}
+
+/* Analyze ranges as we enter basic block BB. */
+
+void
+evrp_range_analyzer::enter (basic_block bb)
+{
+ push_marker ();
record_ranges_from_incoming_edge (bb);
record_ranges_from_phis (bb);
bb->flags |= BB_VISITED;
}
}
+/* Record ranges from STMT into our VR_VALUES class. If TEMPORARY is
+ true, then this is a temporary equivalence and should be recorded
+ into the unwind table. Othewise record the equivalence into the
+ global table. */
+
void
-evrp_range_analyzer::record_ranges_from_stmt (gimple *stmt)
+evrp_range_analyzer::record_ranges_from_stmt (gimple *stmt, bool temporary)
{
tree output = NULL_TREE;
vr_values->extract_range_from_stmt (stmt, &taken_edge, &output, &vr);
if (output)
{
- vr_values->update_value_range (output, &vr);
-
- /* Set the SSA with the value range. */
- set_ssa_range_info (output, &vr);
+ /* Set the SSA with the value range. There are two cases to
+ consider. First (the the most common) is we are processing
+ STMT in a context where its resulting range globally holds
+ and thus it can be reflected into the global ranges and need
+ not be unwound as we leave scope.
+
+ The second case occurs if we are processing a statement in
+ a context where the resulting range must not be reflected
+ into the global tables and must be unwound as we leave
+ the current context. This happens in jump threading for
+ example. */
+ if (!temporary)
+ {
+ /* Case one. We can just update the underlying range
+ information as well as the global information. */
+ vr_values->update_value_range (output, &vr);
+ set_ssa_range_info (output, &vr);
+ }
+ else
+ {
+ /* We're going to need to unwind this range. We can
+ not use VR as that's a stack object. We have to allocate
+ a new range and push the old range onto the stack. We
+ also have to be very careful about sharing the underlying
+ bitmaps. Ugh. */
+ value_range *new_vr = vr_values->allocate_value_range ();
+ *new_vr = vr;
+ new_vr->equiv = NULL;
+ push_value_range (output, new_vr);
+ }
}
else
vr_values->set_defs_to_varying (stmt);
}
}
-/* Restore/pop VRs valid only for BB when we leave BB. */
+/* Unwind recorded ranges to their most recent state. */
void
-evrp_range_analyzer::leave (basic_block bb ATTRIBUTE_UNUSED)
+evrp_range_analyzer::pop_to_marker (void)
{
gcc_checking_assert (!stack.is_empty ());
while (stack.last ().first != NULL_TREE)
stack.pop ();
}
+/* Restore/pop VRs valid only for BB when we leave BB. */
+
+void
+evrp_range_analyzer::leave (basic_block bb ATTRIBUTE_UNUSED)
+{
+ pop_to_marker ();
+}
+
+
/* Push the Value Range of VAR to the stack and update it with new VR. */
void
}
void enter (basic_block);
+ void push_marker (void);
+ void pop_to_marker (void);
void leave (basic_block);
- void record_ranges_from_stmt (gimple *);
+ void record_ranges_from_stmt (gimple *, bool);
/* Main interface to retrieve range information. */
value_range *get_value_range (const_tree op)
{ return vr_values->get_value_range (op); }
+ /* Record a new unwindable range. */
+ void push_value_range (tree var, value_range *vr);
+
/* Dump all the current value ranges. This is primarily
a debugging interface. */
void dump_all_value_ranges (FILE *fp)
DISABLE_COPY_AND_ASSIGN (evrp_range_analyzer);
class vr_values *vr_values;
- void push_value_range (tree var, value_range *vr);
value_range *pop_value_range (tree var);
value_range *try_find_new_range (tree, tree op, tree_code code, tree limit);
void record_ranges_from_incoming_edge (basic_block);
print_gimple_stmt (dump_file, stmt, 0);
}
- evrp_range_analyzer.record_ranges_from_stmt (stmt);
+ evrp_range_analyzer.record_ranges_from_stmt (stmt, false);
if (gcond *cond = dyn_cast <gcond *> (stmt))
{
+2017-12-12 Jeff Law <law@redhat.com>
+
+ PR tree-optimization/83298
+ PR tree-optimization/83362
+ PR tree-optimization/83383
+ * gcc.c-torture/execute/pr83298.c: New test.
+ * gcc.c-torture/execute/pr83362.c New test.
+ * gcc.c-torture/execute/pr83383.c New test.
+
2017-12-12 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
* lib/gcc-dg.exp (process-message): Avoid additional whitespace in
--- /dev/null
+
+int a, b, c = 1;
+
+int main ()
+{
+ for (; b < 1; b++)
+ ;
+ if (!(c * (a < 1)))
+ __builtin_abort ();
+ return 0;
+}
--- /dev/null
+typedef unsigned char u8;
+typedef unsigned int u32;
+
+u32 a, b, d, e;
+u8 c;
+
+static u32 __attribute__ ((noinline, noclone))
+foo (u32 p)
+{
+ do
+ {
+ e /= 0xfff;
+ if (p > c)
+ d = 0;
+ e -= 3;
+ e *= b <= a;
+ }
+ while (e >= 88030);
+ return e;
+}
+
+int
+main (void)
+{
+ u32 x = foo (1164);
+ if (x != 0xfd)
+ __builtin_abort ();
+ return 0;
+}
+
+
--- /dev/null
+/* PR tree-optimization/83383 */
+
+unsigned long long int a = 16ULL;
+unsigned char b = 195;
+unsigned long long int c = ~0ULL;
+unsigned char d = 1;
+unsigned long long int e[2] = { 3625445792498952486ULL, 0 };
+unsigned long long int f[2] = { 0, 8985037393681294663ULL };
+unsigned long long int g = 5052410635626804928ULL;
+
+void
+foo ()
+{
+ a = ((signed char) a) < b;
+ c = (d ? e[0] : 0) - (f[1] * a ? 1 : g);
+}
+
+int
+main()
+{
+ foo ();
+ if (a != 1 || c != 3625445792498952485ULL)
+ __builtin_abort ();
+ return 0;
+}
edge taken_edge = NULL;
for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
{
- evrp_range_analyzer.record_ranges_from_stmt (gsi_stmt (gsi));
+ evrp_range_analyzer.record_ranges_from_stmt (gsi_stmt (gsi), false);
taken_edge = this->optimize_stmt (bb, gsi);
}
x_vr_values = evrp_range_analyzer.get_vr_values ();
thread_outgoing_edges (bb, m_dummy_cond, m_const_and_copies,
m_avail_exprs_stack,
+ &evrp_range_analyzer,
simplify_stmt_for_jump_threading);
x_vr_values = NULL;
#include "tree-ssa-dom.h"
#include "gimple-fold.h"
#include "cfganal.h"
+#include "alloc-pool.h"
+#include "vr-values.h"
+#include "gimple-ssa-evrp-analyze.h"
/* To avoid code explosion due to jump threading, we limit the
number of statements we are going to copy. This variable
}
/* Record temporary equivalences created by PHIs at the target of the
- edge E. Record unwind information for the equivalences onto STACK.
+ edge E. Record unwind information for the equivalences into
+ CONST_AND_COPIES and EVRP_RANGE_DATA.
If a PHI which prevents threading is encountered, then return FALSE
- indicating we should not thread this edge, else return TRUE.
-
- If SRC_MAP/DST_MAP exist, then mark the source and destination SSA_NAMEs
- of any equivalences recorded. We use this to make invalidation after
- traversing back edges less painful. */
+ indicating we should not thread this edge, else return TRUE. */
static bool
-record_temporary_equivalences_from_phis (edge e, const_and_copies *const_and_copies)
+record_temporary_equivalences_from_phis (edge e,
+ const_and_copies *const_and_copies,
+ evrp_range_analyzer *evrp_range_analyzer)
{
gphi_iterator gsi;
stmt_count++;
const_and_copies->record_const_or_copy (dst, src);
+
+ /* Also update the value range associated with DST, using
+ the range from SRC. */
+ if (evrp_range_analyzer && TREE_CODE (src) == SSA_NAME)
+ {
+ value_range *vr = evrp_range_analyzer->get_value_range (src);
+ evrp_range_analyzer->push_value_range (dst, vr);
+ }
}
return true;
}
record_temporary_equivalences_from_stmts_at_dest (edge e,
const_and_copies *const_and_copies,
avail_exprs_stack *avail_exprs_stack,
+ evrp_range_analyzer *evrp_range_analyzer,
pfn_simplify simplify)
{
gimple *stmt = NULL;
if (stmt_count > max_stmt_count)
return NULL;
+ /* These are temporary ranges, do nto reflect them back into
+ the global range data. */
+ if (evrp_range_analyzer)
+ evrp_range_analyzer->record_ranges_from_stmt (stmt, true);
+
/* If this is not a statement that sets an SSA_NAME to a new
value, then do not try to simplify this statement as it will
not simplify in any way that is helpful for jump threading. */
gcond *dummy_cond,
const_and_copies *const_and_copies,
avail_exprs_stack *avail_exprs_stack,
+ evrp_range_analyzer *evrp_range_analyzer,
pfn_simplify simplify,
vec<jump_thread_edge *> *path,
bitmap visited)
Note that if we found a PHI that made the block non-threadable, then
we need to bubble that up to our caller in the same manner we do
when we prematurely stop processing statements below. */
- if (!record_temporary_equivalences_from_phis (e, const_and_copies))
+ if (!record_temporary_equivalences_from_phis (e, const_and_copies,
+ evrp_range_analyzer))
return -1;
/* Now walk each statement recording any context sensitive
gimple *stmt
= record_temporary_equivalences_from_stmts_at_dest (e, const_and_copies,
avail_exprs_stack,
+ evrp_range_analyzer,
simplify);
/* There's two reasons STMT might be null, and distinguishing
edge e,
class const_and_copies *const_and_copies,
class avail_exprs_stack *avail_exprs_stack,
+ class evrp_range_analyzer *evrp_range_analyzer,
pfn_simplify simplify)
{
bitmap visited = BITMAP_ALLOC (NULL);
const_and_copies->push_marker ();
avail_exprs_stack->push_marker ();
+ if (evrp_range_analyzer)
+ evrp_range_analyzer->push_marker ();
stmt_count = 0;
threaded = thread_through_normal_block (e, dummy_cond,
const_and_copies,
avail_exprs_stack,
+ evrp_range_analyzer,
simplify, path,
visited);
else
e->dest);
const_and_copies->pop_to_marker ();
avail_exprs_stack->pop_to_marker ();
+ if (evrp_range_analyzer)
+ evrp_range_analyzer->pop_to_marker ();
BITMAP_FREE (visited);
register_jump_thread (path);
return;
BITMAP_FREE (visited);
const_and_copies->pop_to_marker ();
avail_exprs_stack->pop_to_marker ();
+ if (evrp_range_analyzer)
+ evrp_range_analyzer->pop_to_marker ();
return;
}
}
{
const_and_copies->pop_to_marker ();
avail_exprs_stack->pop_to_marker ();
+ if (evrp_range_analyzer)
+ evrp_range_analyzer->pop_to_marker ();
BITMAP_FREE (visited);
return;
}
for each of E->dest's successors. */
const_and_copies->push_marker ();
avail_exprs_stack->push_marker ();
+ if (evrp_range_analyzer)
+ evrp_range_analyzer->push_marker ();
/* Avoid threading to any block we have already visited. */
bitmap_clear (visited);
found = thread_through_normal_block (path->last ()->e, dummy_cond,
const_and_copies,
avail_exprs_stack,
+ evrp_range_analyzer,
simplify, path,
visited) > 0;
delete_jump_thread_path (path);
/* And unwind the equivalence table. */
+ if (evrp_range_analyzer)
+ evrp_range_analyzer->pop_to_marker ();
avail_exprs_stack->pop_to_marker ();
const_and_copies->pop_to_marker ();
}
BITMAP_FREE (visited);
}
+ if (evrp_range_analyzer)
+ evrp_range_analyzer->pop_to_marker ();
const_and_copies->pop_to_marker ();
avail_exprs_stack->pop_to_marker ();
}
thread_outgoing_edges (basic_block bb, gcond *dummy_cond,
class const_and_copies *const_and_copies,
class avail_exprs_stack *avail_exprs_stack,
+ class evrp_range_analyzer *evrp_range_analyzer,
tree (*simplify) (gimple *, gimple *,
class avail_exprs_stack *,
basic_block))
{
thread_across_edge (dummy_cond, single_succ_edge (bb),
const_and_copies, avail_exprs_stack,
- simplify);
+ evrp_range_analyzer, simplify);
}
else if ((last = last_stmt (bb))
&& gimple_code (last) == GIMPLE_COND
more than one predecessor and more than one successor. */
if (potentially_threadable_block (true_edge->dest))
thread_across_edge (dummy_cond, true_edge,
- const_and_copies, avail_exprs_stack, simplify);
+ const_and_copies, avail_exprs_stack,
+ evrp_range_analyzer, simplify);
/* Similarly for the ELSE arm. */
if (potentially_threadable_block (false_edge->dest))
thread_across_edge (dummy_cond, false_edge,
- const_and_copies, avail_exprs_stack, simplify);
+ const_and_copies, avail_exprs_stack,
+ evrp_range_analyzer, simplify);
}
}
extern void threadedge_finalize_values (void);
extern bool potentially_threadable_block (basic_block);
extern void propagate_threaded_block_debug_into (basic_block, basic_block);
+class evrp_range_analyzer;
extern void thread_outgoing_edges (basic_block, gcond *,
const_and_copies *,
avail_exprs_stack *,
+ evrp_range_analyzer *,
tree (*) (gimple *, gimple *,
avail_exprs_stack *, basic_block));
x_vr_values = vr_values;
thread_outgoing_edges (bb, m_dummy_cond, m_const_and_copies,
- m_avail_exprs_stack,
+ m_avail_exprs_stack, NULL,
simplify_stmt_for_jump_threading);
x_vr_values = NULL;