mirror of
https://gcc.gnu.org/git/gcc.git
synced 2026-02-22 12:00:03 -05:00
Compare commits
203 Commits
devel/exis
...
devel/rang
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f69ab586f6 | ||
|
|
f67c1bddaf | ||
|
|
7cefb069fa | ||
|
|
6472945db3 | ||
|
|
397aece267 | ||
|
|
b9e67f2840 | ||
|
|
1957047ed1 | ||
|
|
71920b87f7 | ||
|
|
e09c42b8a4 | ||
|
|
52e2fc662a | ||
|
|
9c7dce1bc5 | ||
|
|
784003f0d5 | ||
|
|
708b56f90b | ||
|
|
4efacd5dbb | ||
|
|
49fac79438 | ||
|
|
2f28c16f0d | ||
|
|
df663310ee | ||
|
|
a5b9a237d6 | ||
|
|
c6e8b9bb06 | ||
|
|
5a8c373b79 | ||
|
|
77f9508510 | ||
|
|
d310e3372a | ||
|
|
f5372d34d4 | ||
|
|
455c0b2c72 | ||
|
|
7b61d7a733 | ||
|
|
e80f12ca10 | ||
|
|
478046cfa0 | ||
|
|
9e7dee0822 | ||
|
|
ec5047297e | ||
|
|
f12f352350 | ||
|
|
8018a7eae5 | ||
|
|
f21c760ce9 | ||
|
|
d1b1758148 | ||
|
|
9fde43096e | ||
|
|
0a16792f35 | ||
|
|
a80468e8ee | ||
|
|
304543d8ff | ||
|
|
af1295ebe1 | ||
|
|
07a3e49243 | ||
|
|
b454a26fc2 | ||
|
|
d7dc8055ac | ||
|
|
eb227c9098 | ||
|
|
671279d304 | ||
|
|
638cee48e6 | ||
|
|
2453788a87 | ||
|
|
edaa86722d | ||
|
|
79b6818236 | ||
|
|
4d54dcd0b2 | ||
|
|
423845c7db | ||
|
|
f4fdaf111d | ||
|
|
7f0cbb5e5c | ||
|
|
d01bb094e0 | ||
|
|
d34a06eb10 | ||
|
|
b1742cc9ca | ||
|
|
57792146bf | ||
|
|
596ec9a19b | ||
|
|
ed94068fb3 | ||
|
|
4e3a54f0ea | ||
|
|
6273e85ad8 | ||
|
|
4a7bfd79b3 | ||
|
|
73d5e1ca79 | ||
|
|
e8fd51064c | ||
|
|
413b5adf6a | ||
|
|
a55f167fde | ||
|
|
77036c3309 | ||
|
|
3fd307e754 | ||
|
|
25cfa84da6 | ||
|
|
31445ce3c2 | ||
|
|
faf33902ff | ||
|
|
ab8cdab5e6 | ||
|
|
4a5c4619b4 | ||
|
|
b9f248d8fa | ||
|
|
f5267b3697 | ||
|
|
608481d7dc | ||
|
|
c0f9a600cc | ||
|
|
6b179b967a | ||
|
|
717b963ed0 | ||
|
|
550186c047 | ||
|
|
353e3a5465 | ||
|
|
302ef01db3 | ||
|
|
9eac184417 | ||
|
|
277d95af38 | ||
|
|
e6db00c130 | ||
|
|
e6fd3f3cdf | ||
|
|
fa8f67d081 | ||
|
|
d04d67fee0 | ||
|
|
9e927c2144 | ||
|
|
762129fe36 | ||
|
|
c6b05b86ed | ||
|
|
c8f4b642d2 | ||
|
|
ff7ae60c27 | ||
|
|
5b6d81b17e | ||
|
|
fde9e8acfb | ||
|
|
eaee77632d | ||
|
|
ee70d79e66 | ||
|
|
52f48b97c5 | ||
|
|
c6a2bc2f87 | ||
|
|
2b00c48907 | ||
|
|
4f40aee87d | ||
|
|
f7626d1ebf | ||
|
|
1ece551411 | ||
|
|
25acb18573 | ||
|
|
02807fb45d | ||
|
|
0e95df7c00 | ||
|
|
7b0df61d25 | ||
|
|
5a9f103322 | ||
|
|
df81d24357 | ||
|
|
c1729bcfb1 | ||
|
|
4fb96e0c6e | ||
|
|
775488eb55 | ||
|
|
e0c9f49367 | ||
|
|
8096618793 | ||
|
|
8678b960e9 | ||
|
|
1eb0287430 | ||
|
|
f6873bb8ff | ||
|
|
a542cf738e | ||
|
|
74cb4de899 | ||
|
|
a3c7d42f45 | ||
|
|
ac18bfb92b | ||
|
|
bce6d53da6 | ||
|
|
3c027e0f14 | ||
|
|
63657cd2eb | ||
|
|
ec00a647c9 | ||
|
|
483d62b0dc | ||
|
|
665956722d | ||
|
|
39ba0fabc0 | ||
|
|
96e9021d1c | ||
|
|
b6a6426a49 | ||
|
|
6b52a6baaa | ||
|
|
73a9a85d0d | ||
|
|
185146f0ac | ||
|
|
6431c0c936 | ||
|
|
3a6a3700e1 | ||
|
|
5852617c99 | ||
|
|
b93b79eceb | ||
|
|
392dd3fbbb | ||
|
|
0437c263f0 | ||
|
|
7b6889b84f | ||
|
|
99403c03fd | ||
|
|
ff64c4fc2a | ||
|
|
f7716ecfbc | ||
|
|
8d31cb98f6 | ||
|
|
20f438d4f0 | ||
|
|
528ac0124c | ||
|
|
bfde05836d | ||
|
|
c1e7c67268 | ||
|
|
1838cf93b0 | ||
|
|
7b785411e4 | ||
|
|
862506fe27 | ||
|
|
edfbdc27fa | ||
|
|
8f0abf2547 | ||
|
|
011496d96f | ||
|
|
112a17036d | ||
|
|
53dc0d5f76 | ||
|
|
3cb7dcfdc6 | ||
|
|
6dc1dafb21 | ||
|
|
7366b4ed51 | ||
|
|
a4e46044c3 | ||
|
|
1e4a1fcc4e | ||
|
|
4fdf8b66b7 | ||
|
|
381cdee9cd | ||
|
|
ab83346043 | ||
|
|
95c27443b4 | ||
|
|
6b3e788d83 | ||
|
|
292d840c41 | ||
|
|
ffbed51445 | ||
|
|
0467dd7cc5 | ||
|
|
5c27e40e54 | ||
|
|
af64c1bd95 | ||
|
|
7cee184441 | ||
|
|
6537c9b038 | ||
|
|
0c0d17e822 | ||
|
|
b80e6a443f | ||
|
|
c8507441c7 | ||
|
|
b540c32126 | ||
|
|
2bedc2b00c | ||
|
|
ab1ce955e2 | ||
|
|
43acb42282 | ||
|
|
05d69a4066 | ||
|
|
795a01b1b0 | ||
|
|
0651329d18 | ||
|
|
43e7f2b096 | ||
|
|
82da0512f7 | ||
|
|
85b722579d | ||
|
|
2a58ac1efd | ||
|
|
fcdbbb3ebb | ||
|
|
cd6639b86f | ||
|
|
9e6c41477c | ||
|
|
ec6fcd5a77 | ||
|
|
e5bda90a68 | ||
|
|
cd84b4aeba | ||
|
|
4372889799 | ||
|
|
41b0416dc2 | ||
|
|
c08555a9bc | ||
|
|
20ecf0b30f | ||
|
|
0a7de7f51a | ||
|
|
7ff8d435e5 | ||
|
|
da26a4ac3b | ||
|
|
c98bbf5b9f | ||
|
|
dbf325ba9a | ||
|
|
f837b1ea59 | ||
|
|
228df8c40c | ||
|
|
e005383e59 |
@@ -226,8 +226,8 @@ dfp.o-warn = -Wno-strict-aliasing
|
||||
# isn't gcc; configure determines that. WARN_CFLAGS will be either
|
||||
# $(GCC_WARN_CFLAGS), or nothing. Similarly, WARN_CXXFLAGS will be
|
||||
# either $(GCC_WARN_CXXFLAGS), or nothing.
|
||||
WARN_CFLAGS = @warn_cflags@
|
||||
WARN_CXXFLAGS = @warn_cxxflags@
|
||||
WARN_CFLAGS = @warn_cflags@ -Wno-format -Wno-implicit-fallthrough
|
||||
WARN_CXXFLAGS = @warn_cxxflags@ -Wno-format -Wno-implicit-fallthrough
|
||||
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
|
||||
@@ -1364,6 +1364,11 @@ OBJS = \
|
||||
gimple-loop-versioning.o \
|
||||
gimple-low.o \
|
||||
gimple-pretty-print.o \
|
||||
gimple-range.o \
|
||||
gimple-range-vrp.o \
|
||||
misc.o \
|
||||
gimple-range-cache.o \
|
||||
gimple-range-gori.o \
|
||||
gimple-ssa-backprop.o \
|
||||
gimple-ssa-evrp.o \
|
||||
gimple-ssa-evrp-analyze.o \
|
||||
@@ -2632,13 +2637,13 @@ GTFILES = $(CPPLIB_H) $(srcdir)/input.h $(srcdir)/coretypes.h \
|
||||
$(srcdir)/tree-ssa-alias.h \
|
||||
$(srcdir)/tree-ssanames.h \
|
||||
$(srcdir)/tree-vrp.h \
|
||||
$(srcdir)/value-range.h \
|
||||
$(srcdir)/ipa-prop.h \
|
||||
$(srcdir)/trans-mem.c \
|
||||
$(srcdir)/lto-streamer.h \
|
||||
$(srcdir)/target-globals.h \
|
||||
$(srcdir)/ipa-predicate.h \
|
||||
$(srcdir)/ipa-fnsummary.h \
|
||||
$(srcdir)/value-range.h \
|
||||
$(srcdir)/vtable-verify.c \
|
||||
$(srcdir)/asan.c \
|
||||
$(srcdir)/ubsan.c \
|
||||
|
||||
@@ -2994,6 +2994,24 @@ fvect-cost-model
|
||||
Common Alias(fvect-cost-model=,dynamic,unlimited)
|
||||
Enables the dynamic vectorizer cost model. Preserved for backward compatibility.
|
||||
|
||||
frvrp1-changes
|
||||
Common Var(flag_rvrp1_changes) Init(0)
|
||||
Allow IL changes in rvrp1 pass.
|
||||
|
||||
frvrp2-changes
|
||||
Common Var(flag_rvrp2_changes) Init(1)
|
||||
Allow IL changes in rvrp2 pass.
|
||||
|
||||
fevrp-traps
|
||||
Common Var(flag_evrp_traps) Init(0)
|
||||
Trap on any EVRP changes to the IL.
|
||||
|
||||
frvrp-changes
|
||||
Common Var(flag_rvrp_changes) Init(-1)
|
||||
Override for both -frvrp1-changes and -frvrp2-changes. This is meant
|
||||
to be used by the testsuite to keep RVRP passes from making IL changes
|
||||
in some tests, thus making easier to test evrp functionality.
|
||||
|
||||
ftree-vect-loop-version
|
||||
Common Ignore
|
||||
Does nothing. Preserved for backward compatibility.
|
||||
|
||||
@@ -158,6 +158,7 @@ DEBUG_COUNTER (dom_unreachable_edges)
|
||||
DEBUG_COUNTER (dse)
|
||||
DEBUG_COUNTER (dse1)
|
||||
DEBUG_COUNTER (dse2)
|
||||
DEBUG_COUNTER (evrp_find_range)
|
||||
DEBUG_COUNTER (gcse2_delete)
|
||||
DEBUG_COUNTER (gimple_unroll)
|
||||
DEBUG_COUNTER (global_alloc_at_func)
|
||||
@@ -182,6 +183,7 @@ DEBUG_COUNTER (postreload_cse)
|
||||
DEBUG_COUNTER (pre)
|
||||
DEBUG_COUNTER (pre_insn)
|
||||
DEBUG_COUNTER (prefetch)
|
||||
DEBUG_COUNTER (ranger_export_count)
|
||||
DEBUG_COUNTER (registered_jump_thread)
|
||||
DEBUG_COUNTER (sched2_func)
|
||||
DEBUG_COUNTER (sched_block)
|
||||
|
||||
@@ -144,8 +144,10 @@ static const kv_pair<dump_flags_t> dump_options[] =
|
||||
{"missed", MSG_MISSED_OPTIMIZATION},
|
||||
{"note", MSG_NOTE},
|
||||
{"optall", MSG_ALL_KINDS},
|
||||
{"gori", TDF_GORI},
|
||||
{"all", dump_flags_t (TDF_ALL_VALUES
|
||||
& ~(TDF_RAW | TDF_SLIM | TDF_LINENO | TDF_GRAPH
|
||||
| TDF_GORI
|
||||
| TDF_STMTADDR | TDF_RHS_ONLY | TDF_NOUID
|
||||
| TDF_ENUMERATE_LOCALS | TDF_SCEV | TDF_GIMPLE))},
|
||||
{NULL, TDF_NONE}
|
||||
|
||||
@@ -196,8 +196,11 @@ enum dump_flag
|
||||
/* For error. */
|
||||
TDF_ERROR = (1 << 26),
|
||||
|
||||
/* Trace GORI as it calculates ranges. */
|
||||
TDF_GORI = (1 << 29),
|
||||
|
||||
/* All values. */
|
||||
TDF_ALL_VALUES = (1 << 29) - 1
|
||||
TDF_ALL_VALUES = (1 << 30) - 1
|
||||
};
|
||||
|
||||
/* Dump flags type. */
|
||||
|
||||
@@ -125,7 +125,10 @@ CXX_KEYWORD inline|public:|private:|protected:|template|operator|friend|static|m
|
||||
"ptr_alias"/{EOID} { return PTR_ALIAS; }
|
||||
"nested_ptr"/{EOID} { return NESTED_PTR; }
|
||||
"user"/{EOID} { return USER_GTY; }
|
||||
[0-9]+ { return NUM; }
|
||||
[0-9]+ {
|
||||
*yylval = XDUPVAR (const char, yytext, yyleng, yyleng+1);
|
||||
return NUM;
|
||||
}
|
||||
|
||||
{IWORD}({WS}{IWORD})*/{EOID} |
|
||||
"ENUM_BITFIELD"{WS}?"("{WS}?{ID}{WS}?")" {
|
||||
|
||||
@@ -42,6 +42,7 @@ along with GCC; see the file COPYING3. If not see
|
||||
#include "attribs.h"
|
||||
#include "asan.h"
|
||||
#include "cfgloop.h"
|
||||
#include "misc.h"
|
||||
|
||||
/* Disable warnings about quoting issues in the pp_xxx calls below
|
||||
that (intentionally) don't follow GCC diagnostic conventions. */
|
||||
@@ -2967,7 +2968,9 @@ gimple_dump_bb_buff (pretty_printer *buffer, basic_block bb, int indent,
|
||||
curr_indent = gimple_code (stmt) == GIMPLE_LABEL ? label_indent : indent;
|
||||
|
||||
INDENT (curr_indent);
|
||||
highlighter.on (buffer, curr_indent, stmt);
|
||||
pp_gimple_stmt_1 (buffer, stmt, curr_indent, flags);
|
||||
highlighter.off (buffer, curr_indent, stmt);
|
||||
pp_newline_and_flush (buffer);
|
||||
gcc_checking_assert (DECL_STRUCT_FUNCTION (current_function_decl));
|
||||
dump_histograms_for_stmt (DECL_STRUCT_FUNCTION (current_function_decl),
|
||||
|
||||
682
gcc/gimple-range-cache.cc
Normal file
682
gcc/gimple-range-cache.cc
Normal file
@@ -0,0 +1,682 @@
|
||||
/* Gimple ranger SSA cache implementation.
|
||||
Copyright (C) 2017-2020 Free Software Foundation, Inc.
|
||||
Contributed by Andrew MacLeod <amacleod@redhat.com>.
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
GCC is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3, or (at your option)
|
||||
any later version.
|
||||
|
||||
GCC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GCC; see the file COPYING3. If not see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "config.h"
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "backend.h"
|
||||
#include "insn-codes.h"
|
||||
#include "tree.h"
|
||||
#include "gimple.h"
|
||||
#include "ssa.h"
|
||||
#include "gimple-pretty-print.h"
|
||||
#include "gimple-range.h"
|
||||
|
||||
// During contructor, allocate the vector of ssa_names.
|
||||
|
||||
non_null_ref::non_null_ref ()
|
||||
{
|
||||
m_nn.create (0);
|
||||
m_nn.safe_grow_cleared (num_ssa_names);
|
||||
}
|
||||
|
||||
// Free any bitmaps which were allocated,a swell as the vector itself.
|
||||
|
||||
non_null_ref::~non_null_ref ()
|
||||
{
|
||||
unsigned x;
|
||||
for (x = 0; x< m_nn.length (); x++)
|
||||
if (m_nn[x])
|
||||
BITMAP_FREE (m_nn[x]);
|
||||
}
|
||||
|
||||
// Return true if NAME has a non-null dereference in block bb. If this is the
|
||||
// first query for NAME, calculate the summary first.
|
||||
|
||||
bool
|
||||
non_null_ref::non_null_deref_p (tree name, basic_block bb)
|
||||
{
|
||||
if (!POINTER_TYPE_P (TREE_TYPE (name)))
|
||||
return false;
|
||||
|
||||
unsigned v = SSA_NAME_VERSION (name);
|
||||
if (!m_nn[v])
|
||||
process_name (name);
|
||||
|
||||
return bitmap_bit_p (m_nn[v], bb->index);
|
||||
}
|
||||
|
||||
// Allocate an populate the bitmap for NAME. An ON bit for a block
|
||||
// index indicates there is a non-null reference in that block. In
|
||||
// order to populate the bitmap, a quick run of all the immediate uses
|
||||
// are made and the statement checked to see if a non-null dereference
|
||||
// is made on that statement.
|
||||
|
||||
void
|
||||
non_null_ref::process_name (tree name)
|
||||
{
|
||||
unsigned v = SSA_NAME_VERSION (name);
|
||||
use_operand_p use_p;
|
||||
imm_use_iterator iter;
|
||||
bitmap b;
|
||||
|
||||
// Only tracked for pointers.
|
||||
if (!POINTER_TYPE_P (TREE_TYPE (name)))
|
||||
return;
|
||||
|
||||
// Already processed if a bitmap has been allocated.
|
||||
if (m_nn[v])
|
||||
return;
|
||||
|
||||
b = BITMAP_ALLOC (NULL);
|
||||
|
||||
// Loop over each immediate use and see if it implies a non-null value.
|
||||
FOR_EACH_IMM_USE_FAST (use_p, iter, name)
|
||||
{
|
||||
gimple *s = USE_STMT (use_p);
|
||||
unsigned index = gimple_bb (s)->index;
|
||||
tree value;
|
||||
enum tree_code comp_code;
|
||||
|
||||
// If bit is already set for this block, dont bother looking again.
|
||||
if (bitmap_bit_p (b, index))
|
||||
continue;
|
||||
|
||||
// If we can infer a != 0 range, then set the bit for this BB
|
||||
if (infer_value_range (s, name, &comp_code, &value))
|
||||
{
|
||||
if (comp_code == NE_EXPR && integer_zerop (value))
|
||||
bitmap_set_bit (b, index);
|
||||
}
|
||||
}
|
||||
|
||||
m_nn[v] = b;
|
||||
}
|
||||
|
||||
// This class implements a cache of ranges indexed by basic block. It
|
||||
// represents all that is known about an SSA_NAME on entry to each
|
||||
// block. It caches a range-for-type varying range so it doesn't need
|
||||
// to be reformed all the time. If a range is ever always associated
|
||||
// with a type, we can use that instead. Whenever varying is being
|
||||
// set for a block, the cache simply points to this cached one rather
|
||||
// than create a new one each time.
|
||||
|
||||
class ssa_block_ranges
|
||||
{
|
||||
public:
|
||||
ssa_block_ranges (tree t);
|
||||
~ssa_block_ranges ();
|
||||
|
||||
void set_bb_range (const basic_block bb, const irange &r);
|
||||
void set_bb_varying (const basic_block bb);
|
||||
bool get_bb_range (irange &r, const basic_block bb);
|
||||
bool bb_range_p (const basic_block bb);
|
||||
|
||||
void dump(FILE *f);
|
||||
private:
|
||||
vec<irange_storage *> m_tab;
|
||||
irange_storage *m_type_range;
|
||||
tree m_type;
|
||||
};
|
||||
|
||||
|
||||
// Initialize a block cache for an ssa_name of type T
|
||||
|
||||
ssa_block_ranges::ssa_block_ranges (tree t)
|
||||
{
|
||||
irange_storage tr;
|
||||
gcc_assert (TYPE_P (t));
|
||||
m_type = t;
|
||||
|
||||
m_tab.create (0);
|
||||
m_tab.safe_grow_cleared (last_basic_block_for_fn (cfun));
|
||||
|
||||
// Create the cached type range.
|
||||
tr.set_varying (t);
|
||||
m_type_range = new irange_storage (tr);
|
||||
|
||||
m_tab[ENTRY_BLOCK_PTR_FOR_FN (cfun)->index] = m_type_range;
|
||||
}
|
||||
|
||||
// Destruct block range.
|
||||
|
||||
ssa_block_ranges::~ssa_block_ranges ()
|
||||
{
|
||||
m_tab.release ();
|
||||
}
|
||||
|
||||
// Set the range for block BB to be R.
|
||||
|
||||
void
|
||||
ssa_block_ranges::set_bb_range (const basic_block bb, const irange &r)
|
||||
{
|
||||
irange_storage *m = m_tab[bb->index];
|
||||
|
||||
// If there is already range memory for this block, kill it.
|
||||
// Look into reuse.
|
||||
//
|
||||
// right now we're losing memory.
|
||||
//
|
||||
// if (m && m != m_type_range)
|
||||
// delete m;
|
||||
|
||||
m = new irange_storage (r);
|
||||
m_tab[bb->index] = m;
|
||||
}
|
||||
|
||||
// Set the range for block BB to the range for the type.
|
||||
|
||||
void
|
||||
ssa_block_ranges::set_bb_varying (const basic_block bb)
|
||||
{
|
||||
m_tab[bb->index] = m_type_range;
|
||||
}
|
||||
|
||||
// Return the range associated with block BB in R. Return false if
|
||||
// there is no range.
|
||||
|
||||
bool
|
||||
ssa_block_ranges::get_bb_range (irange &r, const basic_block bb)
|
||||
{
|
||||
irange_storage *m = m_tab[bb->index];
|
||||
if (m)
|
||||
{
|
||||
r = irange_storage (*m);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Returns true if a range is present
|
||||
|
||||
bool
|
||||
ssa_block_ranges::bb_range_p (const basic_block bb)
|
||||
{
|
||||
return m_tab[bb->index] != NULL;
|
||||
}
|
||||
|
||||
|
||||
// Print the list of known ranges for file F in a nice format.
|
||||
|
||||
void
|
||||
ssa_block_ranges::dump (FILE *f)
|
||||
{
|
||||
basic_block bb;
|
||||
widest_irange r;
|
||||
|
||||
FOR_EACH_BB_FN (bb, cfun)
|
||||
if (get_bb_range (r, bb))
|
||||
{
|
||||
fprintf (f, "BB%d -> ", bb->index);
|
||||
r.dump (f);
|
||||
fprintf (f, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
// Initialize the block cache.
|
||||
|
||||
block_range_cache::block_range_cache ()
|
||||
{
|
||||
m_ssa_ranges.create (0);
|
||||
m_ssa_ranges.safe_grow_cleared (num_ssa_names);
|
||||
}
|
||||
|
||||
// Remove any m_block_caches which have been created.
|
||||
|
||||
block_range_cache::~block_range_cache ()
|
||||
{
|
||||
unsigned x;
|
||||
for (x = 0; x < m_ssa_ranges.length (); ++x)
|
||||
{
|
||||
if (m_ssa_ranges[x])
|
||||
delete m_ssa_ranges[x];
|
||||
}
|
||||
// Release the vector itself.
|
||||
m_ssa_ranges.release ();
|
||||
}
|
||||
|
||||
// Return a reference to the m_block_cache for NAME. If it has not been
|
||||
// accessed yet, allocate it.
|
||||
|
||||
ssa_block_ranges &
|
||||
block_range_cache::get_block_ranges (tree name)
|
||||
{
|
||||
unsigned v = SSA_NAME_VERSION (name);
|
||||
if (v >= m_ssa_ranges.length ())
|
||||
m_ssa_ranges.safe_grow_cleared (num_ssa_names + 1);
|
||||
|
||||
if (!m_ssa_ranges[v])
|
||||
m_ssa_ranges[v] = new ssa_block_ranges (TREE_TYPE (name));
|
||||
|
||||
return *(m_ssa_ranges[v]);
|
||||
}
|
||||
|
||||
// Set the range for NAME on entry to block BB to R.
|
||||
|
||||
void
|
||||
block_range_cache::set_bb_range (tree name, const basic_block bb,
|
||||
const irange &r)
|
||||
{
|
||||
return get_block_ranges (name).set_bb_range (bb, r);
|
||||
}
|
||||
|
||||
// Set the range for NAME on entry to block BB to varying..
|
||||
|
||||
void
|
||||
block_range_cache::set_bb_varying (tree name, const basic_block bb)
|
||||
{
|
||||
return get_block_ranges (name).set_bb_varying (bb);
|
||||
}
|
||||
|
||||
// Return the range for NAME on entry to BB in R. Return true if here
|
||||
// is one.
|
||||
|
||||
bool
|
||||
block_range_cache::get_bb_range (irange &r, tree name, const basic_block bb)
|
||||
{
|
||||
return get_block_ranges (name).get_bb_range (r, bb);
|
||||
}
|
||||
|
||||
// Return true if NAME has a range set in block BB.
|
||||
|
||||
bool
|
||||
block_range_cache::bb_range_p (tree name, const basic_block bb)
|
||||
{
|
||||
return get_block_ranges (name).bb_range_p (bb);
|
||||
}
|
||||
|
||||
// Print all known block caches to file F.
|
||||
void
|
||||
block_range_cache::dump (FILE *f)
|
||||
{
|
||||
unsigned x;
|
||||
for (x = 0; x < m_ssa_ranges.length (); ++x)
|
||||
{
|
||||
if (m_ssa_ranges[x])
|
||||
{
|
||||
fprintf (f, " Ranges for ");
|
||||
print_generic_expr (f, ssa_name (x), TDF_NONE);
|
||||
fprintf (f, ":\n");
|
||||
m_ssa_ranges[x]->dump (f);
|
||||
fprintf (f, "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Print all known ranges on entry to blobk BB to file F.
|
||||
void
|
||||
block_range_cache::dump (FILE *f, basic_block bb, bool print_varying)
|
||||
{
|
||||
unsigned x;
|
||||
widest_irange r;
|
||||
bool summarize_varying = false;
|
||||
for (x = 1; x < m_ssa_ranges.length (); ++x)
|
||||
{
|
||||
if (!gimple_range_ssa_p (ssa_name (x)))
|
||||
continue;
|
||||
if (m_ssa_ranges[x] && m_ssa_ranges[x]->get_bb_range (r, bb))
|
||||
{
|
||||
if (!print_varying && r.varying_p ())
|
||||
{
|
||||
summarize_varying = true;
|
||||
continue;
|
||||
}
|
||||
print_generic_expr (f, ssa_name (x), TDF_NONE);
|
||||
fprintf (f, "\t");
|
||||
r.dump(f);
|
||||
fprintf (f, "\n");
|
||||
}
|
||||
}
|
||||
// If there were any varying entries, lump them all together.
|
||||
if (summarize_varying)
|
||||
{
|
||||
fprintf (f, "VARYING_P on entry : ");
|
||||
for (x = 1; x < num_ssa_names; ++x)
|
||||
{
|
||||
if (!gimple_range_ssa_p (ssa_name (x)))
|
||||
continue;
|
||||
if (m_ssa_ranges[x] && m_ssa_ranges[x]->get_bb_range (r, bb))
|
||||
{
|
||||
if (r.varying_p ())
|
||||
{
|
||||
print_generic_expr (f, ssa_name (x), TDF_NONE);
|
||||
fprintf (f, " ");
|
||||
}
|
||||
}
|
||||
}
|
||||
fprintf (f, "\n");
|
||||
}
|
||||
}
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
// Initialize a global cache.
|
||||
|
||||
ssa_global_cache::ssa_global_cache ()
|
||||
{
|
||||
m_tab.create (0);
|
||||
m_tab.safe_grow_cleared (num_ssa_names);
|
||||
}
|
||||
|
||||
// Deconstruct a global cache.
|
||||
|
||||
ssa_global_cache::~ssa_global_cache ()
|
||||
{
|
||||
m_tab.release ();
|
||||
}
|
||||
|
||||
// Retrieve the global range of NAME from cache memory if it exists.
|
||||
// Return the value in R.
|
||||
|
||||
bool
|
||||
ssa_global_cache::get_global_range (irange &r, tree name) const
|
||||
{
|
||||
unsigned v = SSA_NAME_VERSION (name);
|
||||
if (v >= m_tab.length ())
|
||||
return false;
|
||||
|
||||
irange_storage *stow = m_tab[v];
|
||||
if (!stow)
|
||||
return false;
|
||||
r = irange_storage (*stow);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Set the range for NAME to R in the global cache.
|
||||
|
||||
void
|
||||
ssa_global_cache::set_global_range (tree name, const irange &r)
|
||||
{
|
||||
unsigned v = SSA_NAME_VERSION (name);
|
||||
if (v >= m_tab.length ())
|
||||
m_tab.safe_grow_cleared (num_ssa_names + 1);
|
||||
irange_storage *m = m_tab[v];
|
||||
|
||||
// Fixme update in place it if fits.
|
||||
// if (m && m->update (r, TREE_TYPE (name)))
|
||||
// ;
|
||||
// else
|
||||
{
|
||||
// m = irange_storage::alloc (r, TREE_TYPE (name));
|
||||
m = new irange_storage (r);
|
||||
m_tab[SSA_NAME_VERSION (name)] = m;
|
||||
}
|
||||
}
|
||||
|
||||
// Set the range for NAME to R in the glonbal cache.
|
||||
|
||||
void
|
||||
ssa_global_cache::clear_global_range (tree name)
|
||||
{
|
||||
unsigned v = SSA_NAME_VERSION (name);
|
||||
if (v >= m_tab.length ())
|
||||
m_tab.safe_grow_cleared (num_ssa_names + 1);
|
||||
m_tab[v] = NULL;
|
||||
}
|
||||
|
||||
// Clear the global cache.
|
||||
|
||||
void
|
||||
ssa_global_cache::clear ()
|
||||
{
|
||||
memset (m_tab.address(), 0, m_tab.length () * sizeof (irange_storage *));
|
||||
}
|
||||
|
||||
// Dump the contents of the global cache to F.
|
||||
|
||||
void
|
||||
ssa_global_cache::dump (FILE *f)
|
||||
{
|
||||
unsigned x;
|
||||
widest_irange r;
|
||||
fprintf (f, "Non-varying global ranges:\n");
|
||||
fprintf (f, "=========================:\n");
|
||||
for ( x = 1; x < num_ssa_names; x++)
|
||||
if (gimple_range_ssa_p (ssa_name (x)) &&
|
||||
get_global_range (r, ssa_name (x)) && !r.varying_p ())
|
||||
{
|
||||
print_generic_expr (f, ssa_name (x), TDF_NONE);
|
||||
fprintf (f, " : ");
|
||||
r.dump (f);
|
||||
fprintf (f, "\n");
|
||||
}
|
||||
fputc ('\n', f);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ranger_cache::ranger_cache ()
|
||||
{
|
||||
m_workback.create (0);
|
||||
m_workback.safe_grow_cleared (last_basic_block_for_fn (cfun));
|
||||
m_update_list.create (0);
|
||||
m_update_list.safe_grow_cleared (last_basic_block_for_fn (cfun));
|
||||
m_update_list.truncate (0);
|
||||
}
|
||||
|
||||
ranger_cache::~ranger_cache ()
|
||||
{
|
||||
m_workback.release ();
|
||||
m_update_list.release ();
|
||||
}
|
||||
|
||||
|
||||
// Provide lookup for the gori-computes class to access the best known range
|
||||
// of an ssa_name in any given basic block. NOte this does no additonal
|
||||
// lookups, just accesses the data that is already known.
|
||||
|
||||
void
|
||||
ranger_cache::ssa_range_in_bb (irange &r, tree name, basic_block bb)
|
||||
{
|
||||
gimple *s = SSA_NAME_DEF_STMT (name);
|
||||
basic_block def_bb = ((s && gimple_bb (s)) ? gimple_bb (s) :
|
||||
ENTRY_BLOCK_PTR_FOR_FN (cfun));
|
||||
if (bb == def_bb || !m_on_entry.get_bb_range (r, name, bb))
|
||||
{
|
||||
// Try to pick up any known value first.
|
||||
if (!m_globals.get_global_range (r, name))
|
||||
r = gimple_range_global (name);
|
||||
}
|
||||
|
||||
// Check if pointers have any non-null dereferences. Non-call
|
||||
// exceptions mean we could throw in the middle of he block, so just
|
||||
// punt for now on those.
|
||||
if (r.varying_p () && m_non_null.non_null_deref_p (name, bb) &&
|
||||
!cfun->can_throw_non_call_exceptions)
|
||||
r = range_nonzero (TREE_TYPE (name));
|
||||
}
|
||||
|
||||
|
||||
// Return a static range for NAME on entry to basic block BB in R. If
|
||||
// calc is true, fill any cache entries required between BB and the
|
||||
// def block for NAME. Otherwise, return false if the cache is empty.
|
||||
|
||||
bool
|
||||
ranger_cache::block_range (irange &r, basic_block bb, tree name, bool calc)
|
||||
{
|
||||
gcc_checking_assert (gimple_range_ssa_p (name));
|
||||
|
||||
if (calc)
|
||||
{
|
||||
gimple *def_stmt = SSA_NAME_DEF_STMT (name);
|
||||
basic_block def_bb = NULL;
|
||||
if (def_stmt)
|
||||
def_bb = gimple_bb (def_stmt);;
|
||||
if (!def_bb)
|
||||
{
|
||||
// If we get to the entry block, this better be a default def
|
||||
// or range_on_entry was called for a block not dominated by
|
||||
// the def. This would be a bug.
|
||||
gcc_checking_assert (SSA_NAME_IS_DEFAULT_DEF (name));
|
||||
def_bb = ENTRY_BLOCK_PTR_FOR_FN (cfun);
|
||||
}
|
||||
|
||||
// There is no range on entry for the defintion block.
|
||||
if (def_bb == bb)
|
||||
return false;
|
||||
|
||||
// Otherwise, go figure out what is known in predecessor blocks.
|
||||
fill_block_cache (name, bb, def_bb);
|
||||
gcc_checking_assert (m_on_entry.bb_range_p (name, bb));
|
||||
}
|
||||
return m_on_entry.get_bb_range (r, name, bb);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ranger_cache::add_to_update (basic_block bb)
|
||||
{
|
||||
if (!m_update_list.contains (bb))
|
||||
m_update_list.quick_push (bb);
|
||||
}
|
||||
|
||||
#define DEBUG_CACHE (0 && dump_file)
|
||||
|
||||
// If there is anything in the iterative update_list, continue
|
||||
// processing NAME until the list of blocks is empty.
|
||||
|
||||
void
|
||||
ranger_cache::iterative_cache_update (tree name)
|
||||
{
|
||||
basic_block bb;
|
||||
edge_iterator ei;
|
||||
edge e;
|
||||
widest_irange new_range;
|
||||
widest_irange current_range;
|
||||
widest_irange e_range;
|
||||
|
||||
// Process each block by seeing if it's calculated range on entry is
|
||||
// the same as it's cached value. IF there is a difference, update
|
||||
// the cache to reflect the new value, and check to see if any
|
||||
// successors have cache entries which may need to be checked for
|
||||
// updates.
|
||||
|
||||
while (m_update_list.length () > 0)
|
||||
{
|
||||
bb = m_update_list.pop ();
|
||||
if (DEBUG_CACHE) fprintf (dump_file, "FWD visiting block %d\n", bb->index);
|
||||
|
||||
gcc_assert (m_on_entry.get_bb_range (current_range, name, bb));
|
||||
// Calculate the "new" range on entry by unioning the pred edges..
|
||||
new_range.set_undefined ();
|
||||
FOR_EACH_EDGE (e, ei, bb->preds)
|
||||
{
|
||||
// Get whatever range we can for this edge
|
||||
if (!outgoing_edge_range_p (e_range, e, name))
|
||||
ssa_range_in_bb (e_range, name, e->src);
|
||||
new_range.union_ (e_range);
|
||||
if (new_range.varying_p ())
|
||||
break;
|
||||
}
|
||||
// If the range on entry has changed, update it.
|
||||
if (new_range != current_range)
|
||||
{
|
||||
if (DEBUG_CACHE) { fprintf (dump_file, "updating range from/to "); current_range.dump (dump_file); new_range.dump (dump_file); }
|
||||
m_on_entry.set_bb_range (name, bb, new_range);
|
||||
// Mark each successor that has a range to re-check it's range
|
||||
FOR_EACH_EDGE (e, ei, bb->succs)
|
||||
if (m_on_entry.bb_range_p (name, e->dest))
|
||||
add_to_update (e->dest);
|
||||
}
|
||||
}
|
||||
if (DEBUG_CACHE) fprintf (dump_file, "DONE visiting blocks \n\n");
|
||||
}
|
||||
|
||||
// Make sure that the range-on-entry cache for NAME is set for block BB.
|
||||
// Work back thourgh the CFG to DEF_BB ensuring the range is calculated
|
||||
// on the block/edges leading back to that point.
|
||||
|
||||
void
|
||||
ranger_cache::fill_block_cache (tree name, basic_block bb, basic_block def_bb)
|
||||
{
|
||||
edge_iterator ei;
|
||||
edge e;
|
||||
widest_irange block_result;
|
||||
widest_irange undefined;
|
||||
|
||||
// At this point we shouldnt be looking at the def, entry or exit block.
|
||||
gcc_checking_assert (bb != def_bb && bb != ENTRY_BLOCK_PTR_FOR_FN (cfun) &&
|
||||
bb != EXIT_BLOCK_PTR_FOR_FN (cfun));
|
||||
|
||||
// If the block cache is set, then we've already visited this block.
|
||||
if (m_on_entry.bb_range_p (name, bb))
|
||||
return;
|
||||
|
||||
// Visit each block back to the DEF. Initialize each one to UNDEFINED.
|
||||
// m_visited at the end will contain all the blocks that we needed to set
|
||||
// the range_on_entry cache for.
|
||||
m_workback.truncate (0);
|
||||
m_workback.quick_push (bb);
|
||||
undefined.set_undefined ();
|
||||
m_on_entry.set_bb_range (name, bb, undefined);
|
||||
gcc_checking_assert (m_update_list.length () == 0);
|
||||
|
||||
if (DEBUG_CACHE) { fprintf (dump_file, "\n"); print_generic_expr (dump_file, name, TDF_SLIM); fprintf (dump_file, " : "); }
|
||||
|
||||
while (m_workback.length () > 0)
|
||||
{
|
||||
basic_block node = m_workback.pop ();
|
||||
if (DEBUG_CACHE) fprintf (dump_file, "BACK visiting block %d\n", node->index);
|
||||
|
||||
FOR_EACH_EDGE (e, ei, node->preds)
|
||||
{
|
||||
basic_block pred = e->src;
|
||||
widest_irange r;
|
||||
// If the pred block is the def block add this BB to update list.
|
||||
if (pred == def_bb)
|
||||
{
|
||||
add_to_update (node);
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the pred is entry but NOT def, then it is used before
|
||||
// defined, it'll get set to []. and no need to update it.
|
||||
if (pred == ENTRY_BLOCK_PTR_FOR_FN (cfun))
|
||||
continue;
|
||||
|
||||
// Regardless of whther we have visited pred or not, if the pred has
|
||||
// a non-null reference, revisit this block.
|
||||
if (m_non_null.non_null_deref_p (name, pred))
|
||||
add_to_update (node);
|
||||
|
||||
// If the pred block already has a range, or if it can contribute
|
||||
// something new. Ie, the edge generates a range of some sort.
|
||||
if (m_on_entry.get_bb_range (r, name, pred))
|
||||
{
|
||||
if (!r.undefined_p () || has_edge_range_p (e, name))
|
||||
add_to_update (node);
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the pred hasn't been visited (has no range), add it to
|
||||
// the list.
|
||||
gcc_checking_assert (!m_on_entry.bb_range_p (name, pred));
|
||||
m_on_entry.set_bb_range (name, pred, undefined);
|
||||
m_workback.quick_push (pred);
|
||||
}
|
||||
}
|
||||
|
||||
iterative_cache_update (name);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
110
gcc/gimple-range-cache.h
Normal file
110
gcc/gimple-range-cache.h
Normal file
@@ -0,0 +1,110 @@
|
||||
/* Header file for gimple ranger SSA cache.
|
||||
Copyright (C) 2017-2020 Free Software Foundation, Inc.
|
||||
Contributed by Andrew MacLeod <amacleod@redhat.com>.
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
GCC is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 3, or (at your option) any later
|
||||
version.
|
||||
|
||||
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GCC; see the file COPYING3. If not see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef GCC_SSA_RANGE_CACHE_H
|
||||
#define GCC_SSA_RANGE_CACHE_H
|
||||
|
||||
#include "gimple-range-gori.h"
|
||||
|
||||
// This global cache is used with the range engine as markers for what
|
||||
// has been visited during this incarnation. Once the ranger evaluates
|
||||
// a name, it is typically not re-evaluated again.
|
||||
|
||||
typedef int_range<3> irange_storage;
|
||||
|
||||
class ssa_global_cache
|
||||
{
|
||||
public:
|
||||
ssa_global_cache ();
|
||||
~ssa_global_cache ();
|
||||
bool get_global_range (irange &r, tree name) const;
|
||||
void set_global_range (tree name, const irange &r);
|
||||
void clear_global_range (tree name);
|
||||
void clear ();
|
||||
void dump (FILE *f = stderr);
|
||||
private:
|
||||
vec<irange_storage *> m_tab;
|
||||
};
|
||||
|
||||
// This class manages a vector of pointers to ssa_block ranges. It
|
||||
// provides the basis for the "range on entry" cache for all
|
||||
// SSA names.
|
||||
|
||||
class block_range_cache
|
||||
{
|
||||
public:
|
||||
block_range_cache ();
|
||||
~block_range_cache ();
|
||||
|
||||
void set_bb_range (tree name, const basic_block bb, const irange &r);
|
||||
void set_bb_varying (tree name, const basic_block bb);
|
||||
bool get_bb_range (irange &r, tree name, const basic_block bb);
|
||||
bool bb_range_p (tree name, const basic_block bb);
|
||||
|
||||
void dump (FILE *f);
|
||||
void dump (FILE *f, basic_block bb, bool print_varying = true);
|
||||
private:
|
||||
vec<class ssa_block_ranges *> m_ssa_ranges;
|
||||
ssa_block_ranges &get_block_ranges (tree name);
|
||||
};
|
||||
|
||||
// Class used to track non-null references of an SSA name. A vector
|
||||
// of bitmaps indexed by SSA name is maintained. When indexed by
|
||||
// basic block, an on-bit indicates there is a non-null dereference
|
||||
// for that SSA in that block.
|
||||
|
||||
class non_null_ref
|
||||
{
|
||||
public:
|
||||
non_null_ref ();
|
||||
~non_null_ref ();
|
||||
bool non_null_deref_p (tree name, basic_block bb);
|
||||
private:
|
||||
vec <bitmap> m_nn;
|
||||
void process_name (tree name);
|
||||
};
|
||||
|
||||
// THis class provides all the caches a global ranger may needs, and makes
|
||||
// them available for gori-computes to query so outgoing edges can be
|
||||
// properly calculated.
|
||||
//
|
||||
class ranger_cache : public gori_compute_cache
|
||||
{
|
||||
public:
|
||||
ranger_cache ();
|
||||
~ranger_cache ();
|
||||
|
||||
virtual void ssa_range_in_bb (irange &r, tree name, basic_block bb);
|
||||
bool block_range (irange &r, basic_block bb, tree name, bool calc = true);
|
||||
|
||||
ssa_global_cache m_globals;
|
||||
block_range_cache m_on_entry;
|
||||
non_null_ref m_non_null;
|
||||
private:
|
||||
void add_to_update (basic_block bb);
|
||||
void fill_block_cache (tree name, basic_block bb, basic_block def_bb);
|
||||
void iterative_cache_update (tree name);
|
||||
|
||||
vec<basic_block> m_workback;
|
||||
vec<basic_block> m_update_list;
|
||||
|
||||
};
|
||||
|
||||
#endif // GCC_SSA_RANGE_CACHE_H
|
||||
1456
gcc/gimple-range-gori.cc
Normal file
1456
gcc/gimple-range-gori.cc
Normal file
File diff suppressed because it is too large
Load Diff
92
gcc/gimple-range-gori.h
Normal file
92
gcc/gimple-range-gori.h
Normal file
@@ -0,0 +1,92 @@
|
||||
/* Header file for gimple range GORI structures.
|
||||
Copyright (C) 2017-2020 Free Software Foundation, Inc.
|
||||
Contributed by Andrew MacLeod <amacleod@redhat.com>
|
||||
and Aldy Hernandez <aldyh@redhat.com>.
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
GCC is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 3, or (at your option) any later
|
||||
version.
|
||||
|
||||
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GCC; see the file COPYING3. If not see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef GCC_GIMPLE_RANGE_GORI_H
|
||||
#define GCC_GIMPLE_RANGE_GORI_H
|
||||
|
||||
|
||||
// This class utilizes a GORI map to determine which SSA_NAMES can
|
||||
// have ranges calculated for them on outgoing edges from basic
|
||||
// blocks.
|
||||
|
||||
class gori_compute
|
||||
{
|
||||
public:
|
||||
gori_compute ();
|
||||
~gori_compute ();
|
||||
bool outgoing_edge_range_p (irange &r, edge e, tree name);
|
||||
bool has_edge_range_p (edge e, tree name);
|
||||
void dump (FILE *f);
|
||||
protected:
|
||||
virtual void ssa_range_in_bb (irange &r, tree name, basic_block bb) = 0;
|
||||
virtual bool compute_operand_range (irange &r, gimple *stmt,
|
||||
const irange &lhs, tree name);
|
||||
|
||||
void expr_range_in_bb (irange &r, tree expr, basic_block bb);
|
||||
bool compute_logical_operands (irange &r, gimple *stmt,
|
||||
const irange &lhs,
|
||||
tree name);
|
||||
void compute_logical_operands_in_chain (class tf_range &range,
|
||||
gimple *stmt, const irange &lhs,
|
||||
tree name, tree op, bool op_in_chain);
|
||||
bool optimize_logical_operands (tf_range &range, gimple *stmt,
|
||||
const irange &lhs, tree name, tree op);
|
||||
|
||||
bool logical_combine (irange &r, enum tree_code code, const irange &lhs,
|
||||
const class tf_range &op1_range,
|
||||
const class tf_range &op2_range);
|
||||
int_range<1> m_bool_zero; // Boolean false cached.
|
||||
int_range<1> m_bool_one; // Boolean true cached.
|
||||
|
||||
private:
|
||||
bool compute_operand_range_switch (irange &r, gswitch *stmt,
|
||||
const irange &lhs, tree name);
|
||||
bool compute_name_range_op (irange &r, gimple *stmt, const irange &lhs,
|
||||
tree name);
|
||||
bool compute_operand1_range (irange &r, gimple *stmt, const irange &lhs,
|
||||
tree name);
|
||||
bool compute_operand2_range (irange &r, gimple *stmt, const irange &lhs,
|
||||
tree name);
|
||||
bool compute_operand1_and_operand2_range (irange &r, gimple *stmt,
|
||||
const irange &lhs, tree name);
|
||||
|
||||
class gori_map *m_gori_map;
|
||||
};
|
||||
|
||||
class gori_compute_cache : public gori_compute
|
||||
{
|
||||
public:
|
||||
gori_compute_cache ();
|
||||
~gori_compute_cache ();
|
||||
protected:
|
||||
virtual bool compute_operand_range (irange &r, gimple *stmt,
|
||||
const irange &lhs, tree name);
|
||||
private:
|
||||
void cache_comparison (gimple *);
|
||||
void cache_comparison_with_int (gimple *, enum tree_code,
|
||||
tree op1, tree op2);
|
||||
void cache_comparison_with_ssa (gimple *, enum tree_code,
|
||||
tree op1, tree op2);
|
||||
typedef gori_compute super;
|
||||
class logical_stmt_cache *m_cache;
|
||||
};
|
||||
|
||||
#endif // GCC_GIMPLE_RANGE_GORI_H
|
||||
190
gcc/gimple-range-vrp.cc
Normal file
190
gcc/gimple-range-vrp.cc
Normal file
@@ -0,0 +1,190 @@
|
||||
/* Value range propagation pass using the ranger.
|
||||
Copyright (C) 2020 Free Software Foundation, Inc.
|
||||
Contributed by Aldy Hernandez <aldyh@redhat.com>.
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
GCC is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3, or (at your option)
|
||||
any later version.
|
||||
|
||||
GCC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GCC; see the file COPYING3. If not see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "config.h"
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "backend.h"
|
||||
#include "tree.h"
|
||||
#include "gimple.h"
|
||||
#include "tree-pass.h"
|
||||
#include "ssa.h"
|
||||
#include "gimple-pretty-print.h"
|
||||
#include "cfganal.h"
|
||||
#include "gimple-fold.h"
|
||||
#include "tree-eh.h"
|
||||
#include "gimple-iterator.h"
|
||||
#include "tree-cfg.h"
|
||||
#include "tree-ssa-loop-manip.h"
|
||||
#include "tree-ssa-loop.h"
|
||||
#include "cfgloop.h"
|
||||
#include "tree-scalar-evolution.h"
|
||||
#include "tree-ssa-propagate.h"
|
||||
#include "alloc-pool.h"
|
||||
#include "domwalk.h"
|
||||
#include "tree-cfgcleanup.h"
|
||||
#include "vr-values.h"
|
||||
#include "gimple-ssa-evrp-analyze.h"
|
||||
#include "gimple-range.h"
|
||||
|
||||
class rvrp_ranger : public range_store
|
||||
{
|
||||
public:
|
||||
rvrp_ranger () : range_pool ("rvrp value range pool") { }
|
||||
~rvrp_ranger ()
|
||||
{
|
||||
range_pool.release ();
|
||||
}
|
||||
// This is the range getter for the simplifier, but is really only
|
||||
// used for the conditional folding which still uses equivalences.
|
||||
virtual const value_range_equiv *get_value_range (const_tree expr,
|
||||
gimple *stmt) OVERRIDE
|
||||
{
|
||||
widest_irange r;
|
||||
if (ranger.range_of_expr (r, const_cast<tree> (expr), stmt))
|
||||
return new (range_pool.allocate ()) value_range_equiv (r);
|
||||
return new (range_pool.allocate ()) value_range_equiv (TREE_TYPE (expr));
|
||||
}
|
||||
virtual bool range_of_expr (irange &r, tree expr, gimple *stmt = NULL)
|
||||
{
|
||||
return ranger.range_of_expr (r, expr, stmt);
|
||||
}
|
||||
gimple_ranger ranger;
|
||||
private:
|
||||
object_allocator<value_range_equiv> range_pool;
|
||||
};
|
||||
|
||||
class rvrp_folder : public substitute_and_fold_engine
|
||||
{
|
||||
public:
|
||||
rvrp_folder (bool allow_il_changes)
|
||||
: simplifier (&ranger), allow_il_changes (allow_il_changes) { }
|
||||
|
||||
tree get_value (tree op, gimple *stmt) OVERRIDE
|
||||
{
|
||||
widest_irange r;
|
||||
tree singleton;
|
||||
if (ranger.ranger.range_of_expr (r, op, stmt) && r.singleton_p (&singleton)
|
||||
&& allow_il_changes)
|
||||
return singleton;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool fold_cond (gcond *cond)
|
||||
{
|
||||
if (!irange::supports_type_p (gimple_expr_type (cond)))
|
||||
return false;
|
||||
|
||||
widest_irange r;
|
||||
if (ranger.ranger.range_of_stmt (r, cond) && r.singleton_p ())
|
||||
{
|
||||
if (allow_il_changes)
|
||||
{
|
||||
if (r.zero_p ())
|
||||
gimple_cond_make_false (cond);
|
||||
else
|
||||
gimple_cond_make_true (cond);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool fold_stmt (gimple_stmt_iterator *gsi) OVERRIDE
|
||||
{
|
||||
gcond *cond = dyn_cast <gcond *> (gsi_stmt (*gsi));
|
||||
if (cond && fold_cond (cond))
|
||||
return true;
|
||||
|
||||
if (allow_il_changes)
|
||||
return simplifier.simplify (gsi);
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
rvrp_ranger ranger;
|
||||
simplify_using_ranges simplifier;
|
||||
bool allow_il_changes;
|
||||
};
|
||||
|
||||
static unsigned int
|
||||
execute_ranger_vrp (bool allow_il_changes)
|
||||
{
|
||||
loop_optimizer_init (LOOPS_NORMAL | LOOPS_HAVE_RECORDED_EXITS);
|
||||
rewrite_into_loop_closed_ssa (NULL, TODO_update_ssa);
|
||||
scev_initialize ();
|
||||
calculate_dominance_info (CDI_DOMINATORS);
|
||||
|
||||
rvrp_folder folder (allow_il_changes);
|
||||
folder.substitute_and_fold ();
|
||||
|
||||
scev_finalize ();
|
||||
loop_optimizer_finalize ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
const pass_data pass_data_ranger_vrp =
|
||||
{
|
||||
GIMPLE_PASS, // type
|
||||
"rvrp", // name
|
||||
OPTGROUP_NONE, // optinfo_flags
|
||||
TV_TREE_EARLY_VRP, // tv_id
|
||||
PROP_ssa, // properties_required
|
||||
0, // properties_provided
|
||||
0, // properties_destroyed
|
||||
0, // todo_flags_start
|
||||
( TODO_cleanup_cfg | TODO_update_ssa | TODO_verify_all ),
|
||||
};
|
||||
|
||||
class pass_ranger_vrp : public gimple_opt_pass
|
||||
{
|
||||
public:
|
||||
pass_ranger_vrp (gcc::context *ctxt)
|
||||
: gimple_opt_pass (pass_data_ranger_vrp, ctxt)
|
||||
{
|
||||
static int pass = 1;
|
||||
rvrp_pass_num = pass;
|
||||
pass++;
|
||||
}
|
||||
opt_pass *clone () { return new pass_ranger_vrp (m_ctxt); }
|
||||
virtual bool gate (function *)
|
||||
{ return flag_tree_vrp != 0; }
|
||||
virtual unsigned int execute (function *)
|
||||
{
|
||||
if (rvrp_pass_num == 1)
|
||||
allow_il_changes = flag_rvrp1_changes;
|
||||
if (rvrp_pass_num == 2)
|
||||
allow_il_changes = flag_rvrp2_changes;
|
||||
return execute_ranger_vrp (allow_il_changes);
|
||||
}
|
||||
private:
|
||||
bool allow_il_changes;
|
||||
int rvrp_pass_num;
|
||||
};
|
||||
|
||||
} // anon namespace
|
||||
|
||||
gimple_opt_pass *
|
||||
make_pass_ranger_vrp (gcc::context *ctxt)
|
||||
{
|
||||
return new pass_ranger_vrp (ctxt);
|
||||
}
|
||||
1309
gcc/gimple-range.cc
Normal file
1309
gcc/gimple-range.cc
Normal file
File diff suppressed because it is too large
Load Diff
160
gcc/gimple-range.h
Normal file
160
gcc/gimple-range.h
Normal file
@@ -0,0 +1,160 @@
|
||||
/* Header file for the GIMPLE range interface.
|
||||
Copyright (C) 2019-2020 Free Software Foundation, Inc.
|
||||
Contributed by Andrew MacLeod <amacleod@redhat.com>
|
||||
and Aldy Hernandez <aldyh@redhat.com>.
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
GCC is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 3, or (at your option) any later
|
||||
version.
|
||||
|
||||
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GCC; see the file COPYING3. If not see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef GCC_GIMPLE_RANGE_STMT_H
|
||||
#define GCC_GIMPLE_RANGE_STMT_H
|
||||
|
||||
|
||||
#include "range.h"
|
||||
#include "range-op.h"
|
||||
#include "gimple-range-gori.h"
|
||||
#include "gimple-range-cache.h"
|
||||
|
||||
// This is the basic range generator interface.
|
||||
//
|
||||
// This base class provides all the API entry points, but only provides
|
||||
// functionality at the statement level. Ie, it can calculate ranges on
|
||||
// statements, but does no additonal lookup.
|
||||
//
|
||||
// All the range_of_* methods will return a range if the types is
|
||||
// supported by the range engine. It may be the full range for the
|
||||
// type, AKA varying_p or it may be a refined range. If the range
|
||||
// type is not supported, then false is returned. Non-statement
|
||||
// related methods return whatever the current global value is.
|
||||
|
||||
|
||||
class gimple_ranger
|
||||
{
|
||||
public:
|
||||
virtual bool range_of_stmt (irange &r, gimple *s, tree name = NULL_TREE);
|
||||
virtual bool range_of_expr (irange &r, tree name, gimple *stmt = NULL);
|
||||
virtual void range_on_edge (irange &r, edge e, tree name);
|
||||
virtual void range_on_entry (irange &r, basic_block bb, tree name);
|
||||
virtual void range_on_exit (irange &r, basic_block bb, tree name);
|
||||
void export_global_ranges ();
|
||||
void dump (FILE *f);
|
||||
protected:
|
||||
bool calc_stmt (irange &r, gimple *s, tree name = NULL_TREE);
|
||||
bool range_of_range_op (irange &r, gimple *s);
|
||||
bool range_of_call (irange &r, gcall *call);
|
||||
bool range_of_cond_expr (irange &r, gassign* cond);
|
||||
ranger_cache m_cache;
|
||||
private:
|
||||
bool range_of_phi (irange &r, gphi *phi);
|
||||
bool range_of_non_trivial_assignment (irange &r, gimple *s);
|
||||
bool range_of_builtin_call (irange &r, gcall *call);
|
||||
void range_of_builtin_ubsan_call (irange &r, gcall *call, tree_code code);
|
||||
};
|
||||
|
||||
|
||||
// A global ranger that uses SCEV/loop (if available) to refine PHI results.
|
||||
|
||||
class loop_ranger : public gimple_ranger
|
||||
{
|
||||
public:
|
||||
loop_ranger ();
|
||||
~loop_ranger ();
|
||||
virtual void range_on_edge (irange &r, edge e, tree name);
|
||||
virtual bool range_of_stmt (irange &r, gimple *stmt, tree name = NULL_TREE);
|
||||
|
||||
private:
|
||||
typedef gimple_ranger super;
|
||||
bool range_with_loop_info (irange &r, tree name);
|
||||
void range_of_ssa_name_with_loop_info (irange &, tree, class loop *,
|
||||
gphi *);
|
||||
|
||||
class vr_values *m_vr_values;
|
||||
};
|
||||
|
||||
// Calculate a basic range for a tree expression.
|
||||
extern bool get_tree_range (irange &r, tree expr);
|
||||
|
||||
// If BB ends with a range generating stmt, return its GSI.
|
||||
extern gimple_stmt_iterator gsi_outgoing_range_stmt (basic_block bb);
|
||||
// If BB ends with a range generating stmt, return that stmt.
|
||||
extern gimple *gimple_outgoing_range_stmt_p (basic_block bb);
|
||||
// If edge E has a constant range, return it and the range generating
|
||||
// statement. for conditonals its TRUE/FALSE, for switches its the
|
||||
// possible cases.
|
||||
extern gimple *gimple_outgoing_edge_range_p (irange &r, edge e);
|
||||
|
||||
// These routines provide a GIMPLE interface to the range-ops code.
|
||||
extern tree gimple_range_operand1 (const gimple *s);
|
||||
extern tree gimple_range_operand2 (const gimple *s);
|
||||
extern tree gimple_range_base_of_assignment (const gimple *s);
|
||||
extern bool gimple_range_fold (irange &res, const gimple *s,
|
||||
const irange &r1);
|
||||
extern bool gimple_range_fold (irange &res, const gimple *s,
|
||||
const irange &r1,
|
||||
const irange &r2);
|
||||
extern bool gimple_range_calc_op1 (irange &r, const gimple *s,
|
||||
const irange &lhs_range);
|
||||
extern bool gimple_range_calc_op1 (irange &r, const gimple *s,
|
||||
const irange &lhs_range,
|
||||
const irange &op2_range);
|
||||
extern bool gimple_range_calc_op2 (irange &r, const gimple *s,
|
||||
const irange &lhs_range,
|
||||
const irange &op1_range);
|
||||
|
||||
|
||||
// Return the range_operator pointer for this statement. This routine
|
||||
// can also be used to gate whether a routine is range-ops enabled.
|
||||
|
||||
static inline range_operator *
|
||||
gimple_range_handler (const gimple *s)
|
||||
{
|
||||
if ((gimple_code (s) == GIMPLE_ASSIGN) || (gimple_code (s) == GIMPLE_COND))
|
||||
return range_op_handler (gimple_expr_code (s), gimple_expr_type (s));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Return EXP if it is an SSA_NAME with a type supported by gimple ranges.
|
||||
|
||||
static inline tree
|
||||
gimple_range_ssa_p (tree exp)
|
||||
{
|
||||
if (exp && TREE_CODE (exp) == SSA_NAME &&
|
||||
!SSA_NAME_IS_VIRTUAL_OPERAND (exp) &&
|
||||
irange::supports_type_p (TREE_TYPE (exp)))
|
||||
return exp;
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
// Return the legacy GCC global range for NAME if it has one, otherwise
|
||||
// return VARYING.
|
||||
|
||||
static inline value_range
|
||||
gimple_range_global (tree name)
|
||||
{
|
||||
gcc_checking_assert (gimple_range_ssa_p (name));
|
||||
tree type = TREE_TYPE (name);
|
||||
if (!POINTER_TYPE_P (type) && SSA_NAME_RANGE_INFO (name))
|
||||
{
|
||||
// Return a range from an SSA_NAME's available range.
|
||||
wide_int min, max;
|
||||
enum value_range_kind kind = get_range_info (name, &min, &max);
|
||||
return value_range (type, min, max, kind);
|
||||
}
|
||||
// Otherwise return range for the type.
|
||||
return value_range (type);
|
||||
}
|
||||
|
||||
#endif // GCC_GIMPLE_RANGE_STMT_H
|
||||
@@ -50,7 +50,10 @@ class evrp_range_analyzer
|
||||
|
||||
/* A bit of a wart. This should ideally go away. */
|
||||
void vrp_visit_cond_stmt (gcond *cond, edge *e)
|
||||
{ return vr_values->vrp_visit_cond_stmt (cond, e); }
|
||||
{
|
||||
simplify_using_ranges simpl (vr_values);
|
||||
simpl.vrp_visit_cond_stmt (cond, e);
|
||||
}
|
||||
|
||||
/* Get the underlying vr_values class instance. If TRANSFER is
|
||||
true, then we are transferring ownership. Else we keep ownership.
|
||||
|
||||
@@ -41,19 +41,19 @@ along with GCC; see the file COPYING3. If not see
|
||||
#include "tree-cfgcleanup.h"
|
||||
#include "vr-values.h"
|
||||
#include "gimple-ssa-evrp-analyze.h"
|
||||
#include "misc.h"
|
||||
|
||||
class evrp_folder : public substitute_and_fold_engine
|
||||
{
|
||||
public:
|
||||
evrp_folder () : m_range_analyzer (/*update_global_ranges=*/true),
|
||||
m_vr_values (m_range_analyzer.get_vr_values ())
|
||||
m_vr_values (m_range_analyzer.get_vr_values ()),
|
||||
simplifier (m_vr_values)
|
||||
{
|
||||
}
|
||||
|
||||
~evrp_folder ()
|
||||
{
|
||||
m_vr_values->cleanup_edges_and_switches ();
|
||||
|
||||
if (dump_file)
|
||||
{
|
||||
fprintf (dump_file, "\nValue ranges after Early VRP:\n\n");
|
||||
@@ -81,12 +81,16 @@ public:
|
||||
fprintf (dump_file, "evrp visiting stmt ");
|
||||
print_gimple_stmt (dump_file, stmt, 0);
|
||||
}
|
||||
m_gimple_state.set_orig_stmt (stmt);
|
||||
m_range_analyzer.record_ranges_from_stmt (stmt, false);
|
||||
}
|
||||
|
||||
bool fold_stmt (gimple_stmt_iterator *gsi) OVERRIDE
|
||||
{
|
||||
return m_vr_values->simplify_stmt_using_ranges (gsi);
|
||||
bool res = simplifier.simplify (gsi);
|
||||
if (m_modified || res)
|
||||
m_gimple_state.maybe_dump_differences_and_trap (gsi_stmt (*gsi));
|
||||
return res;
|
||||
}
|
||||
|
||||
void post_fold_bb (basic_block bb) OVERRIDE
|
||||
@@ -96,13 +100,34 @@ public:
|
||||
|
||||
void post_new_stmt (gimple *stmt) OVERRIDE
|
||||
{
|
||||
m_vr_values->set_defs_to_varying (stmt);
|
||||
m_range_analyzer.get_vr_values ()->set_defs_to_varying (stmt);
|
||||
}
|
||||
|
||||
void tmp_stats_remove_stmt (gimple *stmt, tree lhs) OVERRIDE
|
||||
{
|
||||
m_gimple_state.maybe_dump_differences_and_trap (stmt, lhs);
|
||||
}
|
||||
|
||||
void tmp_stats_changed_phi (gphi *orig_phi, gphi *new_phi) OVERRIDE
|
||||
{
|
||||
gimple *save = m_gimple_state.set_orig_stmt (orig_phi);
|
||||
m_gimple_state.maybe_dump_differences_and_trap (new_phi);
|
||||
m_gimple_state.set_orig_stmt (save);
|
||||
}
|
||||
|
||||
void tmp_stats_set_modified (bool modified) OVERRIDE
|
||||
{
|
||||
m_modified = modified;
|
||||
}
|
||||
|
||||
private:
|
||||
DISABLE_COPY_AND_ASSIGN (evrp_folder);
|
||||
class evrp_range_analyzer m_range_analyzer;
|
||||
class vr_values *m_vr_values;
|
||||
|
||||
simplify_using_ranges simplifier;
|
||||
class gimple_state m_gimple_state;
|
||||
bool m_modified;
|
||||
};
|
||||
|
||||
/* Main entry point for the early vrp pass which is a simplified non-iterative
|
||||
|
||||
@@ -1270,6 +1270,7 @@ initialize_node_lattices (struct cgraph_node *node)
|
||||
plats->ctxlat.set_to_bottom ();
|
||||
set_agg_lats_to_bottom (plats);
|
||||
plats->bits_lattice.set_to_bottom ();
|
||||
plats->m_value_range.m_vr = value_range ();
|
||||
plats->m_value_range.set_to_bottom ();
|
||||
}
|
||||
else
|
||||
@@ -3898,8 +3899,10 @@ ipcp_propagate_stage (class ipa_topo_info *topo)
|
||||
{
|
||||
class ipa_node_params *info = IPA_NODE_REF (node);
|
||||
determine_versionability (node, info);
|
||||
info->lattices = XCNEWVEC (class ipcp_param_lattices,
|
||||
ipa_get_param_count (info));
|
||||
|
||||
unsigned nlattices = ipa_get_param_count (info);
|
||||
void *chunk = XCNEWVEC (class ipcp_param_lattices, nlattices);
|
||||
info->lattices = new (chunk) ipcp_param_lattices[nlattices];
|
||||
initialize_node_lattices (node);
|
||||
}
|
||||
ipa_size_summary *s = ipa_size_summaries->get (node);
|
||||
|
||||
@@ -82,6 +82,7 @@ along with GCC; see the file COPYING3. If not see
|
||||
#include "gimplify.h"
|
||||
#include "stringpool.h"
|
||||
#include "attribs.h"
|
||||
#include <vector>
|
||||
#include "tree-into-ssa.h"
|
||||
|
||||
/* Summaries. */
|
||||
@@ -330,7 +331,7 @@ static void
|
||||
evaluate_conditions_for_known_args (struct cgraph_node *node,
|
||||
bool inline_p,
|
||||
vec<tree> known_vals,
|
||||
vec<value_range> known_value_ranges,
|
||||
const std::vector<value_range> &known_value_ranges,
|
||||
vec<ipa_agg_value_set> known_aggs,
|
||||
clause_t *ret_clause,
|
||||
clause_t *ret_nonspec_clause)
|
||||
@@ -445,7 +446,7 @@ evaluate_conditions_for_known_args (struct cgraph_node *node,
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (c->operand_num < (int) known_value_ranges.length ()
|
||||
if (c->operand_num < (int) known_value_ranges.size ()
|
||||
&& !c->agg_contents
|
||||
&& !known_value_ranges[c->operand_num].undefined_p ()
|
||||
&& !known_value_ranges[c->operand_num].varying_p ()
|
||||
@@ -554,7 +555,7 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
|
||||
{
|
||||
struct cgraph_node *callee = e->callee->ultimate_alias_target ();
|
||||
class ipa_fn_summary *info = ipa_fn_summaries->get (callee);
|
||||
auto_vec<value_range, 32> known_value_ranges;
|
||||
std::vector<value_range> known_value_ranges (32);
|
||||
class ipa_edge_args *args;
|
||||
|
||||
if (clause_ptr)
|
||||
@@ -629,8 +630,12 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
|
||||
i));
|
||||
if (!vr.undefined_p () && !vr.varying_p ())
|
||||
{
|
||||
if (!known_value_ranges.length ())
|
||||
known_value_ranges.safe_grow_cleared (count);
|
||||
if (!known_value_ranges.size ())
|
||||
{
|
||||
known_value_ranges.resize (count);
|
||||
for (int i = 0; i < count; ++i)
|
||||
known_value_ranges[i].set_undefined ();
|
||||
}
|
||||
known_value_ranges[i] = vr;
|
||||
}
|
||||
}
|
||||
@@ -803,7 +808,7 @@ ipa_fn_summary_t::duplicate (cgraph_node *src,
|
||||
}
|
||||
evaluate_conditions_for_known_args (dst, false,
|
||||
known_vals,
|
||||
vNULL,
|
||||
std::vector<value_range> (),
|
||||
vNULL,
|
||||
&possible_truths,
|
||||
/* We are going to specialize,
|
||||
@@ -3681,7 +3686,8 @@ estimate_ipcp_clone_size_and_time (struct cgraph_node *node,
|
||||
clause_t clause, nonspec_clause;
|
||||
|
||||
/* TODO: Also pass known value ranges. */
|
||||
evaluate_conditions_for_known_args (node, false, known_vals, vNULL,
|
||||
evaluate_conditions_for_known_args (node, false, known_vals,
|
||||
std::vector<value_range> (),
|
||||
known_aggs, &clause, &nonspec_clause);
|
||||
ipa_call_context ctx (node, clause, nonspec_clause,
|
||||
known_vals, known_contexts,
|
||||
|
||||
@@ -2059,7 +2059,7 @@ ipa_get_value_range (value_range *tmp)
|
||||
if (*slot)
|
||||
return *slot;
|
||||
|
||||
value_range *vr = ggc_alloc<value_range> ();
|
||||
value_range *vr = new (ggc_alloc<value_range> ()) value_range;
|
||||
*vr = *tmp;
|
||||
*slot = vr;
|
||||
|
||||
|
||||
@@ -318,7 +318,9 @@ struct GTY (()) ipa_jump_func
|
||||
/* Information about value range, containing valid data only when vr_known is
|
||||
true. The pointed to structure is shared betweed different jump
|
||||
functions. Use ipa_set_jfunc_vr to set this field. */
|
||||
class value_range *m_vr;
|
||||
// ?? Using "class value_range" here causes GTY to complain:
|
||||
// warning: structure `value_range' used but not defined
|
||||
value_range *m_vr;
|
||||
|
||||
enum jump_func_type type;
|
||||
/* Represents a value of a jump function. pass_through is used only in jump
|
||||
|
||||
402
gcc/misc.cc
Normal file
402
gcc/misc.cc
Normal file
@@ -0,0 +1,402 @@
|
||||
// Miscellaneous support routines not intended for upstream merge.
|
||||
|
||||
#include "config.h"
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "backend.h"
|
||||
#include "tree.h"
|
||||
#include "gimple.h"
|
||||
#include "tree-pass.h"
|
||||
#include "ssa.h"
|
||||
#include "gimple-pretty-print.h"
|
||||
#include "cfganal.h"
|
||||
#include "gimple-fold.h"
|
||||
#include "tree-eh.h"
|
||||
#include "gimple-iterator.h"
|
||||
#include "tree-cfg.h"
|
||||
#include "tree-ssa-loop-manip.h"
|
||||
#include "tree-ssa-loop.h"
|
||||
#include "cfgloop.h"
|
||||
#include "tree-scalar-evolution.h"
|
||||
#include "tree-ssa-propagate.h"
|
||||
#include "alloc-pool.h"
|
||||
#include "domwalk.h"
|
||||
#include "tree-cfgcleanup.h"
|
||||
#include "vr-values.h"
|
||||
#include "gimple-ssa-evrp-analyze.h"
|
||||
#include "fold-const.h"
|
||||
#include "misc.h"
|
||||
|
||||
//====================================================
|
||||
// unseen_function_p
|
||||
//====================================================
|
||||
|
||||
static const char *
|
||||
get_fresh_function_name ()
|
||||
{
|
||||
char *result;
|
||||
if (cfun->decl)
|
||||
{
|
||||
pretty_printer pp;
|
||||
dump_generic_node (&pp, cfun->decl, 0, TDF_VOPS|TDF_MEMSYMS, false);
|
||||
const char *str = pp_formatted_text (&pp);
|
||||
result = new char[strlen (str) + 1];
|
||||
return strcpy (result, str);
|
||||
}
|
||||
result = new char[sizeof("UNKNOWN") + 1];
|
||||
return strcpy (result, "UNKNOWN");
|
||||
}
|
||||
|
||||
static bool
|
||||
unseen_function_p ()
|
||||
{
|
||||
bool unseen = true;
|
||||
static const char *prev_function_name;
|
||||
const char *curr_function_name = get_fresh_function_name ();
|
||||
|
||||
if (prev_function_name && curr_function_name)
|
||||
unseen = strcmp (prev_function_name, curr_function_name);
|
||||
|
||||
if (prev_function_name)
|
||||
delete prev_function_name;
|
||||
prev_function_name = curr_function_name;
|
||||
return unseen;
|
||||
}
|
||||
|
||||
//====================================================
|
||||
// highlighter
|
||||
//====================================================
|
||||
|
||||
class highlighter highlighter;
|
||||
|
||||
#define INDENT(SPACE) \
|
||||
do { int i; for (i = 0; i < SPACE; i++) pp_space (buffer); } while (0)
|
||||
|
||||
void
|
||||
highlighter::on (pretty_printer *buffer, int spc, gimple *stmt)
|
||||
{
|
||||
bool removal = untainted_stmt == stmt;
|
||||
bool found_orig_stmt = new_stmt == stmt;
|
||||
bool need_header = found_orig_stmt || removal;
|
||||
if (need_header)
|
||||
{
|
||||
pp_string (buffer, ";; (STATE) filename = ");
|
||||
pp_string (buffer, main_input_filename);
|
||||
pp_newline_and_flush (buffer);
|
||||
INDENT (spc);
|
||||
}
|
||||
if (removal)
|
||||
{
|
||||
pp_string (buffer, ";; Queued for removal LHS= ");
|
||||
dump_generic_node (buffer, lhs, spc, TDF_SLIM, false);
|
||||
}
|
||||
else if (found_orig_stmt)
|
||||
{
|
||||
pp_string (buffer, ";; Original statement was: ");
|
||||
pp_gimple_stmt_1 (buffer, old_stmt, spc, TDF_SLIM);
|
||||
}
|
||||
if (need_header)
|
||||
{
|
||||
pp_newline_and_flush (buffer);
|
||||
INDENT (spc);
|
||||
pp_string (buffer, ";; VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV\n");
|
||||
INDENT (spc);
|
||||
// For PHI removal, dump the PHI as well as the statement.
|
||||
if (removal && is_a<gphi *> (new_stmt))
|
||||
{
|
||||
pp_gimple_stmt_1 (buffer, new_stmt, spc, TDF_SLIM);
|
||||
pp_newline_and_flush (buffer);
|
||||
INDENT (spc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
highlighter::off (pretty_printer *buffer, int spc, gimple *stmt)
|
||||
{
|
||||
bool removal = untainted_stmt == stmt;
|
||||
bool found_orig_stmt = new_stmt == stmt;
|
||||
if (found_orig_stmt || removal)
|
||||
{
|
||||
pp_newline_and_flush (buffer);
|
||||
INDENT (spc);
|
||||
pp_string (buffer, ";; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
highlighter::set (gimple *untainted_stmt,
|
||||
gimple *old_stmt, gimple *new_stmt, tree lhs)
|
||||
{
|
||||
this->untainted_stmt = untainted_stmt;
|
||||
this->old_stmt = old_stmt;
|
||||
this->new_stmt = new_stmt;
|
||||
this->lhs = lhs;
|
||||
}
|
||||
|
||||
//====================================================
|
||||
// gimple_state
|
||||
//====================================================
|
||||
|
||||
gimple_state::gimple_state ()
|
||||
{
|
||||
orig_stmt = NULL;
|
||||
out = stderr;
|
||||
accumulate_changes = false;
|
||||
|
||||
// Instead of trapping, accumulate changes into the filename stored
|
||||
// in EVRP_TRAPS.
|
||||
if (const char *filename = getenv ("EVRP_TRAPS"))
|
||||
{
|
||||
out = fopen (filename, "a");
|
||||
accumulate_changes = true;
|
||||
}
|
||||
}
|
||||
|
||||
gimple_state::~gimple_state ()
|
||||
{
|
||||
if (out != stderr)
|
||||
fclose (out);
|
||||
}
|
||||
|
||||
gimple *
|
||||
gimple_state::set_orig_stmt (gimple *stmt)
|
||||
{
|
||||
untainted_stmt = stmt;
|
||||
gimple *prev = orig_stmt;
|
||||
orig_stmt = gimple_copy (stmt);
|
||||
return prev;
|
||||
}
|
||||
|
||||
void
|
||||
gimple_state::maybe_dump_differences_and_trap (gimple *new_stmt, tree lhs)
|
||||
{
|
||||
if (flag_evrp_traps)
|
||||
{
|
||||
if (unseen_function_p ())
|
||||
{
|
||||
fprintf (out, "===============================================\n");
|
||||
highlighter.set (untainted_stmt, orig_stmt, new_stmt, lhs);
|
||||
dump_function_to_file (current_function_decl, out, TDF_NONE);
|
||||
highlighter.set ();
|
||||
}
|
||||
if (accumulate_changes)
|
||||
return;
|
||||
gcc_unreachable ();
|
||||
}
|
||||
}
|
||||
|
||||
//====================================================
|
||||
// Miscellaneous debugging aids.
|
||||
//====================================================
|
||||
|
||||
DEBUG_FUNCTION char *
|
||||
strcpy_gimple (char *dest, const gimple *g)
|
||||
{
|
||||
pretty_printer pp;
|
||||
pp_gimple_stmt_1 (&pp, g, 0, TDF_NONE);
|
||||
const char *str = pp_formatted_text (&pp);
|
||||
return strcpy (dest, str);
|
||||
}
|
||||
|
||||
DEBUG_FUNCTION int
|
||||
strncmp_gimple (const gimple *g, const char *str, size_t n)
|
||||
{
|
||||
char gstr[100];
|
||||
strcpy_gimple (gstr, g);
|
||||
return strncmp (gstr, str, n);
|
||||
}
|
||||
|
||||
DEBUG_FUNCTION int
|
||||
strcmp_gimple (const gimple *g, const char *str)
|
||||
{
|
||||
char gstr[100];
|
||||
strcpy_gimple (gstr, g);
|
||||
return strcmp (gstr, str);
|
||||
}
|
||||
|
||||
DEBUG_FUNCTION char *
|
||||
strcpy_tree (char *dest, tree t)
|
||||
{
|
||||
pretty_printer pp;
|
||||
dump_generic_node (&pp, t, 0, TDF_VOPS|TDF_MEMSYMS, false);
|
||||
const char *str = pp_formatted_text (&pp);
|
||||
return strcpy (dest, str);
|
||||
}
|
||||
|
||||
DEBUG_FUNCTION int
|
||||
strncmp_tree (tree t, const char *str, size_t n)
|
||||
{
|
||||
char tstr[100];
|
||||
strcpy_tree (tstr, t);
|
||||
return strncmp (tstr, str, n);
|
||||
}
|
||||
|
||||
DEBUG_FUNCTION int
|
||||
strcmp_tree (tree t, const char *str)
|
||||
{
|
||||
char tstr[100];
|
||||
strcpy_tree (tstr, t);
|
||||
return strcmp (tstr, str);
|
||||
}
|
||||
|
||||
//=========================================
|
||||
// vr_comparison
|
||||
//=========================================
|
||||
|
||||
vr_comparison::vr_comparison (const irange *old_range,
|
||||
const irange *new_range,
|
||||
vr_values *vr)
|
||||
{
|
||||
m_old_range = old_range;
|
||||
m_new_range = new_range;
|
||||
m_vr_values = vr;
|
||||
}
|
||||
|
||||
void
|
||||
vr_comparison::compare ()
|
||||
{
|
||||
if (new_range_is_same ())
|
||||
return;
|
||||
if (new_range_is_better ())
|
||||
{
|
||||
if (dump_file)
|
||||
dump_improvements (dump_file);
|
||||
return;
|
||||
}
|
||||
dump_differences_and_trap ();
|
||||
}
|
||||
|
||||
void
|
||||
vr_comparison::compare (tree name, edge e)
|
||||
{
|
||||
m_name = name;
|
||||
m_edge = e;
|
||||
m_stmt = NULL;
|
||||
compare ();
|
||||
}
|
||||
|
||||
void
|
||||
vr_comparison::compare (gimple *stmt)
|
||||
{
|
||||
m_name = get_output_for_vrp (stmt);
|
||||
m_edge = NULL;
|
||||
m_stmt = stmt;
|
||||
compare ();
|
||||
}
|
||||
|
||||
bool
|
||||
vr_comparison::new_range_is_same () const
|
||||
{
|
||||
// We may be able to normalize a symbolic to a [MIN,MAX] plus
|
||||
// or minus the end-points. Don't count that as a win just yet.
|
||||
if (m_old_range && m_old_range->symbolic_p ())
|
||||
return true;
|
||||
widest_irange old;
|
||||
if (m_old_range)
|
||||
old = *m_old_range;
|
||||
// Treat UNDEFINED and VARYING as interchangeable.
|
||||
if (old.undefined_p () && m_new_range->varying_p ())
|
||||
return true;
|
||||
if (old.varying_p () && m_new_range->undefined_p ())
|
||||
return true;
|
||||
return old == *m_new_range;
|
||||
}
|
||||
|
||||
bool
|
||||
vr_comparison::new_range_is_better () const
|
||||
{
|
||||
if (new_range_is_same ())
|
||||
return false;
|
||||
if (!m_old_range)
|
||||
return true;
|
||||
// ?? Sometimes we get an undefined because the ranger determined a
|
||||
// path was unexecutable. Verify this is actually the case by
|
||||
// turning this off and analyzing all failures.
|
||||
if (m_new_range->undefined_p ())
|
||||
return true;
|
||||
if (!range_has_numeric_bounds_p (m_old_range))
|
||||
{
|
||||
gcc_checking_assert (range_has_numeric_bounds_p (m_new_range));
|
||||
return true;
|
||||
}
|
||||
widest_irange inter (*m_new_range);
|
||||
inter.intersect (*m_old_range);
|
||||
return inter == *m_new_range;
|
||||
}
|
||||
|
||||
void
|
||||
vr_comparison::dump_differences_and_trap () const
|
||||
{
|
||||
bool dumping = getenv("GORI_DUMP_FILE") != NULL;
|
||||
if (dumping)
|
||||
{
|
||||
const char *filename = getenv("GORI_DUMP_FILE");
|
||||
FILE *out = fopen (filename, "a");
|
||||
fprintf (out, "=========FILE: %s ========\n",
|
||||
main_input_filename ? main_input_filename : "UNKNOWN");
|
||||
dump_differences (out);
|
||||
fclose (out);
|
||||
return;
|
||||
}
|
||||
dump_differences (stderr);
|
||||
gcc_unreachable ();
|
||||
}
|
||||
|
||||
void
|
||||
vr_comparison::dump_differences (FILE *out) const
|
||||
{
|
||||
dump_flags_t flags = TDF_NONE;
|
||||
if (m_stmt)
|
||||
{
|
||||
fprintf (out, "Different ranges for stmt: ");
|
||||
print_gimple_stmt (out, m_stmt, 0, flags);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (out, "Different ranges on edge (%d -> %d) for SSA: ",
|
||||
m_edge->src->index, m_edge->dest->index);
|
||||
print_generic_stmt (out, m_name, flags);
|
||||
}
|
||||
fprintf (out, "\told range: ");
|
||||
m_old_range->dump (out);
|
||||
fprintf (out, "\n\tnew range: ");
|
||||
m_new_range->dump (out);
|
||||
if (m_edge)
|
||||
{
|
||||
fprintf (out, "\n\n");
|
||||
dump_bb (out, m_edge->src, 0, TDF_NONE);
|
||||
}
|
||||
fprintf (out, "\n");
|
||||
fprintf (out, "==============================================\n");
|
||||
dump_function_to_file (current_function_decl, out, TDF_NONE);
|
||||
|
||||
if (m_vr_values)
|
||||
{
|
||||
dump_flags_t save = dump_flags;
|
||||
dump_flags |= TDF_GORI;
|
||||
m_vr_values->dump_all_value_ranges (out);
|
||||
dump_flags = save;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
vr_comparison::dump_improvements (FILE *out) const
|
||||
{
|
||||
if (m_old_range && !range_has_numeric_bounds_p (m_old_range))
|
||||
return;
|
||||
if (new_range_is_better ())
|
||||
{
|
||||
fprintf (out, "New range improved: ");
|
||||
if (m_name)
|
||||
print_generic_expr (out, m_name);
|
||||
fprintf (out, " from: ");
|
||||
if (m_old_range)
|
||||
m_old_range->dump (out);
|
||||
else
|
||||
fprintf (out, "UNDEFINED");
|
||||
fprintf (out, " to: ");
|
||||
m_new_range->dump (out);
|
||||
fprintf (out, "\n");
|
||||
}
|
||||
}
|
||||
68
gcc/misc.h
Normal file
68
gcc/misc.h
Normal file
@@ -0,0 +1,68 @@
|
||||
// -*- C++ -*-
|
||||
|
||||
// Miscellaneous support routines not intended for upstream merge.
|
||||
|
||||
// Class to report any possible changes to the IL while folding.
|
||||
//
|
||||
// When environment variable EVRP_TRAPS is set, it points to the
|
||||
// output file to dump any IL changes to. If EVRP_TRAPS is not set,
|
||||
// any diagnostics are dumped to stderr and a trap occurs at the first
|
||||
// change.
|
||||
|
||||
class gimple_state
|
||||
{
|
||||
public:
|
||||
gimple_state ();
|
||||
~gimple_state ();
|
||||
gimple *set_orig_stmt (gimple *stmt);
|
||||
void maybe_dump_differences_and_trap (gimple *new_stmt, tree lhs = NULL);
|
||||
|
||||
private:
|
||||
gimple *orig_stmt;
|
||||
gimple *untainted_stmt;
|
||||
FILE *out;
|
||||
bool accumulate_changes;
|
||||
};
|
||||
|
||||
// Hook for pretty printer to highlight a particular statement.
|
||||
|
||||
class highlighter
|
||||
{
|
||||
public:
|
||||
void set (gimple *untainted_stmt = 0,
|
||||
gimple *old_stmt = 0, gimple *new_stmt = 0,
|
||||
tree lhs = 0);
|
||||
void on (class pretty_printer *, int spc, gimple *);
|
||||
void off (class pretty_printer *, int spc, gimple *);
|
||||
private:
|
||||
gimple *untainted_stmt;
|
||||
gimple *old_stmt;
|
||||
gimple *new_stmt;
|
||||
tree lhs;
|
||||
};
|
||||
|
||||
extern class highlighter highlighter;
|
||||
|
||||
// Class to assert that the new range is at least as good as the old
|
||||
// one.
|
||||
|
||||
class vr_comparison
|
||||
{
|
||||
public:
|
||||
vr_comparison (const irange *, const irange *, class vr_values * = 0);
|
||||
void compare (tree name, edge);
|
||||
void compare (gimple *);
|
||||
private:
|
||||
void compare ();
|
||||
void dump_differences_and_trap () const;
|
||||
void dump_differences (FILE *) const;
|
||||
void dump_improvements (FILE *) const;
|
||||
bool new_range_is_same () const;
|
||||
bool new_range_is_better () const;
|
||||
tree m_name;
|
||||
edge m_edge;
|
||||
gimple *m_stmt;
|
||||
const irange *m_old_range;
|
||||
const irange *m_new_range;
|
||||
class vr_values *m_vr_values;
|
||||
};
|
||||
@@ -949,6 +949,13 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
|
||||
opts->x_flag_reorder_blocks = 1;
|
||||
}
|
||||
|
||||
// -frvrp-changes overrides the individual -frvrp[12]-changes.
|
||||
if (opts->x_flag_rvrp_changes != -1)
|
||||
{
|
||||
opts->x_flag_rvrp1_changes = opts->x_flag_rvrp_changes;
|
||||
opts->x_flag_rvrp2_changes = opts->x_flag_rvrp_changes;
|
||||
}
|
||||
|
||||
/* If user requested unwind info, then turn off the partitioning
|
||||
optimization. */
|
||||
|
||||
|
||||
@@ -86,7 +86,14 @@ along with GCC; see the file COPYING3. If not see
|
||||
execute TODO_rebuild_alias at this point. */
|
||||
NEXT_PASS (pass_build_ealias);
|
||||
NEXT_PASS (pass_fre, true /* may_iterate */);
|
||||
|
||||
NEXT_PASS (pass_ranger_vrp);
|
||||
/* Run copy-prop to keep evrp below from doing simple copy prop
|
||||
and messing up our comparison and trap phase. */
|
||||
NEXT_PASS (pass_evrp_copy_prop);
|
||||
|
||||
NEXT_PASS (pass_early_vrp);
|
||||
NEXT_PASS (pass_ranger_vrp);
|
||||
NEXT_PASS (pass_merge_phi);
|
||||
NEXT_PASS (pass_dse);
|
||||
NEXT_PASS (pass_cd_dce);
|
||||
|
||||
1889
gcc/range-op.cc
1889
gcc/range-op.cc
File diff suppressed because it is too large
Load Diff
@@ -50,9 +50,9 @@ class range_operator
|
||||
{
|
||||
public:
|
||||
// Perform an operation between 2 ranges and return it.
|
||||
virtual bool fold_range (value_range &r, tree type,
|
||||
const value_range &lh,
|
||||
const value_range &rh) const;
|
||||
virtual bool fold_range (irange &r, tree type,
|
||||
const irange &lh,
|
||||
const irange &rh) const;
|
||||
|
||||
// Return the range for op[12] in the general case. LHS is the range for
|
||||
// the LHS of the expression, OP[12]is the range for the other
|
||||
@@ -65,16 +65,16 @@ public:
|
||||
//
|
||||
// i.e. [LHS] = ??? + OP2
|
||||
// is re-formed as R = [LHS] - OP2.
|
||||
virtual bool op1_range (value_range &r, tree type,
|
||||
const value_range &lhs,
|
||||
const value_range &op2) const;
|
||||
virtual bool op2_range (value_range &r, tree type,
|
||||
const value_range &lhs,
|
||||
const value_range &op1) const;
|
||||
virtual bool op1_range (irange &r, tree type,
|
||||
const irange &lhs,
|
||||
const irange &op2) const;
|
||||
virtual bool op2_range (irange &r, tree type,
|
||||
const irange &lhs,
|
||||
const irange &op1) const;
|
||||
|
||||
protected:
|
||||
// Perform an integral operation between 2 sub-ranges and return it.
|
||||
virtual void wi_fold (value_range &r, tree type,
|
||||
virtual void wi_fold (irange &r, tree type,
|
||||
const wide_int &lh_lb,
|
||||
const wide_int &lh_ub,
|
||||
const wide_int &rh_lb,
|
||||
@@ -82,7 +82,7 @@ protected:
|
||||
};
|
||||
|
||||
extern range_operator *range_op_handler (enum tree_code code, tree type);
|
||||
extern void range_cast (value_range &, tree type);
|
||||
extern void range_cast (irange &, tree type);
|
||||
extern void wi_set_zero_nonzero_bits (tree type,
|
||||
const wide_int &, const wide_int &,
|
||||
wide_int &maybe_nonzero,
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
// { dg-do compile }
|
||||
// { dg-options "-O2 -fdump-tree-fre3 -fdump-tree-optimized -fdelete-null-pointer-checks --param early-inlining-insns=14 --param max-inline-insns-single=200" }
|
||||
|
||||
// NOTE: rvrp throws this test off because it removes all the calls to
|
||||
// __builtin_unreachable earlier than expected, and the number of
|
||||
// __builtin_free's don't match.
|
||||
// { dg-additional-options "-fno-rvrp-changes" }
|
||||
|
||||
#define assume(x) if(!(x))__builtin_unreachable()
|
||||
|
||||
inline void* operator new(__SIZE_TYPE__ n){ return __builtin_malloc(n); }
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O3 -fdump-tree-local-pure-const1 -fdump-tree-optimized" } */
|
||||
/* { dg-options "-O3 -fdump-tree-local-pure-const1 -fdump-tree-optimized -fno-rvrp-changes" } */
|
||||
static __attribute__ ((noinline, noclone))
|
||||
int i_am_pure(char *c, int n)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fdisable-tree-evrp -fdump-tree-vrp1" } */
|
||||
/* { dg-options "-O2 -fdisable-tree-evrp -fdump-tree-vrp1 -fno-rvrp-changes" } */
|
||||
|
||||
int foo (void)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fdisable-tree-evrp -fdump-tree-profile_estimate -fno-finite-loops" } */
|
||||
/* { dg-options "-O2 -fdisable-tree-evrp -fdump-tree-profile_estimate -fno-finite-loops -fno-rvrp-changes" } */
|
||||
|
||||
extern int global;
|
||||
extern int global2;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fdump-tree-cunrolli-details -fdisable-tree-evrp" } */
|
||||
/* { dg-options "-O2 -fdump-tree-cunrolli-details -fdisable-tree-evrp -fno-rvrp-changes" } */
|
||||
void abort (void);
|
||||
int q (void);
|
||||
int a[10];
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fno-tree-ccp -fno-tree-forwprop -fno-tree-fre -fno-tree-vrp -fdump-tree-dse1-details" } */
|
||||
/* { dg-additional-options "-fdisable-tree-evrp-copyprop" } */
|
||||
|
||||
int
|
||||
f ()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* { dg-do compile { target { ! keeps_null_pointer_checks } } } */
|
||||
/* { dg-options "-O2 -fdump-tree-original -fdump-tree-vrp1 -fdelete-null-pointer-checks -fdisable-tree-evrp" } */
|
||||
/* { dg-options "-O2 -fdump-tree-original -fdump-tree-vrp1 -fdelete-null-pointer-checks -fdisable-tree-evrp -fno-rvrp-changes" } */
|
||||
|
||||
extern int* f(int) __attribute__((returns_nonnull));
|
||||
extern void eliminate ();
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
immediate successors of the basic block. */
|
||||
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fno-tree-dominator-opts -fdisable-tree-evrp -fdump-tree-vrp1-details -fdelete-null-pointer-checks" } */
|
||||
/* { dg-options "-O2 -fno-tree-dominator-opts -fdisable-tree-evrp -fdump-tree-vrp1-details -fdelete-null-pointer-checks -fno-rvrp-changes" } */
|
||||
|
||||
extern void bar (int);
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
range information out of the conditional. */
|
||||
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fno-tree-dominator-opts -fno-tree-fre -fdisable-tree-evrp -fdump-tree-vrp1-details" } */
|
||||
/* { dg-options "-O2 -fno-tree-dominator-opts -fno-tree-fre -fdisable-tree-evrp -fdump-tree-vrp1-details -fno-rvrp-changes" } */
|
||||
|
||||
int
|
||||
foo (int a)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fdisable-tree-evrp -fdump-tree-vrp1 -fdump-tree-dce2 -fdelete-null-pointer-checks" } */
|
||||
/* { dg-options "-O2 -fdisable-tree-evrp -fdump-tree-vrp1 -fdump-tree-dce2 -fdelete-null-pointer-checks -fno-rvrp-changes" } */
|
||||
|
||||
int
|
||||
foo (int *p)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fdisable-tree-evrp -fdump-tree-vrp1 -fdelete-null-pointer-checks" } */
|
||||
/* { dg-options "-O2 -fdisable-tree-evrp -fdump-tree-vrp1 -fdelete-null-pointer-checks -fno-rvrp-changes" } */
|
||||
|
||||
int g, h;
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
allows us to eliminate the second "if" statement. */
|
||||
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fno-tree-dominator-opts -fdisable-tree-evrp -fdump-tree-vrp1-details" } */
|
||||
/* { dg-options "-O2 -fno-tree-dominator-opts -fdisable-tree-evrp -fdump-tree-vrp1-details -fno-rvrp-changes" } */
|
||||
|
||||
struct f {
|
||||
int i;
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fdump-tree-evrp-details" } */
|
||||
|
||||
/* range_of_stmt will call SCEV to set global ranges for the PHI
|
||||
results, and alter the results here. */
|
||||
/* { dg-additional-options "-fdisable-tree-rvrp1 -fdisable-tree-rvrp2" } */
|
||||
|
||||
extern void g (void);
|
||||
extern void bar (int);
|
||||
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fdisable-tree-evrp -fdump-tree-vrp1" } */
|
||||
|
||||
/* range_of_stmt will call SCEV to set global ranges for the PHI
|
||||
results, and alter the results here. */
|
||||
/* { dg-additional-options "-fdisable-tree-rvrp1 -fdisable-tree-rvrp2" } */
|
||||
|
||||
extern void g (void);
|
||||
extern void bar (int);
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
Make sure VRP folds the second "if" statement. */
|
||||
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fno-tree-dominator-opts -fdisable-tree-evrp -fdump-tree-vrp1-details" } */
|
||||
/* { dg-options "-O2 -fno-tree-dominator-opts -fdisable-tree-evrp -fdump-tree-vrp1-details -fno-rvrp-changes" } */
|
||||
|
||||
int
|
||||
foo (int a)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fno-tree-ccp -fdisable-tree-evrp -fdump-tree-vrp1-details" } */
|
||||
/* { dg-options "-O2 -fno-tree-ccp -fdisable-tree-evrp -fdump-tree-vrp1-details -fno-rvrp-changes" } */
|
||||
|
||||
void h (void);
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
Check that VRP now gets ranges from BIT_AND_EXPRs. */
|
||||
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fno-tree-ccp -fdisable-tree-evrp -fdump-tree-vrp1" } */
|
||||
/* { dg-options "-O2 -fno-tree-ccp -fdisable-tree-evrp -fdump-tree-vrp1 -fno-rvrp-changes" } */
|
||||
|
||||
int
|
||||
foo (int a)
|
||||
|
||||
@@ -15,9 +15,8 @@ typedef struct
|
||||
ProtocolOperations;
|
||||
static const ProtocolOperations *protocol;
|
||||
int
|
||||
brl_readCommand (BrailleDisplay * brl)
|
||||
brl_readCommand (BrailleDisplay * brl, unsigned long int keys)
|
||||
{
|
||||
unsigned long int keys;
|
||||
int command;
|
||||
int keyPressed;
|
||||
unsigned char routingKeys[200];
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* PR tree-optimization/49039 */
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fdisable-tree-evrp -fdump-tree-vrp1" } */
|
||||
/* { dg-options "-O2 -fdisable-tree-evrp -fdump-tree-vrp1 -fno-rvrp-changes" } */
|
||||
|
||||
extern void bar (void);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* { dg-do compile { target { ! keeps_null_pointer_checks } } } */
|
||||
/* { dg-options "-O2 -fdisable-tree-evrp -fdump-tree-vrp1 -fdelete-null-pointer-checks" } */
|
||||
/* { dg-options "-O2 -fdisable-tree-evrp -fdump-tree-vrp1 -fdelete-null-pointer-checks -fno-rvrp-changes" } */
|
||||
|
||||
extern void eliminate (void);
|
||||
extern void* f1 (void *a, void *b) __attribute__((nonnull));
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* PR tree-optimization/61839. */
|
||||
/* { dg-do run } */
|
||||
/* { dg-options "-O2 -fdump-tree-vrp1 -fdisable-tree-evrp -fdump-tree-optimized" } */
|
||||
/* { dg-options "-O2 -fdump-tree-vrp1 -fdisable-tree-evrp -fdump-tree-optimized -fno-rvrp-changes" } */
|
||||
/* { dg-require-effective-target int32plus } */
|
||||
|
||||
__attribute__ ((noinline))
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* PR tree-optimization/61839. */
|
||||
/* { dg-do run } */
|
||||
/* { dg-options "-O2 -fdump-tree-vrp1 -fdisable-tree-evrp -fdump-tree-optimized" } */
|
||||
/* { dg-options "-O2 -fdump-tree-vrp1 -fdisable-tree-evrp -fdump-tree-optimized -fno-rvrp-changes" } */
|
||||
/* { dg-require-effective-target int32plus } */
|
||||
|
||||
__attribute__ ((noinline))
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* PR tree-optimization/68431 */
|
||||
/* { dg-options "-O2 -fdisable-tree-evrp -fdump-tree-vrp1-details" } */
|
||||
/* { dg-options "-O2 -fdisable-tree-evrp -fdump-tree-vrp1-details -fno-rvrp-changes" } */
|
||||
|
||||
unsigned int x = 1;
|
||||
int
|
||||
|
||||
252
gcc/testsuite/gcc.dg/tree-ssa/rvrp-logic-1.c
Normal file
252
gcc/testsuite/gcc.dg/tree-ssa/rvrp-logic-1.c
Normal file
@@ -0,0 +1,252 @@
|
||||
/* Extracted from fedora build for compile time issues with ranger
|
||||
taking a long time to evalaute deeply nested logical expressions. */
|
||||
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2" } */
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned value;
|
||||
} aarch64_sys_reg;
|
||||
|
||||
typedef unsigned long long aarch64_feature_set;
|
||||
|
||||
int
|
||||
aarch64_sys_reg_supported_p (const aarch64_feature_set features,
|
||||
const aarch64_sys_reg *reg)
|
||||
{
|
||||
|
||||
|
||||
if (reg->value == ((((3) << 19) | (((0)) << 16) | ((4) << 12) | (((2)) << 8) | (((3)) << 5)) >> 5)
|
||||
&& !((~(features) & (0x00200000)) == 0))
|
||||
return 0;
|
||||
|
||||
|
||||
if ((reg->value == ((((3) << 19) | ((3) << 16) | ((13) << 12) | ((0) << 8) | ((7) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((0) << 16) | ((13) << 12) | ((0) << 8) | ((7) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((4) << 16) | ((13) << 12) | ((0) << 8) | ((7) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((6) << 16) | ((13) << 12) | ((0) << 8) | ((7) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((5) << 16) | ((13) << 12) | ((0) << 8) | ((7) << 5)) >> 5))
|
||||
&& !((~(features) & (0x200000000000ULL)) == 0))
|
||||
return 0;
|
||||
|
||||
|
||||
if (reg->value == ((((3) << 19) | ((0) << 16) | ((0) << 12) | ((3) << 8) | ((4) << 5)) >> 5)
|
||||
&& !((~(features) & (0x400000000000ULL)) == 0))
|
||||
return 0;
|
||||
|
||||
|
||||
if (reg->value == ((((3) << 19) | (((3)) << 16) | ((4) << 12) | (((2)) << 8) | (((6)) << 5)) >> 5)
|
||||
&& !((~(features) & (0x800000000000ULL)) == 0))
|
||||
return 0;
|
||||
|
||||
|
||||
if ((reg->value == ((((3) << 19) | ((4) << 16) | ((2) << 12) | ((0) << 8) | ((1) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((4) << 16) | ((13) << 12) | ((0) << 8) | ((1) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((4) << 16) | ((14) << 12) | ((3) << 8) | ((0) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((4) << 16) | ((14) << 12) | ((3) << 8) | ((1) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((4) << 16) | ((14) << 12) | ((3) << 8) | ((2) << 5)) >> 5))
|
||||
&& !((~(features) & (0x01000000)) == 0))
|
||||
return 0;
|
||||
|
||||
|
||||
if ((reg->value == ((((3) << 19) | (((5)) << 16) | ((4) << 12) | (((0)) << 8) | (((0)) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | (((5)) << 16) | ((4) << 12) | (((0)) << 8) | (((1)) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((5) << 16) | ((1) << 12) | ((0) << 8) | ((0) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((5) << 16) | ((1) << 12) | ((0) << 8) | ((2) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((5) << 16) | ((2) << 12) | ((0) << 8) | ((0) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((5) << 16) | ((2) << 12) | ((0) << 8) | ((1) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((5) << 16) | ((2) << 12) | ((0) << 8) | ((2) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((5) << 16) | ((5) << 12) | ((1) << 8) | ((0) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((5) << 16) | ((5) << 12) | ((1) << 8) | ((1) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((5) << 16) | ((5) << 12) | ((2) << 8) | ((0) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((5) << 16) | ((6) << 12) | ((0) << 8) | ((0) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((5) << 16) | ((10) << 12) | ((2) << 8) | ((0) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((5) << 16) | ((10) << 12) | ((3) << 8) | ((0) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((5) << 16) | ((12) << 12) | ((0) << 8) | ((0) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((5) << 16) | ((13) << 12) | ((0) << 8) | ((1) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((5) << 16) | ((14) << 12) | ((1) << 8) | ((0) << 5)) >> 5))
|
||||
&& !((~(features) & (0x01000000)) == 0))
|
||||
return 0;
|
||||
|
||||
|
||||
if ((reg->value == ((((3) << 19) | ((5) << 16) | ((14) << 12) | ((2) << 8) | ((0) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((5) << 16) | ((14) << 12) | ((2) << 8) | ((1) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((5) << 16) | ((14) << 12) | ((2) << 8) | ((2) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((5) << 16) | ((14) << 12) | ((3) << 8) | ((0) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((5) << 16) | ((14) << 12) | ((3) << 8) | ((1) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((5) << 16) | ((14) << 12) | ((3) << 8) | ((2) << 5)) >> 5))
|
||||
&& !((~(features) & (0x01000000)) == 0))
|
||||
return 0;
|
||||
|
||||
|
||||
|
||||
|
||||
if (reg->value == ((((3) << 19) | ((0) << 16) | ((0) << 12) | ((7) << 8) | ((2) << 5)) >> 5)
|
||||
&& !((~(features) & (0x00000020)) == 0))
|
||||
return 0;
|
||||
|
||||
|
||||
if (reg->value == ((((3) << 19) | (((0)) << 16) | ((4) << 12) | (((2)) << 8) | (((4)) << 5)) >> 5)
|
||||
&& !((~(features) & (0x00000020)) == 0))
|
||||
return 0;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if ((reg->value == ((((3) << 19) | ((0) << 16) | ((5) << 12) | ((3) << 8) | ((0) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((0) << 16) | ((5) << 12) | ((3) << 8) | ((1) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((0) << 16) | ((5) << 12) | ((3) << 8) | ((2) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((0) << 16) | ((5) << 12) | ((3) << 8) | ((3) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((0) << 16) | ((5) << 12) | ((4) << 8) | ((0) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((0) << 16) | ((5) << 12) | ((4) << 8) | ((1) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((0) << 16) | ((5) << 12) | ((4) << 8) | ((2) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((0) << 16) | ((5) << 12) | ((4) << 8) | ((3) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((0) << 16) | ((5) << 12) | ((5) << 8) | ((0) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((0) << 16) | ((5) << 12) | ((5) << 8) | ((1) << 5)) >> 5))
|
||||
&& !((~(features) & (0x04000000)) == 0))
|
||||
return 0;
|
||||
|
||||
|
||||
if ((reg->value == ((((3) << 19) | ((4) << 16) | ((5) << 12) | ((2) << 8) | ((3) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((0) << 16) | ((12) << 12) | ((1) << 8) | ((1) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((4) << 16) | ((12) << 12) | ((1) << 8) | ((1) << 5)) >> 5))
|
||||
&& !((~(features) & (0x04000000)) == 0))
|
||||
return 0;
|
||||
|
||||
|
||||
if ((reg->value == ((((3) << 19) | ((0) << 16) | ((9) << 12) | ((10) << 8) | ((0) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((0) << 16) | ((9) << 12) | ((10) << 8) | ((1) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((0) << 16) | ((9) << 12) | ((10) << 8) | ((3) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((0) << 16) | ((9) << 12) | ((10) << 8) | ((7) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((0) << 16) | ((9) << 12) | ((9) << 8) | ((0) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((0) << 16) | ((9) << 12) | ((9) << 8) | ((2) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((0) << 16) | ((9) << 12) | ((9) << 8) | ((3) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((0) << 16) | ((9) << 12) | ((9) << 8) | ((4) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((0) << 16) | ((9) << 12) | ((9) << 8) | ((5) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((0) << 16) | ((9) << 12) | ((9) << 8) | ((6) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((0) << 16) | ((9) << 12) | ((9) << 8) | ((7) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((4) << 16) | ((9) << 12) | ((9) << 8) | ((0) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((5) << 16) | ((9) << 12) | ((9) << 8) | ((0) << 5)) >> 5))
|
||||
&& !((~(features) & (0x08000000)) == 0))
|
||||
return 0;
|
||||
|
||||
|
||||
if ((reg->value == ((((3) << 19) | ((0) << 16) | ((2) << 12) | ((1) << 8) | ((0) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((0) << 16) | ((2) << 12) | ((1) << 8) | ((1) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((0) << 16) | ((2) << 12) | ((1) << 8) | ((2) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((0) << 16) | ((2) << 12) | ((1) << 8) | ((3) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((0) << 16) | ((2) << 12) | ((2) << 8) | ((0) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((0) << 16) | ((2) << 12) | ((2) << 8) | ((1) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((0) << 16) | ((2) << 12) | ((2) << 8) | ((2) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((0) << 16) | ((2) << 12) | ((2) << 8) | ((3) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((0) << 16) | ((2) << 12) | ((3) << 8) | ((0) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((0) << 16) | ((2) << 12) | ((3) << 8) | ((1) << 5)) >> 5))
|
||||
&& !((~(features) & (0x00000040)) == 0))
|
||||
return 0;
|
||||
|
||||
|
||||
if ((reg->value == ((((3) << 19) | ((0) << 16) | ((0) << 12) | ((4) << 8) | ((4) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((0) << 16) | ((1) << 12) | ((2) << 8) | ((0) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((4) << 16) | ((1) << 12) | ((2) << 8) | ((0) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((6) << 16) | ((1) << 12) | ((2) << 8) | ((0) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((5) << 16) | ((1) << 12) | ((2) << 8) | ((0) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((0) << 16) | ((0) << 12) | ((0) << 8) | ((7) << 5)) >> 5))
|
||||
&& !((~(features) & (0x10000000)) == 0))
|
||||
return 0;
|
||||
|
||||
|
||||
|
||||
|
||||
if (reg->value == ((((3) << 19) | (((3)) << 16) | ((4) << 12) | (((2)) << 8) | (((5)) << 5)) >> 5)
|
||||
&& !((~(features) & (0x000000800ULL)) == 0))
|
||||
return 0;
|
||||
|
||||
|
||||
if ((reg->value == ((((3) << 19) | ((4) << 16) | ((2) << 12) | ((6) << 8) | ((2) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((4) << 16) | ((2) << 12) | ((6) << 8) | ((0) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((4) << 16) | ((14) << 12) | ((4) << 8) | ((0) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((4) << 16) | ((14) << 12) | ((4) << 8) | ((2) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((4) << 16) | ((14) << 12) | ((4) << 8) | ((1) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((4) << 16) | ((14) << 12) | ((5) << 8) | ((0) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((4) << 16) | ((14) << 12) | ((5) << 8) | ((2) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((4) << 16) | ((14) << 12) | ((5) << 8) | ((1) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((4) << 16) | ((1) << 12) | ((3) << 8) | ((1) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((4) << 16) | ((2) << 12) | ((2) << 8) | ((0) << 5)) >> 5))
|
||||
&& !((~(features) & (0x000000800ULL)) == 0))
|
||||
return 0;
|
||||
|
||||
|
||||
if ((reg->value == ((((1) << 19) | (((0)) << 16) | (((8)) << 12) | (((1)) << 8) | (((0)) << 5)) >> 5)
|
||||
|| reg->value == ((((1) << 19) | (((0)) << 16) | (((8)) << 12) | (((1)) << 8) | (((1)) << 5)) >> 5)
|
||||
|| reg->value == ((((1) << 19) | (((0)) << 16) | (((8)) << 12) | (((1)) << 8) | (((2)) << 5)) >> 5)
|
||||
|| reg->value == ((((1) << 19) | (((0)) << 16) | (((8)) << 12) | (((1)) << 8) | (((3)) << 5)) >> 5)
|
||||
|| reg->value == ((((1) << 19) | (((0)) << 16) | (((8)) << 12) | (((1)) << 8) | (((5)) << 5)) >> 5)
|
||||
|| reg->value == ((((1) << 19) | (((0)) << 16) | (((8)) << 12) | (((1)) << 8) | (((7)) << 5)) >> 5)
|
||||
|| reg->value == ((((1) << 19) | (((4)) << 16) | (((8)) << 12) | (((4)) << 8) | (((0)) << 5)) >> 5)
|
||||
|| reg->value == ((((1) << 19) | (((4)) << 16) | (((8)) << 12) | (((4)) << 8) | (((4)) << 5)) >> 5)
|
||||
|| reg->value == ((((1) << 19) | (((4)) << 16) | (((8)) << 12) | (((1)) << 8) | (((1)) << 5)) >> 5)
|
||||
|| reg->value == ((((1) << 19) | (((4)) << 16) | (((8)) << 12) | (((1)) << 8) | (((5)) << 5)) >> 5)
|
||||
|| reg->value == ((((1) << 19) | (((4)) << 16) | (((8)) << 12) | (((1)) << 8) | (((6)) << 5)) >> 5)
|
||||
|| reg->value == ((((1) << 19) | (((6)) << 16) | (((8)) << 12) | (((1)) << 8) | (((1)) << 5)) >> 5)
|
||||
|| reg->value == ((((1) << 19) | (((6)) << 16) | (((8)) << 12) | (((1)) << 8) | (((5)) << 5)) >> 5)
|
||||
|| reg->value == ((((1) << 19) | (((4)) << 16) | (((8)) << 12) | (((1)) << 8) | (((0)) << 5)) >> 5)
|
||||
|| reg->value == ((((1) << 19) | (((4)) << 16) | (((8)) << 12) | (((1)) << 8) | (((4)) << 5)) >> 5)
|
||||
|| reg->value == ((((1) << 19) | (((6)) << 16) | (((8)) << 12) | (((1)) << 8) | (((0)) << 5)) >> 5)
|
||||
|| reg->value == ((((1) << 19) | (((0)) << 16) | (((8)) << 12) | (((6)) << 8) | (((1)) << 5)) >> 5)
|
||||
|| reg->value == ((((1) << 19) | (((0)) << 16) | (((8)) << 12) | (((6)) << 8) | (((3)) << 5)) >> 5)
|
||||
|| reg->value == ((((1) << 19) | (((0)) << 16) | (((8)) << 12) | (((6)) << 8) | (((5)) << 5)) >> 5)
|
||||
|| reg->value == ((((1) << 19) | (((0)) << 16) | (((8)) << 12) | (((6)) << 8) | (((7)) << 5)) >> 5)
|
||||
|| reg->value == ((((1) << 19) | (((0)) << 16) | (((8)) << 12) | (((2)) << 8) | (((1)) << 5)) >> 5)
|
||||
|| reg->value == ((((1) << 19) | (((0)) << 16) | (((8)) << 12) | (((2)) << 8) | (((3)) << 5)) >> 5)
|
||||
|| reg->value == ((((1) << 19) | (((0)) << 16) | (((8)) << 12) | (((2)) << 8) | (((5)) << 5)) >> 5)
|
||||
|| reg->value == ((((1) << 19) | (((0)) << 16) | (((8)) << 12) | (((2)) << 8) | (((7)) << 5)) >> 5)
|
||||
|| reg->value == ((((1) << 19) | (((0)) << 16) | (((8)) << 12) | (((5)) << 8) | (((1)) << 5)) >> 5)
|
||||
|| reg->value == ((((1) << 19) | (((0)) << 16) | (((8)) << 12) | (((5)) << 8) | (((3)) << 5)) >> 5)
|
||||
|| reg->value == ((((1) << 19) | (((0)) << 16) | (((8)) << 12) | (((5)) << 8) | (((5)) << 5)) >> 5)
|
||||
|| reg->value == ((((1) << 19) | (((0)) << 16) | (((8)) << 12) | (((5)) << 8) | (((7)) << 5)) >> 5)
|
||||
|| reg->value == ((((1) << 19) | (((4)) << 16) | (((8)) << 12) | (((0)) << 8) | (((2)) << 5)) >> 5)
|
||||
|| reg->value == ((((1) << 19) | (((4)) << 16) | (((8)) << 12) | (((0)) << 8) | (((6)) << 5)) >> 5)
|
||||
|| reg->value == ((((1) << 19) | (((4)) << 16) | (((8)) << 12) | (((4)) << 8) | (((2)) << 5)) >> 5)
|
||||
|| reg->value == ((((1) << 19) | (((4)) << 16) | (((8)) << 12) | (((4)) << 8) | (((6)) << 5)) >> 5)
|
||||
|| reg->value == ((((1) << 19) | (((4)) << 16) | (((8)) << 12) | (((4)) << 8) | (((3)) << 5)) >> 5)
|
||||
|| reg->value == ((((1) << 19) | (((4)) << 16) | (((8)) << 12) | (((4)) << 8) | (((7)) << 5)) >> 5)
|
||||
|| reg->value == ((((1) << 19) | (((4)) << 16) | (((8)) << 12) | (((6)) << 8) | (((1)) << 5)) >> 5)
|
||||
|| reg->value == ((((1) << 19) | (((4)) << 16) | (((8)) << 12) | (((6)) << 8) | (((5)) << 5)) >> 5)
|
||||
|| reg->value == ((((1) << 19) | (((4)) << 16) | (((8)) << 12) | (((2)) << 8) | (((1)) << 5)) >> 5)
|
||||
|| reg->value == ((((1) << 19) | (((4)) << 16) | (((8)) << 12) | (((2)) << 8) | (((5)) << 5)) >> 5)
|
||||
|| reg->value == ((((1) << 19) | (((4)) << 16) | (((8)) << 12) | (((5)) << 8) | (((1)) << 5)) >> 5)
|
||||
|| reg->value == ((((1) << 19) | (((4)) << 16) | (((8)) << 12) | (((5)) << 8) | (((5)) << 5)) >> 5)
|
||||
|| reg->value == ((((1) << 19) | (((6)) << 16) | (((8)) << 12) | (((6)) << 8) | (((1)) << 5)) >> 5)
|
||||
|| reg->value == ((((1) << 19) | (((6)) << 16) | (((8)) << 12) | (((6)) << 8) | (((5)) << 5)) >> 5)
|
||||
|| reg->value == ((((1) << 19) | (((6)) << 16) | (((8)) << 12) | (((2)) << 8) | (((1)) << 5)) >> 5)
|
||||
|| reg->value == ((((1) << 19) | (((6)) << 16) | (((8)) << 12) | (((2)) << 8) | (((5)) << 5)) >> 5)
|
||||
|| reg->value == ((((1) << 19) | (((6)) << 16) | (((8)) << 12) | (((5)) << 8) | (((1)) << 5)) >> 5)
|
||||
|| reg->value == ((((1) << 19) | (((6)) << 16) | (((8)) << 12) | (((5)) << 8) | (((5)) << 5)) >> 5))
|
||||
&& !((~(features) & (0x000000800ULL)) == 0))
|
||||
return 0;
|
||||
|
||||
|
||||
|
||||
if ((reg->value == ((((3) << 19) | ((3) << 16) | ((2) << 12) | ((4) << 8) | ((0) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((3) << 16) | ((2) << 12) | ((4) << 8) | ((1) << 5)) >> 5))
|
||||
&& !(((~(features) & (0x80000000000ULL)) == 0)
|
||||
&& ((~(features) & (0x2000000000ULL)) == 0)))
|
||||
return 0;
|
||||
|
||||
|
||||
if ((reg->value == ((((3) << 19) | ((3) << 16) | ((4) << 12) | ((2) << 8) | ((7) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((0) << 16) | ((6) << 12) | ((6) << 8) | ((1) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((0) << 16) | ((6) << 12) | ((5) << 8) | ((0) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((4) << 16) | ((6) << 12) | ((5) << 8) | ((0) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((6) << 16) | ((6) << 12) | ((6) << 8) | ((0) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((5) << 16) | ((6) << 12) | ((6) << 8) | ((0) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((0) << 16) | ((1) << 12) | ((0) << 8) | ((5) << 5)) >> 5)
|
||||
|| reg->value == ((((3) << 19) | ((0) << 16) | ((1) << 12) | ((0) << 8) | ((6) << 5)) >> 5))
|
||||
&& !(((~(features) & (0x1000000000000ULL)) == 0)))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
193
gcc/testsuite/gcc.dg/tree-ssa/rvrp-logic-2.c
Normal file
193
gcc/testsuite/gcc.dg/tree-ssa/rvrp-logic-2.c
Normal file
@@ -0,0 +1,193 @@
|
||||
/* Extracted from i386.c for compile time issues with ranger taking a
|
||||
long time to evalaute deeply nested logical expressions. */
|
||||
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2" } */
|
||||
|
||||
enum machine_mode
|
||||
{
|
||||
E_VOIDmode,
|
||||
E_BLKmode,
|
||||
E_CCmode,
|
||||
E_CCGCmode,
|
||||
E_CCGOCmode,
|
||||
E_CCNOmode,
|
||||
E_CCGZmode,
|
||||
E_CCAmode,
|
||||
E_CCCmode,
|
||||
E_CCOmode,
|
||||
E_CCPmode,
|
||||
E_CCSmode,
|
||||
E_CCZmode,
|
||||
E_CCFPmode,
|
||||
E_BImode,
|
||||
E_QImode,
|
||||
E_HImode,
|
||||
E_SImode,
|
||||
E_DImode,
|
||||
E_TImode,
|
||||
E_OImode,
|
||||
E_XImode,
|
||||
E_P2QImode,
|
||||
E_P2HImode,
|
||||
E_QQmode,
|
||||
E_HQmode,
|
||||
E_SQmode,
|
||||
E_DQmode,
|
||||
E_TQmode,
|
||||
E_UQQmode,
|
||||
E_UHQmode,
|
||||
E_USQmode,
|
||||
E_UDQmode,
|
||||
E_UTQmode,
|
||||
E_HAmode,
|
||||
E_SAmode,
|
||||
E_DAmode,
|
||||
E_TAmode,
|
||||
E_UHAmode,
|
||||
E_USAmode,
|
||||
E_UDAmode,
|
||||
E_UTAmode,
|
||||
E_SFmode,
|
||||
E_DFmode,
|
||||
E_XFmode,
|
||||
E_TFmode,
|
||||
E_SDmode,
|
||||
E_DDmode,
|
||||
E_TDmode,
|
||||
E_CQImode,
|
||||
E_CP2QImode,
|
||||
E_CHImode,
|
||||
E_CP2HImode,
|
||||
E_CSImode,
|
||||
E_CDImode,
|
||||
E_CTImode,
|
||||
E_COImode,
|
||||
E_CXImode,
|
||||
E_SCmode,
|
||||
E_DCmode,
|
||||
E_XCmode,
|
||||
E_TCmode,
|
||||
E_V2QImode,
|
||||
E_V4QImode,
|
||||
E_V2HImode,
|
||||
E_V1SImode,
|
||||
E_V8QImode,
|
||||
E_V4HImode,
|
||||
E_V2SImode,
|
||||
E_V1DImode,
|
||||
E_V12QImode,
|
||||
E_V6HImode,
|
||||
E_V14QImode,
|
||||
E_V16QImode,
|
||||
E_V8HImode,
|
||||
E_V4SImode,
|
||||
E_V2DImode,
|
||||
E_V1TImode,
|
||||
E_V32QImode,
|
||||
E_V16HImode,
|
||||
E_V8SImode,
|
||||
E_V4DImode,
|
||||
E_V2TImode,
|
||||
E_V64QImode,
|
||||
E_V32HImode,
|
||||
E_V16SImode,
|
||||
E_V8DImode,
|
||||
E_V4TImode,
|
||||
E_V128QImode,
|
||||
E_V64HImode,
|
||||
E_V32SImode,
|
||||
E_V16DImode,
|
||||
E_V8TImode,
|
||||
E_V64SImode,
|
||||
E_V2SFmode,
|
||||
E_V4SFmode,
|
||||
E_V2DFmode,
|
||||
E_V8SFmode,
|
||||
E_V4DFmode,
|
||||
E_V2TFmode,
|
||||
E_V16SFmode,
|
||||
E_V8DFmode,
|
||||
E_V4TFmode,
|
||||
E_V32SFmode,
|
||||
E_V16DFmode,
|
||||
E_V8TFmode,
|
||||
E_V64SFmode,
|
||||
E_V32DFmode,
|
||||
E_V16TFmode,
|
||||
MAX_MACHINE_MODE,
|
||||
MIN_MODE_RANDOM = E_VOIDmode,
|
||||
MAX_MODE_RANDOM = E_BLKmode,
|
||||
MIN_MODE_CC = E_CCmode,
|
||||
MAX_MODE_CC = E_CCFPmode,
|
||||
MIN_MODE_INT = E_QImode,
|
||||
MAX_MODE_INT = E_XImode,
|
||||
MIN_MODE_PARTIAL_INT = E_P2QImode,
|
||||
MAX_MODE_PARTIAL_INT = E_P2HImode,
|
||||
MIN_MODE_FRACT = E_QQmode,
|
||||
MAX_MODE_FRACT = E_TQmode,
|
||||
MIN_MODE_UFRACT = E_UQQmode,
|
||||
MAX_MODE_UFRACT = E_UTQmode,
|
||||
MIN_MODE_ACCUM = E_HAmode,
|
||||
MAX_MODE_ACCUM = E_TAmode,
|
||||
MIN_MODE_UACCUM = E_UHAmode,
|
||||
MAX_MODE_UACCUM = E_UTAmode,
|
||||
MIN_MODE_FLOAT = E_SFmode,
|
||||
MAX_MODE_FLOAT = E_TFmode,
|
||||
MIN_MODE_DECIMAL_FLOAT = E_SDmode,
|
||||
MAX_MODE_DECIMAL_FLOAT = E_TDmode,
|
||||
MIN_MODE_COMPLEX_INT = E_CQImode,
|
||||
MAX_MODE_COMPLEX_INT = E_CXImode,
|
||||
MIN_MODE_COMPLEX_FLOAT = E_SCmode,
|
||||
MAX_MODE_COMPLEX_FLOAT = E_TCmode,
|
||||
MIN_MODE_VECTOR_BOOL = E_VOIDmode,
|
||||
MAX_MODE_VECTOR_BOOL = E_VOIDmode,
|
||||
MIN_MODE_VECTOR_INT = E_V2QImode,
|
||||
MAX_MODE_VECTOR_INT = E_V64SImode,
|
||||
MIN_MODE_VECTOR_FRACT = E_VOIDmode,
|
||||
MAX_MODE_VECTOR_FRACT = E_VOIDmode,
|
||||
MIN_MODE_VECTOR_UFRACT = E_VOIDmode,
|
||||
MAX_MODE_VECTOR_UFRACT = E_VOIDmode,
|
||||
MIN_MODE_VECTOR_ACCUM = E_VOIDmode,
|
||||
MAX_MODE_VECTOR_ACCUM = E_VOIDmode,
|
||||
MIN_MODE_VECTOR_UACCUM = E_VOIDmode,
|
||||
MAX_MODE_VECTOR_UACCUM = E_VOIDmode,
|
||||
MIN_MODE_VECTOR_FLOAT = E_V2SFmode,
|
||||
MAX_MODE_VECTOR_FLOAT = E_V16TFmode,
|
||||
NUM_MACHINE_MODES = MAX_MACHINE_MODE
|
||||
};
|
||||
|
||||
extern unsigned get_mode_alignment (enum machine_mode);
|
||||
long
|
||||
ix86_static_rtx_alignment (enum machine_mode mode)
|
||||
{
|
||||
if (mode == E_DFmode)
|
||||
return 64;
|
||||
if (((mode) == E_XFmode
|
||||
|| ((mode) == ((void) 0, E_V1TImode)
|
||||
|| (mode) == E_TImode
|
||||
|| (mode) == ((void) 0, E_V16QImode)
|
||||
|| (mode) == E_TFmode
|
||||
|| (mode) == ((void) 0, E_V8HImode)
|
||||
|| (mode) == ((void) 0, E_V2DFmode)
|
||||
|| (mode) == ((void) 0, E_V2DImode)
|
||||
|| (mode) == ((void) 0, E_V4SFmode)
|
||||
|| (mode) == ((void) 0, E_V4SImode)
|
||||
|| (mode) == ((void) 0, E_V32QImode)
|
||||
|| (mode) == ((void) 0, E_V16HImode)
|
||||
|| (mode) == ((void) 0, E_V8SImode)
|
||||
|| (mode) == ((void) 0, E_V4DImode)
|
||||
|| (mode) == ((void) 0, E_V8SFmode)
|
||||
|| (mode) == ((void) 0, E_V4DFmode)
|
||||
|| (mode) == ((void) 0, E_V2TImode)
|
||||
|| (mode) == ((void) 0, E_V8DImode)
|
||||
|| (mode) == ((void) 0, E_V64QImode)
|
||||
|| (mode) == ((void) 0, E_V16SImode)
|
||||
|| (mode) == ((void) 0, E_V32HImode)
|
||||
|| (mode) == ((void) 0, E_V8DFmode)
|
||||
|| (mode) == ((void) 0, E_V16SFmode))))
|
||||
return ((128) >
|
||||
(get_mode_alignment (mode)) ? (128)
|
||||
: (get_mode_alignment (mode)));
|
||||
return get_mode_alignment (mode);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fdump-tree-vrp1 -fdelete-null-pointer-checks -fdisable-tree-evrp" } */
|
||||
/* { dg-options "-O2 -fdump-tree-vrp1 -fdelete-null-pointer-checks -fdisable-tree-evrp -fno-rvrp-changes" } */
|
||||
|
||||
struct A
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fdisable-tree-evrp -fdump-tree-vrp1" } */
|
||||
/* { dg-options "-O2 -fdisable-tree-evrp -fdump-tree-vrp1 -fno-rvrp-changes" } */
|
||||
|
||||
struct A
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fdisable-tree-evrp -fdump-tree-vrp1" } */
|
||||
/* { dg-options "-O2 -fdisable-tree-evrp -fdump-tree-vrp1 -fno-rvrp-changes" } */
|
||||
|
||||
int baz (void);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fno-tree-fre -fdisable-tree-evrp -fdump-tree-vrp1-details -fdelete-null-pointer-checks" } */
|
||||
/* { dg-options "-O2 -fno-tree-fre -fdisable-tree-evrp -fdump-tree-vrp1-details -fdelete-null-pointer-checks -fno-rvrp-changes" } */
|
||||
|
||||
int
|
||||
foo (int i, int *p)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fno-tree-fre -fdisable-tree-evrp -fdump-tree-vrp1-details -fdelete-null-pointer-checks" } */
|
||||
/* { dg-options "-O2 -fno-tree-fre -fdisable-tree-evrp -fdump-tree-vrp1-details -fdelete-null-pointer-checks -fno-rvrp-changes" } */
|
||||
|
||||
/* Compile with -fno-tree-fre -O2 to prevent CSEing *p. */
|
||||
int
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fno-tree-fre -fdisable-tree-evrp -fdump-tree-vrp1 -std=gnu89" } */
|
||||
/* { dg-options "-O2 -fno-tree-fre -fdisable-tree-evrp -fdump-tree-vrp1 -std=gnu89 -fno-rvrp-changes" } */
|
||||
|
||||
foo (int *p)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fdump-tree-vrp1 -fdisable-tree-evrp" } */
|
||||
/* { dg-options "-O2 -fdump-tree-vrp1 -fdisable-tree-evrp -fno-rvrp-changes" } */
|
||||
|
||||
int f(int a) {
|
||||
switch (a & 1) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-fwrapv -O1 -ftree-vrp -fdisable-tree-evrp -fdump-tree-vrp1" } */
|
||||
/* { dg-options "-fwrapv -O1 -ftree-vrp -fdisable-tree-evrp -fdump-tree-vrp1 -fno-rvrp-changes" } */
|
||||
|
||||
#include <limits.h>
|
||||
extern void abort ();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-fwrapv -O1 -fno-tree-fre -fdisable-tree-evrp -ftree-vrp -fdump-tree-vrp1" } */
|
||||
/* { dg-options "-fwrapv -O1 -fno-tree-fre -fdisable-tree-evrp -ftree-vrp -fdump-tree-vrp1 -fno-rvrp-changes" } */
|
||||
|
||||
extern void abort ();
|
||||
extern void exit (int);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fdump-tree-vrp1 -fno-tree-fre -fdisable-tree-evrp" } */
|
||||
/* { dg-options "-O2 -fdump-tree-vrp1 -fno-tree-fre -fdisable-tree-evrp -fno-rvrp-changes" } */
|
||||
|
||||
/* This is from PR14052. */
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fdisable-tree-evrp -fdump-tree-vrp1-details" } */
|
||||
/* { dg-options "-O2 -fdisable-tree-evrp -fdump-tree-vrp1-details -fno-rvrp-changes" } */
|
||||
|
||||
int test1(int i, int k)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fdisable-tree-evrp -fdump-tree-vrp1-details" } */
|
||||
/* { dg-options "-O2 -fdisable-tree-evrp -fdump-tree-vrp1-details -fno-rvrp-changes" } */
|
||||
|
||||
int foo(int i)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fdump-tree-vrp1 -fdisable-tree-evrp -fdump-tree-mergephi2" } */
|
||||
/* { dg-options "-O2 -fdump-tree-vrp1 -fdisable-tree-evrp -fdump-tree-mergephi2 -fno-rvrp-changes" } */
|
||||
|
||||
int bar (void);
|
||||
|
||||
|
||||
@@ -2140,6 +2140,7 @@ dump_memory_report (const char *header)
|
||||
dump_ggc_loc_statistics ();
|
||||
dump_alias_stats (stderr);
|
||||
dump_pta_stats (stderr);
|
||||
dump_value_range_stats (stderr);
|
||||
}
|
||||
|
||||
/* Clean up: close opened files, etc. */
|
||||
|
||||
@@ -444,8 +444,10 @@ extern gimple_opt_pass *make_pass_sink_code (gcc::context *ctxt);
|
||||
extern gimple_opt_pass *make_pass_fre (gcc::context *ctxt);
|
||||
extern gimple_opt_pass *make_pass_check_data_deps (gcc::context *ctxt);
|
||||
extern gimple_opt_pass *make_pass_copy_prop (gcc::context *ctxt);
|
||||
extern gimple_opt_pass *make_pass_evrp_copy_prop (gcc::context *ctxt);
|
||||
extern gimple_opt_pass *make_pass_isolate_erroneous_paths (gcc::context *ctxt);
|
||||
extern gimple_opt_pass *make_pass_early_vrp (gcc::context *ctxt);
|
||||
extern gimple_opt_pass *make_pass_ranger_vrp (gcc::context *ctxt);
|
||||
extern gimple_opt_pass *make_pass_vrp (gcc::context *ctxt);
|
||||
extern gimple_opt_pass *make_pass_uncprop (gcc::context *ctxt);
|
||||
extern gimple_opt_pass *make_pass_return_slot (gcc::context *ctxt);
|
||||
|
||||
@@ -636,11 +636,22 @@ const pass_data pass_data_copy_prop =
|
||||
0, /* todo_flags_finish */
|
||||
};
|
||||
|
||||
class pass_data_factory : public pass_data
|
||||
{
|
||||
public:
|
||||
pass_data_factory (const pass_data &pass, const char *name)
|
||||
{
|
||||
memcpy (this, &pass, sizeof (*this));
|
||||
if (name)
|
||||
this->name = name;
|
||||
}
|
||||
};
|
||||
|
||||
class pass_copy_prop : public gimple_opt_pass
|
||||
{
|
||||
public:
|
||||
pass_copy_prop (gcc::context *ctxt)
|
||||
: gimple_opt_pass (pass_data_copy_prop, ctxt)
|
||||
pass_copy_prop (gcc::context *ctxt, const char *name = NULL)
|
||||
: gimple_opt_pass (pass_data_factory (pass_data_copy_prop, name), ctxt)
|
||||
{}
|
||||
|
||||
/* opt_pass methods: */
|
||||
@@ -657,3 +668,12 @@ make_pass_copy_prop (gcc::context *ctxt)
|
||||
{
|
||||
return new pass_copy_prop (ctxt);
|
||||
}
|
||||
|
||||
// Instantiate a new copy propagation pass with a different name, to
|
||||
// minimize changes to tests looking for a particular copyprop dump
|
||||
// file.
|
||||
gimple_opt_pass *
|
||||
make_pass_evrp_copy_prop (gcc::context *ctxt)
|
||||
{
|
||||
return new pass_copy_prop (ctxt, "evrp-copyprop");
|
||||
}
|
||||
|
||||
@@ -887,12 +887,11 @@ simplify_stmt_for_jump_threading (gimple *stmt,
|
||||
copy in tree-vrp is scheduled for removal in gcc-9. */
|
||||
if (gcond *cond_stmt = dyn_cast <gcond *> (stmt))
|
||||
{
|
||||
cached_lhs
|
||||
= x_vr_values->vrp_evaluate_conditional (gimple_cond_code (cond_stmt),
|
||||
gimple_cond_lhs (cond_stmt),
|
||||
gimple_cond_rhs (cond_stmt),
|
||||
within_stmt);
|
||||
return cached_lhs;
|
||||
simplify_using_ranges simplifier (x_vr_values);
|
||||
return simplifier.vrp_evaluate_conditional (gimple_cond_code (cond_stmt),
|
||||
gimple_cond_lhs (cond_stmt),
|
||||
gimple_cond_rhs (cond_stmt),
|
||||
within_stmt);
|
||||
}
|
||||
|
||||
if (gswitch *switch_stmt = dyn_cast <gswitch *> (stmt))
|
||||
|
||||
@@ -902,6 +902,7 @@ substitute_and_fold_engine::replace_phi_args_in (gphi *phi)
|
||||
{
|
||||
size_t i;
|
||||
bool replaced = false;
|
||||
gimple *orig_phi = gimple_copy (phi);
|
||||
|
||||
for (i = 0; i < gimple_phi_num_args (phi); i++)
|
||||
{
|
||||
@@ -940,6 +941,9 @@ substitute_and_fold_engine::replace_phi_args_in (gphi *phi)
|
||||
}
|
||||
}
|
||||
|
||||
if (replaced)
|
||||
tmp_stats_changed_phi (as_a<gphi *> (orig_phi), phi);
|
||||
|
||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
||||
{
|
||||
if (!replaced)
|
||||
@@ -1075,6 +1079,7 @@ substitute_and_fold_dom_walker::before_dom_children (basic_block bb)
|
||||
fprintf (dump_file, "\n");
|
||||
}
|
||||
stmts_to_remove.safe_push (phi);
|
||||
substitute_and_fold_engine->tmp_stats_remove_stmt (phi, sprime);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -1120,6 +1125,7 @@ substitute_and_fold_dom_walker::before_dom_children (basic_block bb)
|
||||
fprintf (dump_file, "\n");
|
||||
}
|
||||
stmts_to_remove.safe_push (stmt);
|
||||
substitute_and_fold_engine->tmp_stats_remove_stmt (stmt, sprime);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -1157,6 +1163,7 @@ substitute_and_fold_dom_walker::before_dom_children (basic_block bb)
|
||||
specific information. Do this before propagating
|
||||
into the stmt to not disturb pass specific information. */
|
||||
update_stmt_if_modified (stmt);
|
||||
substitute_and_fold_engine->tmp_stats_set_modified (did_replace);
|
||||
if (substitute_and_fold_engine->fold_stmt (&i))
|
||||
{
|
||||
did_replace = true;
|
||||
|
||||
@@ -120,6 +120,13 @@ class substitute_and_fold_engine
|
||||
/* Users like VRP can set this when they want to perform
|
||||
folding for every propagation. */
|
||||
bool fold_all_stmts;
|
||||
|
||||
// FIXME: These are temporarily used for keeping track of IL changes
|
||||
// for evrp. They should be removed before merging upstream.
|
||||
virtual void tmp_stats_remove_stmt (gimple *, tree) { }
|
||||
virtual void tmp_stats_set_modified (bool) { }
|
||||
virtual void tmp_stats_changed_phi (gphi *orig_phi ATTRIBUTE_UNUSED,
|
||||
gphi *new_phi ATTRIBUTE_UNUSED) { }
|
||||
};
|
||||
|
||||
#endif /* _TREE_SSA_PROPAGATE_H */
|
||||
|
||||
@@ -1402,7 +1402,7 @@ dump_assert_info (FILE *file, const assert_info &assert)
|
||||
fprintf (file, "] %s ", get_tree_code_name (assert.comp_code));
|
||||
fprintf (file, "val=[");
|
||||
print_generic_expr (file, assert.val);
|
||||
fprintf (file, "]\n\n");
|
||||
fprintf (file, "]\n");
|
||||
}
|
||||
|
||||
DEBUG_FUNCTION void
|
||||
@@ -1637,7 +1637,7 @@ extract_code_and_val_from_cond_with_ops (tree name, enum tree_code cond_code,
|
||||
(to transform signed values into unsigned) and at the end xor
|
||||
SGNBIT back. */
|
||||
|
||||
static wide_int
|
||||
wide_int
|
||||
masked_increment (const wide_int &val_in, const wide_int &mask,
|
||||
const wide_int &sgnbit, unsigned int prec)
|
||||
{
|
||||
@@ -3373,7 +3373,7 @@ public:
|
||||
struct function *fun;
|
||||
|
||||
void vrp_initialize (struct function *);
|
||||
void vrp_finalize (bool);
|
||||
void vrp_finalize (class vrp_folder *, bool);
|
||||
|
||||
class vr_values vr_values;
|
||||
|
||||
@@ -3938,23 +3938,28 @@ vrp_prop::visit_phi (gphi *phi)
|
||||
|
||||
class vrp_folder : public substitute_and_fold_engine
|
||||
{
|
||||
public:
|
||||
vrp_folder () : substitute_and_fold_engine (/* Fold all stmts. */ true) { }
|
||||
public:
|
||||
vrp_folder (vr_values *v)
|
||||
: substitute_and_fold_engine (/* Fold all stmts. */ true),
|
||||
m_vr_values (v), simplifier (v)
|
||||
{ }
|
||||
tree get_value (tree, gimple *stmt) FINAL OVERRIDE;
|
||||
bool fold_stmt (gimple_stmt_iterator *) FINAL OVERRIDE;
|
||||
|
||||
class vr_values *vr_values;
|
||||
class vr_values *m_vr_values;
|
||||
|
||||
private:
|
||||
bool fold_predicate_in (gimple_stmt_iterator *);
|
||||
/* Delegators. */
|
||||
tree vrp_evaluate_conditional (tree_code code, tree op0,
|
||||
tree op1, gimple *stmt)
|
||||
{ return vr_values->vrp_evaluate_conditional (code, op0, op1, stmt); }
|
||||
{ return simplifier.vrp_evaluate_conditional (code, op0, op1, stmt); }
|
||||
bool simplify_stmt_using_ranges (gimple_stmt_iterator *gsi)
|
||||
{ return vr_values->simplify_stmt_using_ranges (gsi); }
|
||||
{ return simplifier.simplify (gsi); }
|
||||
tree op_with_constant_singleton_value_range (tree op)
|
||||
{ return vr_values->op_with_constant_singleton_value_range (op); }
|
||||
{ return m_vr_values->op_with_constant_singleton_value_range (op); }
|
||||
|
||||
simplify_using_ranges simplifier;
|
||||
};
|
||||
|
||||
/* If the statement pointed by SI has a predicate whose value can be
|
||||
@@ -4096,7 +4101,8 @@ simplify_stmt_for_jump_threading (gimple *stmt, gimple *within_stmt,
|
||||
tree op1 = gimple_cond_rhs (cond_stmt);
|
||||
op1 = lhs_of_dominating_assert (op1, bb, stmt);
|
||||
|
||||
return vr_values->vrp_evaluate_conditional (gimple_cond_code (cond_stmt),
|
||||
simplify_using_ranges simplifier (vr_values);
|
||||
return simplifier.vrp_evaluate_conditional (gimple_cond_code (cond_stmt),
|
||||
op0, op1, within_stmt);
|
||||
}
|
||||
|
||||
@@ -4332,7 +4338,7 @@ identify_jump_threads (struct function *fun, class vr_values *vr_values)
|
||||
/* Traverse all the blocks folding conditionals with known ranges. */
|
||||
|
||||
void
|
||||
vrp_prop::vrp_finalize (bool warn_array_bounds_p)
|
||||
vrp_prop::vrp_finalize (vrp_folder *folder, bool warn_array_bounds_p)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
@@ -4376,9 +4382,7 @@ vrp_prop::vrp_finalize (bool warn_array_bounds_p)
|
||||
if (warn_array_bounds && warn_array_bounds_p)
|
||||
set_all_edges_as_executable (fun);
|
||||
|
||||
class vrp_folder vrp_folder;
|
||||
vrp_folder.vr_values = &vr_values;
|
||||
vrp_folder.substitute_and_fold ();
|
||||
folder->substitute_and_fold ();
|
||||
|
||||
if (warn_array_bounds && warn_array_bounds_p)
|
||||
{
|
||||
@@ -4453,7 +4457,10 @@ execute_vrp (struct function *fun, bool warn_array_bounds_p)
|
||||
class vrp_prop vrp_prop;
|
||||
vrp_prop.vrp_initialize (fun);
|
||||
vrp_prop.ssa_propagate ();
|
||||
vrp_prop.vrp_finalize (warn_array_bounds_p);
|
||||
/* Instantiate the folder here, so that edge cleanups happen at the
|
||||
end of this function. */
|
||||
vrp_folder folder (&vrp_prop.vr_values);
|
||||
vrp_prop.vrp_finalize (&folder, warn_array_bounds_p);
|
||||
|
||||
/* We must identify jump threading opportunities before we release
|
||||
the datastructures built by VRP. */
|
||||
@@ -4471,7 +4478,8 @@ execute_vrp (struct function *fun, bool warn_array_bounds_p)
|
||||
{
|
||||
gimple *last = last_stmt (bb);
|
||||
if (last && gimple_code (last) == GIMPLE_COND)
|
||||
vrp_prop.vr_values.simplify_cond_using_ranges_2 (as_a <gcond *> (last));
|
||||
simplify_cond_using_ranges_2 (&vrp_prop.vr_values,
|
||||
as_a <gcond *> (last));
|
||||
}
|
||||
|
||||
free_numbers_of_iterations_estimates (fun);
|
||||
@@ -4496,7 +4504,6 @@ execute_vrp (struct function *fun, bool warn_array_bounds_p)
|
||||
processing by the pass manager. */
|
||||
thread_through_all_blocks (false);
|
||||
|
||||
vrp_prop.vr_values.cleanup_edges_and_switches ();
|
||||
threadedge_finalize_values ();
|
||||
|
||||
scev_finalize ();
|
||||
|
||||
@@ -30,12 +30,14 @@ along with GCC; see the file COPYING3. If not see
|
||||
value_range_equiv::value_range_equiv (tree min, tree max, bitmap equiv,
|
||||
value_range_kind kind)
|
||||
{
|
||||
m_discriminator = IRANGE_KIND_INT;
|
||||
m_equiv = NULL;
|
||||
set (min, max, equiv, kind);
|
||||
}
|
||||
|
||||
value_range_equiv::value_range_equiv (const value_range &other)
|
||||
{
|
||||
m_discriminator = IRANGE_KIND_INT;
|
||||
m_equiv = NULL;
|
||||
set (other.min(), other.max (), NULL, other.kind ());
|
||||
}
|
||||
|
||||
@@ -27,7 +27,11 @@ along with GCC; see the file COPYING3. If not see
|
||||
class GTY((user)) value_range_equiv : public value_range
|
||||
{
|
||||
public:
|
||||
value_range_equiv () : value_range () { m_equiv = NULL; }
|
||||
value_range_equiv () : value_range ()
|
||||
{
|
||||
m_discriminator = IRANGE_KIND_INT;
|
||||
m_equiv = NULL;
|
||||
}
|
||||
value_range_equiv (const value_range &);
|
||||
/* Deep-copies equiv bitmap argument. */
|
||||
value_range_equiv (tree, tree, bitmap = NULL, value_range_kind = VR_RANGE);
|
||||
|
||||
1111
gcc/value-range.cc
1111
gcc/value-range.cc
File diff suppressed because it is too large
Load Diff
@@ -35,17 +35,22 @@ enum value_range_kind
|
||||
VR_LAST
|
||||
};
|
||||
|
||||
// Range of values that can be associated with an SSA_NAME.
|
||||
// Helper for is_a<> to distinguish between irange and widest_irange.
|
||||
|
||||
class GTY((for_user)) value_range
|
||||
enum irange_discriminator
|
||||
{
|
||||
IRANGE_KIND_UNKNOWN,
|
||||
IRANGE_KIND_INT,
|
||||
IRANGE_KIND_WIDEST_INT
|
||||
};
|
||||
|
||||
// Range of values that can be associated with an SSA_NAME.
|
||||
//
|
||||
// This is the base class without any storage.
|
||||
|
||||
class irange
|
||||
{
|
||||
public:
|
||||
value_range ();
|
||||
value_range (tree, tree, value_range_kind = VR_RANGE);
|
||||
value_range (tree type, const wide_int &, const wide_int &,
|
||||
value_range_kind = VR_RANGE);
|
||||
value_range (tree type);
|
||||
|
||||
void set (tree, tree, value_range_kind = VR_RANGE);
|
||||
void set (tree);
|
||||
void set_nonzero (tree);
|
||||
@@ -63,14 +68,15 @@ public:
|
||||
void set_varying (tree type);
|
||||
void set_undefined ();
|
||||
|
||||
void union_ (const value_range *);
|
||||
void intersect (const value_range *);
|
||||
void union_ (const value_range &);
|
||||
void intersect (const value_range &);
|
||||
void union_ (const irange *);
|
||||
void intersect (const irange *);
|
||||
void union_ (const irange &);
|
||||
void intersect (const irange &);
|
||||
|
||||
bool operator== (const value_range &) const;
|
||||
bool operator!= (const value_range &) const /* = delete */;
|
||||
bool equal_p (const value_range &) const;
|
||||
irange& operator= (const irange &);
|
||||
bool operator== (const irange &) const;
|
||||
bool operator!= (const irange &r) const { return !(*this == r); }
|
||||
bool equal_p (const irange &) const;
|
||||
|
||||
/* Misc methods. */
|
||||
tree type () const;
|
||||
@@ -78,14 +84,13 @@ public:
|
||||
bool zero_p () const;
|
||||
bool nonzero_p () const;
|
||||
bool singleton_p (tree *result = NULL) const;
|
||||
void dump (FILE *) const;
|
||||
void dump () const;
|
||||
void dump (FILE * = stderr) const;
|
||||
void simple_dump (FILE *) const;
|
||||
|
||||
static bool supports_type_p (tree);
|
||||
void normalize_symbolics ();
|
||||
void normalize_addresses ();
|
||||
|
||||
static const unsigned int m_max_pairs = 2;
|
||||
bool contains_p (tree) const;
|
||||
unsigned num_pairs () const;
|
||||
wide_int lower_bound (unsigned = 0) const;
|
||||
@@ -95,105 +100,239 @@ public:
|
||||
|
||||
protected:
|
||||
void check ();
|
||||
static value_range union_helper (const value_range *, const value_range *);
|
||||
static value_range intersect_helper (const value_range *,
|
||||
const value_range *);
|
||||
|
||||
friend void gt_ggc_mx_value_range (void *);
|
||||
friend void gt_pch_p_11value_range (void *, void *,
|
||||
gt_pointer_operator, void *);
|
||||
friend void gt_pch_nx_value_range (void *);
|
||||
friend void gt_ggc_mx (value_range &);
|
||||
friend void gt_ggc_mx (value_range *&);
|
||||
friend void gt_pch_nx (value_range &);
|
||||
friend void gt_pch_nx (value_range *, gt_pointer_operator, void *);
|
||||
|
||||
enum value_range_kind m_kind;
|
||||
tree m_min;
|
||||
tree m_max;
|
||||
// Returns true for an old-school value_range with anti ranges.
|
||||
bool simple_ranges_p () const { return m_max_ranges == 1; }
|
||||
irange (tree *, unsigned);
|
||||
irange (tree *, unsigned, const irange &);
|
||||
|
||||
private:
|
||||
int value_inside_range (tree) const;
|
||||
|
||||
void intersect_from_wide_ints (const wide_int &, const wide_int &);
|
||||
bool maybe_anti_range (const irange &) const;
|
||||
void multi_range_set_anti_range (tree, tree);
|
||||
void multi_range_union (const irange &);
|
||||
void multi_range_intersect (const irange &);
|
||||
tree tree_lower_bound (unsigned = 0) const;
|
||||
tree tree_upper_bound (unsigned) const;
|
||||
|
||||
bool compatible_copy_p (const irange &) const;
|
||||
void copy_compatible_range (const irange &);
|
||||
void copy_simple_range (const irange &);
|
||||
|
||||
public:
|
||||
ENUM_BITFIELD(irange_discriminator) m_discriminator : 8;
|
||||
protected:
|
||||
unsigned char m_num_ranges;
|
||||
unsigned char m_max_ranges;
|
||||
ENUM_BITFIELD(value_range_kind) m_kind : 8;
|
||||
|
||||
tree *m_base;
|
||||
};
|
||||
|
||||
extern bool range_has_numeric_bounds_p (const value_range *);
|
||||
// int_range<N> describes an irange with N pairs of ranges.
|
||||
|
||||
template<unsigned N>
|
||||
class GTY((user)) int_range : public irange
|
||||
{
|
||||
public:
|
||||
int_range ();
|
||||
int_range (tree, tree, value_range_kind = VR_RANGE);
|
||||
int_range (tree type, const wide_int &, const wide_int &,
|
||||
value_range_kind = VR_RANGE);
|
||||
int_range (tree type);
|
||||
int_range (const int_range &);
|
||||
int_range (const irange &);
|
||||
int_range& operator= (const int_range &);
|
||||
private:
|
||||
template <unsigned X> friend void gt_ggc_mx (int_range<X> *);
|
||||
template <unsigned X> friend void gt_pch_nx (int_range<X> *);
|
||||
template <unsigned X> friend void gt_pch_nx (int_range<X> *,
|
||||
gt_pointer_operator, void *);
|
||||
/* ?? hash-traits.h has its own extern for these, which is causing
|
||||
them to never be picked up by the templates. For now, define
|
||||
elsewhere. */
|
||||
//template<unsigned X> friend void gt_ggc_mx (int_range<X> *&);
|
||||
//template<unsigned X> friend void gt_pch_nx (int_range<X> *&);
|
||||
friend void gt_ggc_mx (int_range<1> *&);
|
||||
friend void gt_pch_nx (int_range<1> *&);
|
||||
|
||||
tree m_ranges[N*2];
|
||||
};
|
||||
|
||||
// This is a special int_range<> with only one pair, plus
|
||||
// VR_ANTI_RANGE magic to describe slightly more than can be described
|
||||
// in one pair. It is described in the code as a "simple range" (as
|
||||
// opposed to multi-ranges which have multiple sub-ranges). It is
|
||||
// provided for backward compatibility with the more limited,
|
||||
// traditional value_range's.
|
||||
//
|
||||
// simple_ranges_p() returns true for value_range's.
|
||||
//
|
||||
// There are copy methods to seamlessly copy to/fro multi-ranges.
|
||||
|
||||
typedef int_range<1> value_range;
|
||||
|
||||
// An irange with "unlimited" sub-ranges. In reality we are limited
|
||||
// by the number of values that fit in an `m_num_ranges'.
|
||||
//
|
||||
// A widest_irange starts with a handful of sub-ranges in local
|
||||
// storage and will grow into the heap as necessary.
|
||||
|
||||
class widest_irange : public irange
|
||||
{
|
||||
public:
|
||||
widest_irange ();
|
||||
widest_irange (tree, tree, value_range_kind = VR_RANGE);
|
||||
widest_irange (tree, const wide_int &, const wide_int &,
|
||||
value_range_kind = VR_RANGE);
|
||||
widest_irange (tree type);
|
||||
widest_irange (const widest_irange &);
|
||||
widest_irange (const irange &);
|
||||
~widest_irange ();
|
||||
widest_irange& operator= (const widest_irange &);
|
||||
void resize_if_needed (unsigned);
|
||||
#if CHECKING_P
|
||||
static void stats_dump (FILE *);
|
||||
#endif
|
||||
|
||||
private:
|
||||
static const unsigned m_sub_ranges_in_local_storage = 5;
|
||||
void init_widest_irange ();
|
||||
|
||||
// Memory usage stats.
|
||||
void stats_register_use (void);
|
||||
static int stats_used_buckets[11];
|
||||
|
||||
tree *m_blob;
|
||||
tree m_ranges[m_sub_ranges_in_local_storage*2];
|
||||
};
|
||||
|
||||
value_range union_helper (const value_range *, const value_range *);
|
||||
value_range intersect_helper (const value_range *, const value_range *);
|
||||
extern bool range_has_numeric_bounds_p (const irange *);
|
||||
extern bool ranges_from_anti_range (const value_range *,
|
||||
value_range *, value_range *);
|
||||
extern void dump_value_range (FILE *, const value_range *);
|
||||
extern void dump_value_range (FILE *, const irange *);
|
||||
extern void dump_value_range_stats (FILE *);
|
||||
extern bool vrp_val_is_min (const_tree);
|
||||
extern bool vrp_val_is_max (const_tree);
|
||||
extern tree vrp_val_min (const_tree);
|
||||
extern tree vrp_val_max (const_tree);
|
||||
extern bool vrp_operand_equal_p (const_tree, const_tree);
|
||||
|
||||
template<unsigned N>
|
||||
inline
|
||||
value_range::value_range ()
|
||||
int_range<N>::int_range ()
|
||||
: irange (m_ranges, N)
|
||||
{
|
||||
m_kind = VR_UNDEFINED;
|
||||
m_min = m_max = NULL;
|
||||
m_num_ranges = 0;
|
||||
}
|
||||
|
||||
inline value_range_kind
|
||||
value_range::kind () const
|
||||
irange::kind () const
|
||||
{
|
||||
return m_kind;
|
||||
if (simple_ranges_p ())
|
||||
return m_kind;
|
||||
|
||||
if (undefined_p ())
|
||||
return VR_UNDEFINED;
|
||||
|
||||
if (varying_p ())
|
||||
return VR_VARYING;
|
||||
|
||||
if (m_kind == VR_ANTI_RANGE)
|
||||
{
|
||||
// VR_ANTI_RANGE's are only valid for symbolics.
|
||||
gcc_checking_assert (m_num_ranges == 1);
|
||||
gcc_checking_assert (!range_has_numeric_bounds_p (this));
|
||||
return VR_ANTI_RANGE;
|
||||
}
|
||||
|
||||
return VR_RANGE;
|
||||
}
|
||||
|
||||
inline tree
|
||||
value_range::type () const
|
||||
irange::type () const
|
||||
{
|
||||
return TREE_TYPE (min ());
|
||||
gcc_checking_assert (!undefined_p ());
|
||||
return TREE_TYPE (m_base[0]);
|
||||
}
|
||||
|
||||
inline tree
|
||||
value_range::min () const
|
||||
irange::tree_lower_bound (unsigned i) const
|
||||
{
|
||||
return m_min;
|
||||
return m_base[i * 2];
|
||||
}
|
||||
|
||||
inline tree
|
||||
value_range::max () const
|
||||
irange::tree_upper_bound (unsigned i) const
|
||||
{
|
||||
return m_max;
|
||||
return m_base[i * 2 + 1];
|
||||
}
|
||||
|
||||
inline tree
|
||||
irange::min () const
|
||||
{
|
||||
return tree_lower_bound (0);
|
||||
}
|
||||
|
||||
inline tree
|
||||
irange::max () const
|
||||
{
|
||||
if (m_num_ranges)
|
||||
return tree_upper_bound (m_num_ranges - 1);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
inline bool
|
||||
value_range::varying_p () const
|
||||
irange::varying_p () const
|
||||
{
|
||||
return m_kind == VR_VARYING;
|
||||
if (simple_ranges_p ())
|
||||
return m_kind == VR_VARYING;
|
||||
|
||||
return (m_num_ranges == 1
|
||||
&& vrp_val_is_min (m_base[0])
|
||||
&& vrp_val_is_max (m_base[1]));
|
||||
}
|
||||
|
||||
inline bool
|
||||
value_range::undefined_p () const
|
||||
irange::undefined_p () const
|
||||
{
|
||||
return m_kind == VR_UNDEFINED;
|
||||
if (simple_ranges_p ())
|
||||
{
|
||||
gcc_checking_assert (m_kind != VR_UNDEFINED || m_num_ranges == 0);
|
||||
return m_kind == VR_UNDEFINED;
|
||||
}
|
||||
return m_num_ranges == 0;
|
||||
}
|
||||
|
||||
inline bool
|
||||
value_range::zero_p () const
|
||||
irange::zero_p () const
|
||||
{
|
||||
return (m_kind == VR_RANGE
|
||||
&& integer_zerop (m_min)
|
||||
&& integer_zerop (m_max));
|
||||
if (m_num_ranges == 1
|
||||
&& integer_zerop (tree_lower_bound (0))
|
||||
&& integer_zerop (tree_upper_bound (0)))
|
||||
{
|
||||
gcc_checking_assert (!simple_ranges_p () || m_kind == VR_RANGE);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool
|
||||
value_range::nonzero_p () const
|
||||
irange::nonzero_p () const
|
||||
{
|
||||
if (m_kind == VR_ANTI_RANGE
|
||||
&& !TYPE_UNSIGNED (type ())
|
||||
&& integer_zerop (m_min)
|
||||
&& integer_zerop (m_max))
|
||||
return true;
|
||||
if (undefined_p ())
|
||||
return false;
|
||||
|
||||
return (m_kind == VR_RANGE
|
||||
&& TYPE_UNSIGNED (type ())
|
||||
&& integer_onep (m_min)
|
||||
&& vrp_val_is_max (m_max));
|
||||
tree zero = build_zero_cst (type ());
|
||||
return *this == int_range<1> (zero, zero, VR_ANTI_RANGE);
|
||||
}
|
||||
|
||||
inline bool
|
||||
value_range::supports_type_p (tree type)
|
||||
irange::supports_type_p (tree type)
|
||||
{
|
||||
if (type && (INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type)))
|
||||
return type;
|
||||
@@ -201,7 +340,7 @@ value_range::supports_type_p (tree type)
|
||||
}
|
||||
|
||||
inline bool
|
||||
range_includes_zero_p (const value_range *vr)
|
||||
range_includes_zero_p (const irange *vr)
|
||||
{
|
||||
if (vr->undefined_p ())
|
||||
return false;
|
||||
@@ -212,4 +351,37 @@ range_includes_zero_p (const value_range *vr)
|
||||
return vr->may_contain_p (build_zero_cst (vr->type ()));
|
||||
}
|
||||
|
||||
template<unsigned N>
|
||||
static inline void
|
||||
gt_ggc_mx (int_range<N> *x)
|
||||
{
|
||||
for (unsigned i = 0; i < N; ++i)
|
||||
{
|
||||
gt_ggc_mx (x->m_ranges[i * 2]);
|
||||
gt_ggc_mx (x->m_ranges[i * 2 + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
template<unsigned N>
|
||||
static inline void
|
||||
gt_pch_nx (int_range<N> *x)
|
||||
{
|
||||
for (unsigned i = 0; i < N; ++i)
|
||||
{
|
||||
gt_pch_nx (x->m_ranges[i * 2]);
|
||||
gt_pch_nx (x->m_ranges[i * 2 + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
template<unsigned N>
|
||||
static inline void
|
||||
gt_pch_nx (int_range<N> *x, gt_pointer_operator op, void *cookie)
|
||||
{
|
||||
for (unsigned i = 0; i < N; ++i)
|
||||
{
|
||||
op (&x->m_ranges[i * 2], cookie);
|
||||
op (&x->m_ranges[i * 2 + 1], cookie);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // GCC_VALUE_RANGE_H
|
||||
|
||||
398
gcc/vr-values.c
398
gcc/vr-values.c
@@ -50,6 +50,7 @@ along with GCC; see the file COPYING3. If not see
|
||||
#include "vr-values.h"
|
||||
#include "cfghooks.h"
|
||||
#include "range-op.h"
|
||||
#include "misc.h"
|
||||
|
||||
/* Set value range VR to a non-negative range of type TYPE. */
|
||||
|
||||
@@ -92,7 +93,8 @@ vr_values::get_lattice_entry (const_tree var)
|
||||
return vr;
|
||||
|
||||
/* Create a default value range. */
|
||||
vr_value[ver] = vr = vrp_value_range_pool.allocate ();
|
||||
vr = new (vrp_value_range_pool.allocate ()) value_range_equiv;
|
||||
vr_value[ver] = vr;
|
||||
|
||||
/* After propagation finished return varying. */
|
||||
if (values_propagated)
|
||||
@@ -146,7 +148,7 @@ vr_values::get_lattice_entry (const_tree var)
|
||||
return NULL. Otherwise create an empty range if none existed for VAR. */
|
||||
|
||||
const value_range_equiv *
|
||||
vr_values::get_value_range (const_tree var)
|
||||
vr_values::get_value_range (const_tree var, gimple *stmt ATTRIBUTE_UNUSED)
|
||||
{
|
||||
/* If we have no recorded ranges, then return NULL. */
|
||||
if (!vr_value)
|
||||
@@ -171,6 +173,25 @@ vr_values::get_value_range (const_tree var)
|
||||
return vr;
|
||||
}
|
||||
|
||||
bool
|
||||
vr_values::range_of_expr (irange &r, tree expr, gimple *stmt ATTRIBUTE_UNUSED)
|
||||
{
|
||||
tree type = TREE_TYPE (expr);
|
||||
if (!irange::supports_type_p (type))
|
||||
return false;
|
||||
|
||||
if (TREE_CODE (expr) == SSA_NAME)
|
||||
{
|
||||
const value_range_equiv *vr = get_value_range (expr);
|
||||
r = *vr;
|
||||
}
|
||||
else if (TREE_CODE (expr) == INTEGER_CST)
|
||||
r.set (expr, expr);
|
||||
else
|
||||
r.set_varying (type);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Set the lattice entry for DEF to VARYING. */
|
||||
|
||||
void
|
||||
@@ -435,10 +456,8 @@ vr_values::op_with_constant_singleton_value_range (tree op)
|
||||
/* Return true if op is in a boolean [0, 1] value-range. */
|
||||
|
||||
bool
|
||||
vr_values::op_with_boolean_value_range_p (tree op)
|
||||
simplify_using_ranges::op_with_boolean_value_range_p (tree op, gimple *stmt)
|
||||
{
|
||||
const value_range_equiv *vr;
|
||||
|
||||
if (TYPE_PRECISION (TREE_TYPE (op)) == 1)
|
||||
return true;
|
||||
|
||||
@@ -449,10 +468,11 @@ vr_values::op_with_boolean_value_range_p (tree op)
|
||||
if (TREE_CODE (op) != SSA_NAME)
|
||||
return false;
|
||||
|
||||
vr = get_value_range (op);
|
||||
return (vr->kind () == VR_RANGE
|
||||
&& integer_zerop (vr->min ())
|
||||
&& integer_onep (vr->max ()));
|
||||
widest_irange r;
|
||||
gcc_assert (store->range_of_expr (r, op, stmt));
|
||||
return (r.kind () == VR_RANGE
|
||||
&& integer_zerop (r.min ())
|
||||
&& integer_onep (r.max ()));
|
||||
}
|
||||
|
||||
/* Extract value range information for VAR when (OP COND_CODE LIMIT) is
|
||||
@@ -978,8 +998,8 @@ vr_values::extract_range_from_comparison (value_range_equiv *vr,
|
||||
bool sop;
|
||||
tree val;
|
||||
|
||||
val = vrp_evaluate_conditional_warnv_with_ops (code, op0, op1, false, &sop,
|
||||
NULL);
|
||||
val = simplifier.vrp_evaluate_conditional_warnv_with_ops (code, op0, op1,
|
||||
false, &sop, NULL);
|
||||
if (val)
|
||||
{
|
||||
/* Since this expression was found on the RHS of an assignment,
|
||||
@@ -1002,20 +1022,21 @@ vr_values::extract_range_from_comparison (value_range_equiv *vr,
|
||||
always overflow. Set *OVF to true if it is known to always
|
||||
overflow. */
|
||||
|
||||
bool
|
||||
vr_values::check_for_binary_op_overflow (enum tree_code subcode, tree type,
|
||||
tree op0, tree op1, bool *ovf)
|
||||
static bool
|
||||
check_for_binary_op_overflow (range_store *store, gimple *stmt,
|
||||
enum tree_code subcode, tree type,
|
||||
tree op0, tree op1, bool *ovf)
|
||||
{
|
||||
value_range vr0, vr1;
|
||||
if (TREE_CODE (op0) == SSA_NAME)
|
||||
vr0 = *get_value_range (op0);
|
||||
gcc_assert (store->range_of_expr (vr0, op0, stmt));
|
||||
else if (TREE_CODE (op0) == INTEGER_CST)
|
||||
vr0.set (op0);
|
||||
else
|
||||
vr0.set_varying (TREE_TYPE (op0));
|
||||
|
||||
if (TREE_CODE (op1) == SSA_NAME)
|
||||
vr1 = *get_value_range (op1);
|
||||
store->range_of_expr (vr1, op1, stmt);
|
||||
else if (TREE_CODE (op1) == INTEGER_CST)
|
||||
vr1.set (op1);
|
||||
else
|
||||
@@ -1395,7 +1416,8 @@ vr_values::extract_range_basic (value_range_equiv *vr, gimple *stmt)
|
||||
if (code == IMAGPART_EXPR)
|
||||
{
|
||||
bool ovf = false;
|
||||
if (check_for_binary_op_overflow (subcode, type,
|
||||
if (check_for_binary_op_overflow (this, stmt,
|
||||
subcode, type,
|
||||
op0, op1, &ovf))
|
||||
vr->set (build_int_cst (type, ovf));
|
||||
else if (TYPE_PRECISION (type) == 1
|
||||
@@ -1636,7 +1658,7 @@ compare_ranges (enum tree_code comp, const value_range_equiv *vr0,
|
||||
assumed signed overflow is undefined. */
|
||||
|
||||
static tree
|
||||
compare_range_with_value (enum tree_code comp, const value_range_equiv *vr,
|
||||
compare_range_with_value (enum tree_code comp, const irange *vr,
|
||||
tree val, bool *strict_overflow_p)
|
||||
{
|
||||
if (vr->varying_p () || vr->undefined_p ())
|
||||
@@ -1940,21 +1962,18 @@ vr_values::dump_all_value_ranges (FILE *file)
|
||||
fprintf (file, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
fprintf (file, "\n");
|
||||
}
|
||||
|
||||
/* Initialize VRP lattice. */
|
||||
|
||||
vr_values::vr_values () : vrp_value_range_pool ("Tree VRP value ranges")
|
||||
vr_values::vr_values () : vrp_value_range_pool ("Tree VRP value ranges"),
|
||||
simplifier (this)
|
||||
{
|
||||
values_propagated = false;
|
||||
num_vr_values = num_ssa_names * 2;
|
||||
vr_value = XCNEWVEC (value_range_equiv *, num_vr_values);
|
||||
vr_phi_edge_counts = XCNEWVEC (int, num_ssa_names);
|
||||
bitmap_obstack_initialize (&vrp_equiv_obstack);
|
||||
to_remove_edges = vNULL;
|
||||
to_update_switch_stmts = vNULL;
|
||||
}
|
||||
|
||||
/* Free VRP lattice. */
|
||||
@@ -1971,12 +1990,6 @@ vr_values::~vr_values ()
|
||||
and not available. */
|
||||
vr_value = NULL;
|
||||
vr_phi_edge_counts = NULL;
|
||||
|
||||
/* If there are entries left in TO_REMOVE_EDGES or TO_UPDATE_SWITCH_STMTS
|
||||
then an EVRP client did not clean up properly. Catch it now rather
|
||||
than seeing something more obscure later. */
|
||||
gcc_assert (to_remove_edges.is_empty ()
|
||||
&& to_update_switch_stmts.is_empty ());
|
||||
}
|
||||
|
||||
|
||||
@@ -2094,10 +2107,10 @@ vr_values::vrp_visit_assignment_or_call (gimple *stmt, tree *output_p,
|
||||
is varying or undefined. Uses TEM as storage for the alternate range. */
|
||||
|
||||
const value_range_equiv *
|
||||
vr_values::get_vr_for_comparison (int i, value_range_equiv *tem)
|
||||
simplify_using_ranges::get_vr_for_comparison (int i, value_range_equiv *tem)
|
||||
{
|
||||
/* Shallow-copy equiv bitmap. */
|
||||
const value_range_equiv *vr = get_value_range (ssa_name (i));
|
||||
const value_range_equiv *vr = get_value_range_equiv (ssa_name (i), m_stmt);
|
||||
|
||||
/* If name N_i does not have a valid range, use N_i as its own
|
||||
range. This allows us to compare against names that may
|
||||
@@ -2117,11 +2130,12 @@ vr_values::get_vr_for_comparison (int i, value_range_equiv *tem)
|
||||
*STRICT_OVERFLOW_P. */
|
||||
|
||||
tree
|
||||
vr_values::compare_name_with_value (enum tree_code comp, tree var, tree val,
|
||||
bool *strict_overflow_p, bool use_equiv_p)
|
||||
simplify_using_ranges::compare_name_with_value
|
||||
(enum tree_code comp, tree var, tree val,
|
||||
bool *strict_overflow_p, bool use_equiv_p)
|
||||
{
|
||||
/* Get the set of equivalences for VAR. */
|
||||
bitmap e = get_value_range (var)->equiv ();
|
||||
bitmap e = get_value_range_equiv (var, m_stmt)->equiv ();
|
||||
|
||||
/* Start at -1. Set it to 0 if we do a comparison without relying
|
||||
on overflow, or 1 if all comparisons rely on overflow. */
|
||||
@@ -2196,13 +2210,13 @@ vr_values::compare_name_with_value (enum tree_code comp, tree var, tree val,
|
||||
|
||||
|
||||
tree
|
||||
vr_values::compare_names (enum tree_code comp, tree n1, tree n2,
|
||||
bool *strict_overflow_p)
|
||||
simplify_using_ranges::compare_names (enum tree_code comp, tree n1, tree n2,
|
||||
bool *strict_overflow_p)
|
||||
{
|
||||
/* Compare the ranges of every name equivalent to N1 against the
|
||||
ranges of every name equivalent to N2. */
|
||||
bitmap e1 = get_value_range (n1)->equiv ();
|
||||
bitmap e2 = get_value_range (n2)->equiv ();
|
||||
bitmap e1 = get_value_range_equiv (n1, m_stmt)->equiv ();
|
||||
bitmap e2 = get_value_range_equiv (n2, m_stmt)->equiv ();
|
||||
|
||||
/* Use the fake bitmaps if e1 or e2 are not available. */
|
||||
static bitmap s_e1 = NULL, s_e2 = NULL;
|
||||
@@ -2310,12 +2324,14 @@ vr_values::compare_names (enum tree_code comp, tree n1, tree n2,
|
||||
optimizers. */
|
||||
|
||||
tree
|
||||
vr_values::vrp_evaluate_conditional_warnv_with_ops_using_ranges
|
||||
simplify_using_ranges::vrp_evaluate_conditional_warnv_with_ops_using_ranges
|
||||
(enum tree_code code, tree op0, tree op1, bool * strict_overflow_p)
|
||||
{
|
||||
const value_range_equiv *vr0, *vr1;
|
||||
vr0 = (TREE_CODE (op0) == SSA_NAME) ? get_value_range (op0) : NULL;
|
||||
vr1 = (TREE_CODE (op1) == SSA_NAME) ? get_value_range (op1) : NULL;
|
||||
vr0 = (TREE_CODE (op0) == SSA_NAME)
|
||||
? get_value_range_equiv (op0, m_stmt) : NULL;
|
||||
vr1 = (TREE_CODE (op1) == SSA_NAME)
|
||||
? get_value_range_equiv (op1, m_stmt) : NULL;
|
||||
|
||||
tree res = NULL_TREE;
|
||||
if (vr0 && vr1)
|
||||
@@ -2331,11 +2347,12 @@ vr_values::vrp_evaluate_conditional_warnv_with_ops_using_ranges
|
||||
/* Helper function for vrp_evaluate_conditional_warnv. */
|
||||
|
||||
tree
|
||||
vr_values::vrp_evaluate_conditional_warnv_with_ops (enum tree_code code,
|
||||
tree op0, tree op1,
|
||||
bool use_equiv_p,
|
||||
bool *strict_overflow_p,
|
||||
bool *only_ranges)
|
||||
simplify_using_ranges::vrp_evaluate_conditional_warnv_with_ops
|
||||
(enum tree_code code,
|
||||
tree op0, tree op1,
|
||||
bool use_equiv_p,
|
||||
bool *strict_overflow_p,
|
||||
bool *only_ranges)
|
||||
{
|
||||
tree ret;
|
||||
if (only_ranges)
|
||||
@@ -2392,7 +2409,7 @@ vr_values::vrp_evaluate_conditional_warnv_with_ops (enum tree_code code,
|
||||
}
|
||||
else
|
||||
gcc_unreachable ();
|
||||
const value_range_equiv *vr0 = get_value_range (op0);
|
||||
const value_range_equiv *vr0 = get_value_range_equiv (op0, m_stmt);
|
||||
/* If vro, the range for OP0 to pass the overflow test, has
|
||||
no intersection with *vr0, OP0's known range, then the
|
||||
overflow test can't pass, so return the node for false.
|
||||
@@ -2438,8 +2455,8 @@ vr_values::vrp_evaluate_conditional_warnv_with_ops (enum tree_code code,
|
||||
appropriate. */
|
||||
|
||||
tree
|
||||
vr_values::vrp_evaluate_conditional (tree_code code, tree op0,
|
||||
tree op1, gimple *stmt)
|
||||
simplify_using_ranges::vrp_evaluate_conditional (tree_code code, tree op0,
|
||||
tree op1, gimple *stmt)
|
||||
{
|
||||
bool sop;
|
||||
tree ret;
|
||||
@@ -2498,7 +2515,7 @@ vr_values::vrp_evaluate_conditional (tree_code code, tree op0,
|
||||
always fold regardless of the value of OP0. If -Wtype-limits
|
||||
was specified, emit a warning. */
|
||||
tree type = TREE_TYPE (op0);
|
||||
const value_range_equiv *vr0 = get_value_range (op0);
|
||||
const value_range_equiv *vr0 = get_value_range_equiv (op0, stmt);
|
||||
|
||||
if (vr0->kind () == VR_RANGE
|
||||
&& INTEGRAL_TYPE_P (type)
|
||||
@@ -2531,31 +2548,40 @@ vr_values::vrp_evaluate_conditional (tree_code code, tree op0,
|
||||
*TAKEN_EDGE_P. Otherwise, set *TAKEN_EDGE_P to NULL. */
|
||||
|
||||
void
|
||||
vr_values::vrp_visit_cond_stmt (gcond *stmt, edge *taken_edge_p)
|
||||
simplify_using_ranges::vrp_visit_cond_stmt (gcond *stmt, edge *taken_edge_p)
|
||||
{
|
||||
tree val;
|
||||
|
||||
*taken_edge_p = NULL;
|
||||
|
||||
dump_flags_t save_flags = dump_flags;
|
||||
dump_flags &= ~TDF_GORI;
|
||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
||||
{
|
||||
tree use;
|
||||
ssa_op_iter i;
|
||||
bool first = true;
|
||||
|
||||
fprintf (dump_file, "\nVisiting conditional with predicate: ");
|
||||
print_gimple_stmt (dump_file, stmt, 0);
|
||||
fprintf (dump_file, "\nWith known ranges\n");
|
||||
|
||||
FOR_EACH_SSA_TREE_OPERAND (use, stmt, i, SSA_OP_USE)
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
fprintf (dump_file, "With known ranges\n");
|
||||
first = false;
|
||||
}
|
||||
fprintf (dump_file, "\t");
|
||||
print_generic_expr (dump_file, use);
|
||||
fprintf (dump_file, ": ");
|
||||
dump_value_range (dump_file, vr_value[SSA_NAME_VERSION (use)]);
|
||||
dump_value_range (dump_file, get_value_range_equiv (use, stmt));
|
||||
}
|
||||
|
||||
fprintf (dump_file, "\n");
|
||||
if (!first)
|
||||
fprintf (dump_file, "\n");
|
||||
}
|
||||
dump_flags = save_flags;
|
||||
|
||||
/* Compute the value of the predicate COND by checking the known
|
||||
ranges of each of its operands.
|
||||
@@ -2624,7 +2650,7 @@ vr_values::vrp_visit_cond_stmt (gcond *stmt, edge *taken_edge_p)
|
||||
Returns true if the default label is not needed. */
|
||||
|
||||
static bool
|
||||
find_case_label_ranges (gswitch *stmt, const value_range_equiv *vr,
|
||||
find_case_label_ranges (gswitch *stmt, const irange *vr,
|
||||
size_t *min_idx1, size_t *max_idx1,
|
||||
size_t *min_idx2, size_t *max_idx2)
|
||||
{
|
||||
@@ -2634,7 +2660,7 @@ find_case_label_ranges (gswitch *stmt, const value_range_equiv *vr,
|
||||
tree case_low, case_high;
|
||||
tree min = vr->min (), max = vr->max ();
|
||||
|
||||
gcc_checking_assert (!vr->varying_p () && !vr->undefined_p ());
|
||||
gcc_assert (!vr->varying_p () && !vr->undefined_p ());
|
||||
|
||||
take_default = !find_case_label_range (stmt, min, max, &i, &j);
|
||||
|
||||
@@ -2808,7 +2834,7 @@ vr_values::extract_range_from_stmt (gimple *stmt, edge *taken_edge_p,
|
||||
else if (is_gimple_assign (stmt) || is_gimple_call (stmt))
|
||||
vrp_visit_assignment_or_call (stmt, output_p, vr);
|
||||
else if (gimple_code (stmt) == GIMPLE_COND)
|
||||
vrp_visit_cond_stmt (as_a <gcond *> (stmt), taken_edge_p);
|
||||
simplifier.vrp_visit_cond_stmt (as_a <gcond *> (stmt), taken_edge_p);
|
||||
else if (gimple_code (stmt) == GIMPLE_SWITCH)
|
||||
vrp_visit_switch_stmt (as_a <gswitch *> (stmt), taken_edge_p);
|
||||
}
|
||||
@@ -3029,8 +3055,9 @@ update_range:
|
||||
/* Simplify boolean operations if the source is known
|
||||
to be already a boolean. */
|
||||
bool
|
||||
vr_values::simplify_truth_ops_using_ranges (gimple_stmt_iterator *gsi,
|
||||
gimple *stmt)
|
||||
simplify_using_ranges::simplify_truth_ops_using_ranges
|
||||
(gimple_stmt_iterator *gsi,
|
||||
gimple *stmt)
|
||||
{
|
||||
enum tree_code rhs_code = gimple_assign_rhs_code (stmt);
|
||||
tree lhs, op0, op1;
|
||||
@@ -3040,11 +3067,11 @@ vr_values::simplify_truth_ops_using_ranges (gimple_stmt_iterator *gsi,
|
||||
gcc_assert (rhs_code == EQ_EXPR || rhs_code == NE_EXPR);
|
||||
|
||||
op0 = gimple_assign_rhs1 (stmt);
|
||||
if (!op_with_boolean_value_range_p (op0))
|
||||
if (!op_with_boolean_value_range_p (op0, stmt))
|
||||
return false;
|
||||
|
||||
op1 = gimple_assign_rhs2 (stmt);
|
||||
if (!op_with_boolean_value_range_p (op1))
|
||||
if (!op_with_boolean_value_range_p (op1, stmt))
|
||||
return false;
|
||||
|
||||
/* Reduce number of cases to handle to NE_EXPR. As there is no
|
||||
@@ -3106,8 +3133,9 @@ vr_values::simplify_truth_ops_using_ranges (gimple_stmt_iterator *gsi,
|
||||
modulo. */
|
||||
|
||||
bool
|
||||
vr_values::simplify_div_or_mod_using_ranges (gimple_stmt_iterator *gsi,
|
||||
gimple *stmt)
|
||||
simplify_using_ranges::simplify_div_or_mod_using_ranges
|
||||
(gimple_stmt_iterator *gsi,
|
||||
gimple *stmt)
|
||||
{
|
||||
enum tree_code rhs_code = gimple_assign_rhs_code (stmt);
|
||||
tree val = NULL;
|
||||
@@ -3115,7 +3143,11 @@ vr_values::simplify_div_or_mod_using_ranges (gimple_stmt_iterator *gsi,
|
||||
tree op1 = gimple_assign_rhs2 (stmt);
|
||||
tree op0min = NULL_TREE, op0max = NULL_TREE;
|
||||
tree op1min = op1;
|
||||
const value_range_equiv *vr = NULL;
|
||||
/* ?? All uses of value_range in the simplifier should be converted
|
||||
to widest_irange. However, in order to do this, there must be no
|
||||
VR_ANTI_RANGE uses downstream, as widest_irange has no concept of
|
||||
them except for symbolics. */
|
||||
value_range vr;
|
||||
|
||||
if (TREE_CODE (op0) == INTEGER_CST)
|
||||
{
|
||||
@@ -3124,20 +3156,21 @@ vr_values::simplify_div_or_mod_using_ranges (gimple_stmt_iterator *gsi,
|
||||
}
|
||||
else
|
||||
{
|
||||
vr = get_value_range (op0);
|
||||
if (range_int_cst_p (vr))
|
||||
gcc_assert (store->range_of_expr (vr, op0, stmt));
|
||||
if (range_int_cst_p (&vr))
|
||||
{
|
||||
op0min = vr->min ();
|
||||
op0max = vr->max ();
|
||||
op0min = vr.min ();
|
||||
op0max = vr.max ();
|
||||
}
|
||||
}
|
||||
|
||||
if (rhs_code == TRUNC_MOD_EXPR
|
||||
&& TREE_CODE (op1) == SSA_NAME)
|
||||
{
|
||||
const value_range_equiv *vr1 = get_value_range (op1);
|
||||
if (range_int_cst_p (vr1))
|
||||
op1min = vr1->min ();
|
||||
value_range vr1;
|
||||
gcc_assert (store->range_of_expr (vr1, op1, stmt));
|
||||
if (range_int_cst_p (&vr1))
|
||||
op1min = vr1.min ();
|
||||
}
|
||||
if (rhs_code == TRUNC_MOD_EXPR
|
||||
&& TREE_CODE (op1min) == INTEGER_CST
|
||||
@@ -3178,7 +3211,7 @@ vr_values::simplify_div_or_mod_using_ranges (gimple_stmt_iterator *gsi,
|
||||
{
|
||||
bool sop = false;
|
||||
|
||||
val = compare_range_with_value (GE_EXPR, vr, integer_zero_node, &sop);
|
||||
val = compare_range_with_value (GE_EXPR, &vr, integer_zero_node, &sop);
|
||||
|
||||
if (val
|
||||
&& sop
|
||||
@@ -3231,46 +3264,50 @@ vr_values::simplify_div_or_mod_using_ranges (gimple_stmt_iterator *gsi,
|
||||
disjoint. Return true if we do simplify. */
|
||||
|
||||
bool
|
||||
vr_values::simplify_min_or_max_using_ranges (gimple_stmt_iterator *gsi,
|
||||
gimple *stmt)
|
||||
simplify_using_ranges::simplify_min_or_max_using_ranges
|
||||
(gimple_stmt_iterator *gsi,
|
||||
gimple *stmt)
|
||||
{
|
||||
tree op0 = gimple_assign_rhs1 (stmt);
|
||||
if (!irange::supports_type_p (TREE_TYPE (op0)))
|
||||
return false;
|
||||
tree op1 = gimple_assign_rhs2 (stmt);
|
||||
bool sop = false;
|
||||
tree val;
|
||||
value_range vr0, vr1;
|
||||
if (TREE_CODE (op0) == SSA_NAME)
|
||||
gcc_assert (store->range_of_expr (vr0, op0, stmt));
|
||||
else if (TREE_CODE (op0) == INTEGER_CST)
|
||||
vr0.set (op0);
|
||||
else
|
||||
vr0.set_varying (TREE_TYPE (op0));
|
||||
if (TREE_CODE (op1) == SSA_NAME)
|
||||
gcc_assert (store->range_of_expr (vr1, op1, stmt));
|
||||
else if (TREE_CODE (op1) == INTEGER_CST)
|
||||
vr1.set (op1);
|
||||
else
|
||||
vr1.set_varying (TREE_TYPE (op1));
|
||||
|
||||
val = (vrp_evaluate_conditional_warnv_with_ops_using_ranges
|
||||
(LE_EXPR, op0, op1, &sop));
|
||||
if (!val)
|
||||
if (vr0.varying_p () || vr1.varying_p ())
|
||||
return false;
|
||||
|
||||
value_range tmp (vr0);
|
||||
tmp.intersect (vr1);
|
||||
if (!tmp.undefined_p ())
|
||||
return false;
|
||||
|
||||
value_range res;
|
||||
range_operator *handler = range_op_handler (gimple_assign_rhs_code (stmt),
|
||||
TREE_TYPE (op0));
|
||||
handler->fold_range (res, TREE_TYPE (op0), vr0, vr1);
|
||||
if (res == vr0)
|
||||
{
|
||||
sop = false;
|
||||
val = (vrp_evaluate_conditional_warnv_with_ops_using_ranges
|
||||
(LT_EXPR, op0, op1, &sop));
|
||||
}
|
||||
|
||||
if (val)
|
||||
{
|
||||
if (sop && issue_strict_overflow_warning (WARN_STRICT_OVERFLOW_MISC))
|
||||
{
|
||||
location_t location;
|
||||
|
||||
if (!gimple_has_location (stmt))
|
||||
location = input_location;
|
||||
else
|
||||
location = gimple_location (stmt);
|
||||
warning_at (location, OPT_Wstrict_overflow,
|
||||
"assuming signed overflow does not occur when "
|
||||
"simplifying %<min/max (X,Y)%> to %<X%> or %<Y%>");
|
||||
}
|
||||
|
||||
/* VAL == TRUE -> OP0 < or <= op1
|
||||
VAL == FALSE -> OP0 > or >= op1. */
|
||||
tree res = ((gimple_assign_rhs_code (stmt) == MAX_EXPR)
|
||||
== integer_zerop (val)) ? op0 : op1;
|
||||
gimple_assign_set_rhs_from_tree (gsi, res);
|
||||
gimple_assign_set_rhs_from_tree (gsi, op0);
|
||||
return true;
|
||||
}
|
||||
if (res == vr1)
|
||||
{
|
||||
gimple_assign_set_rhs_from_tree (gsi, op1);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -3279,23 +3316,25 @@ vr_values::simplify_min_or_max_using_ranges (gimple_stmt_iterator *gsi,
|
||||
ABS_EXPR into a NEGATE_EXPR. */
|
||||
|
||||
bool
|
||||
vr_values::simplify_abs_using_ranges (gimple_stmt_iterator *gsi, gimple *stmt)
|
||||
simplify_using_ranges::simplify_abs_using_ranges (gimple_stmt_iterator *gsi,
|
||||
gimple *stmt)
|
||||
{
|
||||
tree op = gimple_assign_rhs1 (stmt);
|
||||
const value_range_equiv *vr = get_value_range (op);
|
||||
value_range vr;
|
||||
gcc_assert (store->range_of_expr (vr, op, stmt));
|
||||
|
||||
if (vr)
|
||||
if (!vr.varying_p () && !vr.undefined_p ())
|
||||
{
|
||||
tree val = NULL;
|
||||
bool sop = false;
|
||||
|
||||
val = compare_range_with_value (LE_EXPR, vr, integer_zero_node, &sop);
|
||||
val = compare_range_with_value (LE_EXPR, &vr, integer_zero_node, &sop);
|
||||
if (!val)
|
||||
{
|
||||
/* The range is neither <= 0 nor > 0. Now see if it is
|
||||
either < 0 or >= 0. */
|
||||
sop = false;
|
||||
val = compare_range_with_value (LT_EXPR, vr, integer_zero_node,
|
||||
val = compare_range_with_value (LT_EXPR, &vr, integer_zero_node,
|
||||
&sop);
|
||||
}
|
||||
|
||||
@@ -3359,8 +3398,9 @@ vr_set_zero_nonzero_bits (const tree expr_type,
|
||||
operation is redundant. */
|
||||
|
||||
bool
|
||||
vr_values::simplify_bit_ops_using_ranges (gimple_stmt_iterator *gsi,
|
||||
gimple *stmt)
|
||||
simplify_using_ranges::simplify_bit_ops_using_ranges
|
||||
(gimple_stmt_iterator *gsi,
|
||||
gimple *stmt)
|
||||
{
|
||||
tree op0 = gimple_assign_rhs1 (stmt);
|
||||
tree op1 = gimple_assign_rhs2 (stmt);
|
||||
@@ -3371,14 +3411,14 @@ vr_values::simplify_bit_ops_using_ranges (gimple_stmt_iterator *gsi,
|
||||
wide_int mask;
|
||||
|
||||
if (TREE_CODE (op0) == SSA_NAME)
|
||||
vr0 = *(get_value_range (op0));
|
||||
gcc_assert (store->range_of_expr (vr0, op0, stmt));
|
||||
else if (is_gimple_min_invariant (op0))
|
||||
vr0.set (op0);
|
||||
else
|
||||
return false;
|
||||
|
||||
if (TREE_CODE (op1) == SSA_NAME)
|
||||
vr1 = *(get_value_range (op1));
|
||||
gcc_assert (store->range_of_expr (vr1, op1, stmt));
|
||||
else if (is_gimple_min_invariant (op1))
|
||||
vr1.set (op1);
|
||||
else
|
||||
@@ -3444,7 +3484,7 @@ vr_values::simplify_bit_ops_using_ranges (gimple_stmt_iterator *gsi,
|
||||
|
||||
static tree
|
||||
test_for_singularity (enum tree_code cond_code, tree op0,
|
||||
tree op1, const value_range_equiv *vr)
|
||||
tree op1, const irange *vr)
|
||||
{
|
||||
tree min = NULL;
|
||||
tree max = NULL;
|
||||
@@ -3502,7 +3542,7 @@ test_for_singularity (enum tree_code cond_code, tree op0,
|
||||
by PRECISION and UNSIGNED_P. */
|
||||
|
||||
static bool
|
||||
range_fits_type_p (const value_range_equiv *vr,
|
||||
range_fits_type_p (const value_range *vr,
|
||||
unsigned dest_precision, signop dest_sgn)
|
||||
{
|
||||
tree src_type;
|
||||
@@ -3554,7 +3594,7 @@ range_fits_type_p (const value_range_equiv *vr,
|
||||
conditional as such, and return TRUE. */
|
||||
|
||||
bool
|
||||
vr_values::fold_cond (gcond *cond)
|
||||
simplify_using_ranges::fold_cond (gcond *cond)
|
||||
{
|
||||
/* ?? vrp_folder::fold_predicate_in() is a superset of this. At
|
||||
some point we should merge all variants of this code. */
|
||||
@@ -3563,11 +3603,11 @@ vr_values::fold_cond (gcond *cond)
|
||||
if (taken_edge)
|
||||
{
|
||||
if (taken_edge->flags & EDGE_TRUE_VALUE)
|
||||
gimple_cond_make_true (cond);
|
||||
gimple_cond_make_true (cond);
|
||||
else if (taken_edge->flags & EDGE_FALSE_VALUE)
|
||||
gimple_cond_make_false (cond);
|
||||
gimple_cond_make_false (cond);
|
||||
else
|
||||
gcc_unreachable ();
|
||||
gcc_unreachable ();
|
||||
update_stmt (cond);
|
||||
return true;
|
||||
}
|
||||
@@ -3579,7 +3619,7 @@ vr_values::fold_cond (gcond *cond)
|
||||
the original conditional. */
|
||||
|
||||
bool
|
||||
vr_values::simplify_cond_using_ranges_1 (gcond *stmt)
|
||||
simplify_using_ranges::simplify_cond_using_ranges_1 (gcond *stmt)
|
||||
{
|
||||
tree op0 = gimple_cond_lhs (stmt);
|
||||
tree op1 = gimple_cond_rhs (stmt);
|
||||
@@ -3594,13 +3634,14 @@ vr_values::simplify_cond_using_ranges_1 (gcond *stmt)
|
||||
&& INTEGRAL_TYPE_P (TREE_TYPE (op0))
|
||||
&& is_gimple_min_invariant (op1))
|
||||
{
|
||||
const value_range_equiv *vr = get_value_range (op0);
|
||||
value_range vr;
|
||||
gcc_assert (store->range_of_expr (vr, op0, stmt));
|
||||
|
||||
/* If we have range information for OP0, then we might be
|
||||
able to simplify this conditional. */
|
||||
if (vr->kind () == VR_RANGE)
|
||||
if (vr.kind () == VR_RANGE)
|
||||
{
|
||||
tree new_tree = test_for_singularity (cond_code, op0, op1, vr);
|
||||
tree new_tree = test_for_singularity (cond_code, op0, op1, &vr);
|
||||
if (new_tree)
|
||||
{
|
||||
if (dump_file)
|
||||
@@ -3630,7 +3671,7 @@ vr_values::simplify_cond_using_ranges_1 (gcond *stmt)
|
||||
issues with inverting FP comparisons. */
|
||||
new_tree = test_for_singularity
|
||||
(invert_tree_comparison (cond_code, false),
|
||||
op0, op1, vr);
|
||||
op0, op1, &vr);
|
||||
if (new_tree)
|
||||
{
|
||||
if (dump_file)
|
||||
@@ -3667,7 +3708,7 @@ vr_values::simplify_cond_using_ranges_1 (gcond *stmt)
|
||||
subsequent passes. */
|
||||
|
||||
void
|
||||
vr_values::simplify_cond_using_ranges_2 (gcond *stmt)
|
||||
simplify_cond_using_ranges_2 (range_store *store, gcond *stmt)
|
||||
{
|
||||
tree op0 = gimple_cond_lhs (stmt);
|
||||
tree op1 = gimple_cond_rhs (stmt);
|
||||
@@ -3697,10 +3738,11 @@ vr_values::simplify_cond_using_ranges_2 (gcond *stmt)
|
||||
&& !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (innerop)
|
||||
&& desired_pro_or_demotion_p (TREE_TYPE (innerop), TREE_TYPE (op0)))
|
||||
{
|
||||
const value_range_equiv *vr = get_value_range (innerop);
|
||||
value_range vr;
|
||||
gcc_assert (store->range_of_expr (vr, innerop, stmt));
|
||||
|
||||
if (range_int_cst_p (vr)
|
||||
&& range_fits_type_p (vr,
|
||||
if (range_int_cst_p (&vr)
|
||||
&& range_fits_type_p (&vr,
|
||||
TYPE_PRECISION (TREE_TYPE (op0)),
|
||||
TYPE_SIGN (TREE_TYPE (op0)))
|
||||
&& int_fits_type_p (op1, TREE_TYPE (innerop)))
|
||||
@@ -3724,10 +3766,10 @@ vr_values::simplify_cond_using_ranges_2 (gcond *stmt)
|
||||
argument. */
|
||||
|
||||
bool
|
||||
vr_values::simplify_switch_using_ranges (gswitch *stmt)
|
||||
simplify_using_ranges::simplify_switch_using_ranges (gswitch *stmt)
|
||||
{
|
||||
tree op = gimple_switch_index (stmt);
|
||||
const value_range_equiv *vr = NULL;
|
||||
value_range vr;
|
||||
bool take_default;
|
||||
edge e;
|
||||
edge_iterator ei;
|
||||
@@ -3738,16 +3780,16 @@ vr_values::simplify_switch_using_ranges (gswitch *stmt)
|
||||
|
||||
if (TREE_CODE (op) == SSA_NAME)
|
||||
{
|
||||
vr = get_value_range (op);
|
||||
gcc_assert (store->range_of_expr (vr, op, stmt));
|
||||
|
||||
/* We can only handle integer ranges. */
|
||||
if (vr->varying_p ()
|
||||
|| vr->undefined_p ()
|
||||
|| vr->symbolic_p ())
|
||||
if (vr.varying_p ()
|
||||
|| vr.undefined_p ()
|
||||
|| vr.symbolic_p ())
|
||||
return false;
|
||||
|
||||
/* Find case label for min/max of the value range. */
|
||||
take_default = !find_case_label_ranges (stmt, vr, &i, &j, &k, &l);
|
||||
take_default = !find_case_label_ranges (stmt, &vr, &i, &j, &k, &l);
|
||||
}
|
||||
else if (TREE_CODE (op) == INTEGER_CST)
|
||||
{
|
||||
@@ -3770,8 +3812,8 @@ vr_values::simplify_switch_using_ranges (gswitch *stmt)
|
||||
/* We can truncate the case label ranges that partially overlap with OP's
|
||||
value range. */
|
||||
size_t min_idx = 1, max_idx = 0;
|
||||
if (vr != NULL)
|
||||
find_case_label_range (stmt, vr->min (), vr->max (), &min_idx, &max_idx);
|
||||
if (!vr.varying_p () && !vr.undefined_p ())
|
||||
find_case_label_range (stmt, vr.min (), vr.max (), &min_idx, &max_idx);
|
||||
if (min_idx <= max_idx)
|
||||
{
|
||||
tree min_label = gimple_switch_label (stmt, min_idx);
|
||||
@@ -3779,10 +3821,10 @@ vr_values::simplify_switch_using_ranges (gswitch *stmt)
|
||||
|
||||
/* Avoid changing the type of the case labels when truncating. */
|
||||
tree case_label_type = TREE_TYPE (CASE_LOW (min_label));
|
||||
tree vr_min = fold_convert (case_label_type, vr->min ());
|
||||
tree vr_max = fold_convert (case_label_type, vr->max ());
|
||||
tree vr_min = fold_convert (case_label_type, vr.min ());
|
||||
tree vr_max = fold_convert (case_label_type, vr.max ());
|
||||
|
||||
if (vr->kind () == VR_RANGE)
|
||||
if (vr.kind () == VR_RANGE)
|
||||
{
|
||||
/* If OP's value range is [2,8] and the low label range is
|
||||
0 ... 3, truncate the label's range to 2 .. 3. */
|
||||
@@ -3798,7 +3840,7 @@ vr_values::simplify_switch_using_ranges (gswitch *stmt)
|
||||
&& tree_int_cst_compare (CASE_HIGH (max_label), vr_max) > 0)
|
||||
CASE_HIGH (max_label) = vr_max;
|
||||
}
|
||||
else if (vr->kind () == VR_ANTI_RANGE)
|
||||
else if (vr.kind () == VR_ANTI_RANGE)
|
||||
{
|
||||
tree one_cst = build_one_cst (case_label_type);
|
||||
|
||||
@@ -3905,7 +3947,7 @@ vr_values::simplify_switch_using_ranges (gswitch *stmt)
|
||||
}
|
||||
|
||||
void
|
||||
vr_values::cleanup_edges_and_switches (void)
|
||||
simplify_using_ranges::cleanup_edges_and_switches (void)
|
||||
{
|
||||
int i;
|
||||
edge e;
|
||||
@@ -3967,6 +4009,12 @@ simplify_conversion_using_ranges (gimple_stmt_iterator *gsi, gimple *stmt)
|
||||
|| SSA_NAME_OCCURS_IN_ABNORMAL_PHI (innerop))
|
||||
return false;
|
||||
|
||||
// FIXME: This conversion has nothing to do with ranges, and the way
|
||||
// it uses global ranges versus local ranges is interfering with our
|
||||
// ability to diagnose differences between evrp and rvrp1.
|
||||
if (flag_evrp_traps)
|
||||
return false;
|
||||
|
||||
/* Get the value-range of the inner operand. Use get_range_info in
|
||||
case innerop was created during substitute-and-fold. */
|
||||
wide_int imin, imax;
|
||||
@@ -4023,11 +4071,13 @@ simplify_conversion_using_ranges (gimple_stmt_iterator *gsi, gimple *stmt)
|
||||
/* Simplify a conversion from integral SSA name to float in STMT. */
|
||||
|
||||
bool
|
||||
vr_values::simplify_float_conversion_using_ranges (gimple_stmt_iterator *gsi,
|
||||
gimple *stmt)
|
||||
simplify_using_ranges::simplify_float_conversion_using_ranges
|
||||
(gimple_stmt_iterator *gsi,
|
||||
gimple *stmt)
|
||||
{
|
||||
tree rhs1 = gimple_assign_rhs1 (stmt);
|
||||
const value_range_equiv *vr = get_value_range (rhs1);
|
||||
value_range vr;
|
||||
gcc_assert (store->range_of_expr (vr, rhs1, stmt));
|
||||
scalar_float_mode fltmode
|
||||
= SCALAR_FLOAT_TYPE_MODE (TREE_TYPE (gimple_assign_lhs (stmt)));
|
||||
scalar_int_mode mode;
|
||||
@@ -4035,14 +4085,14 @@ vr_values::simplify_float_conversion_using_ranges (gimple_stmt_iterator *gsi,
|
||||
gassign *conv;
|
||||
|
||||
/* We can only handle constant ranges. */
|
||||
if (!range_int_cst_p (vr))
|
||||
if (!range_int_cst_p (&vr))
|
||||
return false;
|
||||
|
||||
/* First check if we can use a signed type in place of an unsigned. */
|
||||
scalar_int_mode rhs_mode = SCALAR_INT_TYPE_MODE (TREE_TYPE (rhs1));
|
||||
if (TYPE_UNSIGNED (TREE_TYPE (rhs1))
|
||||
&& can_float_p (fltmode, rhs_mode, 0) != CODE_FOR_nothing
|
||||
&& range_fits_type_p (vr, TYPE_PRECISION (TREE_TYPE (rhs1)), SIGNED))
|
||||
&& range_fits_type_p (&vr, TYPE_PRECISION (TREE_TYPE (rhs1)), SIGNED))
|
||||
mode = rhs_mode;
|
||||
/* If we can do the conversion in the current input mode do nothing. */
|
||||
else if (can_float_p (fltmode, rhs_mode,
|
||||
@@ -4059,7 +4109,7 @@ vr_values::simplify_float_conversion_using_ranges (gimple_stmt_iterator *gsi,
|
||||
or if the value-range does not fit in the signed type
|
||||
try with a wider mode. */
|
||||
if (can_float_p (fltmode, mode, 0) != CODE_FOR_nothing
|
||||
&& range_fits_type_p (vr, GET_MODE_PRECISION (mode), SIGNED))
|
||||
&& range_fits_type_p (&vr, GET_MODE_PRECISION (mode), SIGNED))
|
||||
break;
|
||||
|
||||
/* But do not widen the input. Instead leave that to the
|
||||
@@ -4085,8 +4135,9 @@ vr_values::simplify_float_conversion_using_ranges (gimple_stmt_iterator *gsi,
|
||||
/* Simplify an internal fn call using ranges if possible. */
|
||||
|
||||
bool
|
||||
vr_values::simplify_internal_call_using_ranges (gimple_stmt_iterator *gsi,
|
||||
gimple *stmt)
|
||||
simplify_using_ranges::simplify_internal_call_using_ranges
|
||||
(gimple_stmt_iterator *gsi,
|
||||
gimple *stmt)
|
||||
{
|
||||
enum tree_code subcode;
|
||||
bool is_ubsan = false;
|
||||
@@ -4131,7 +4182,8 @@ vr_values::simplify_internal_call_using_ranges (gimple_stmt_iterator *gsi,
|
||||
return false;
|
||||
else
|
||||
type = TREE_TYPE (TREE_TYPE (gimple_call_lhs (stmt)));
|
||||
if (!check_for_binary_op_overflow (subcode, type, op0, op1, &ovf)
|
||||
if (!check_for_binary_op_overflow (store, stmt, subcode, type, op0, op1,
|
||||
&ovf)
|
||||
|| (is_ubsan && ovf))
|
||||
return false;
|
||||
|
||||
@@ -4188,29 +4240,30 @@ vr_values::simplify_internal_call_using_ranges (gimple_stmt_iterator *gsi,
|
||||
two-values when it is true. Return false otherwise. */
|
||||
|
||||
bool
|
||||
vr_values::two_valued_val_range_p (tree var, tree *a, tree *b)
|
||||
simplify_using_ranges::two_valued_val_range_p (tree var, tree *a, tree *b)
|
||||
{
|
||||
const value_range_equiv *vr = get_value_range (var);
|
||||
if (vr->varying_p ()
|
||||
|| vr->undefined_p ()
|
||||
|| TREE_CODE (vr->min ()) != INTEGER_CST
|
||||
|| TREE_CODE (vr->max ()) != INTEGER_CST)
|
||||
value_range vr;
|
||||
gcc_assert (store->range_of_expr (vr, var, m_stmt));
|
||||
if (vr.varying_p ()
|
||||
|| vr.undefined_p ()
|
||||
|| TREE_CODE (vr.min ()) != INTEGER_CST
|
||||
|| TREE_CODE (vr.max ()) != INTEGER_CST)
|
||||
return false;
|
||||
|
||||
if (vr->kind () == VR_RANGE
|
||||
&& wi::to_wide (vr->max ()) - wi::to_wide (vr->min ()) == 1)
|
||||
if (vr.kind () == VR_RANGE
|
||||
&& wi::to_wide (vr.max ()) - wi::to_wide (vr.min ()) == 1)
|
||||
{
|
||||
*a = vr->min ();
|
||||
*b = vr->max ();
|
||||
*a = vr.min ();
|
||||
*b = vr.max ();
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ~[TYPE_MIN + 1, TYPE_MAX - 1] */
|
||||
if (vr->kind () == VR_ANTI_RANGE
|
||||
&& (wi::to_wide (vr->min ())
|
||||
if (vr.kind () == VR_ANTI_RANGE
|
||||
&& (wi::to_wide (vr.min ())
|
||||
- wi::to_wide (vrp_val_min (TREE_TYPE (var)))) == 1
|
||||
&& (wi::to_wide (vrp_val_max (TREE_TYPE (var)))
|
||||
- wi::to_wide (vr->max ())) == 1)
|
||||
- wi::to_wide (vr.max ())) == 1)
|
||||
{
|
||||
*a = vrp_val_min (TREE_TYPE (var));
|
||||
*b = vrp_val_max (TREE_TYPE (var));
|
||||
@@ -4220,12 +4273,25 @@ vr_values::two_valued_val_range_p (tree var, tree *a, tree *b)
|
||||
return false;
|
||||
}
|
||||
|
||||
simplify_using_ranges::simplify_using_ranges (range_store *store)
|
||||
: store (store)
|
||||
{
|
||||
to_remove_edges = vNULL;
|
||||
to_update_switch_stmts = vNULL;
|
||||
}
|
||||
|
||||
simplify_using_ranges::~simplify_using_ranges ()
|
||||
{
|
||||
cleanup_edges_and_switches ();
|
||||
}
|
||||
|
||||
/* Simplify STMT using ranges if possible. */
|
||||
|
||||
bool
|
||||
vr_values::simplify_stmt_using_ranges (gimple_stmt_iterator *gsi)
|
||||
simplify_using_ranges::simplify (gimple_stmt_iterator *gsi)
|
||||
{
|
||||
gimple *stmt = gsi_stmt (*gsi);
|
||||
m_stmt = stmt;
|
||||
if (is_gimple_assign (stmt))
|
||||
{
|
||||
enum tree_code rhs_code = gimple_assign_rhs_code (stmt);
|
||||
|
||||
126
gcc/vr-values.h
126
gcc/vr-values.h
@@ -21,6 +21,75 @@ along with GCC; see the file COPYING3. If not see
|
||||
#define GCC_VR_VALUES_H
|
||||
|
||||
#include "value-range-equiv.h"
|
||||
#include "gimple-range.h"
|
||||
|
||||
// Generic object to return a range for an SSA.
|
||||
class range_store
|
||||
{
|
||||
public:
|
||||
virtual bool range_of_expr (irange &r, tree expr, gimple *stmt = NULL) = 0;
|
||||
virtual const class value_range_equiv *get_value_range (const_tree expr,
|
||||
gimple *stmt = NULL) = 0;
|
||||
};
|
||||
|
||||
class simplify_using_ranges
|
||||
{
|
||||
public:
|
||||
simplify_using_ranges (range_store *);
|
||||
~simplify_using_ranges ();
|
||||
bool simplify (gimple_stmt_iterator *);
|
||||
|
||||
// ?? These should be cleaned, merged, and made private.
|
||||
tree vrp_evaluate_conditional (tree_code, tree, tree, gimple *);
|
||||
void vrp_visit_cond_stmt (gcond *, edge *);
|
||||
tree vrp_evaluate_conditional_warnv_with_ops (enum tree_code,
|
||||
tree, tree, bool,
|
||||
bool *, bool *);
|
||||
|
||||
private:
|
||||
// This is named differently than get_value_range to make it obvious
|
||||
// that it returns an equivalence. Only use this for calculations
|
||||
// that may take equivalences, otherwise use range_of_expr.
|
||||
const value_range_equiv *get_value_range_equiv (const_tree op,
|
||||
gimple *stmt = NULL)
|
||||
{ return store->get_value_range (op, stmt); }
|
||||
bool simplify_truth_ops_using_ranges (gimple_stmt_iterator *, gimple *);
|
||||
bool simplify_div_or_mod_using_ranges (gimple_stmt_iterator *, gimple *);
|
||||
bool simplify_abs_using_ranges (gimple_stmt_iterator *, gimple *);
|
||||
bool simplify_bit_ops_using_ranges (gimple_stmt_iterator *, gimple *);
|
||||
bool simplify_min_or_max_using_ranges (gimple_stmt_iterator *, gimple *);
|
||||
bool simplify_cond_using_ranges_1 (gcond *);
|
||||
bool fold_cond (gcond *);
|
||||
bool simplify_switch_using_ranges (gswitch *);
|
||||
bool simplify_float_conversion_using_ranges (gimple_stmt_iterator *,
|
||||
gimple *);
|
||||
bool simplify_internal_call_using_ranges (gimple_stmt_iterator *, gimple *);
|
||||
|
||||
bool two_valued_val_range_p (tree, tree *, tree *);
|
||||
bool op_with_boolean_value_range_p (tree, gimple *);
|
||||
tree compare_name_with_value (enum tree_code, tree, tree, bool *, bool);
|
||||
tree compare_names (enum tree_code, tree, tree, bool *);
|
||||
const value_range_equiv *get_vr_for_comparison (int, value_range_equiv *);
|
||||
tree vrp_evaluate_conditional_warnv_with_ops_using_ranges (enum tree_code,
|
||||
tree, tree,
|
||||
bool *);
|
||||
void cleanup_edges_and_switches (void);
|
||||
|
||||
/* Vectors of edges that need removing and switch statements that
|
||||
need updating. It is expected that a pass using the simplification
|
||||
routines will, at the end of the pass, clean up the edges and
|
||||
switch statements. The class dtor will try to detect cases
|
||||
that do not follow that expectation. */
|
||||
struct switch_update {
|
||||
gswitch *stmt;
|
||||
tree vec;
|
||||
};
|
||||
|
||||
vec<edge> to_remove_edges;
|
||||
vec<switch_update> to_update_switch_stmts;
|
||||
gimple *m_stmt;
|
||||
range_store *store;
|
||||
};
|
||||
|
||||
/* The VR_VALUES class holds the current view of range information
|
||||
for all the SSA_NAMEs in the IL.
|
||||
@@ -36,15 +105,16 @@ along with GCC; see the file COPYING3. If not see
|
||||
gets attached to an SSA_NAME. It's unclear how useful that global
|
||||
information will be in a world where we can compute context sensitive
|
||||
range information fast or perform on-demand queries. */
|
||||
class vr_values
|
||||
class vr_values : public range_store
|
||||
{
|
||||
public:
|
||||
vr_values (void);
|
||||
~vr_values (void);
|
||||
virtual ~vr_values (void);
|
||||
|
||||
const value_range_equiv *get_value_range (const_tree);
|
||||
const value_range_equiv *get_value_range (const_tree, gimple *stmt = NULL);
|
||||
void set_vr_value (tree, value_range_equiv *);
|
||||
value_range_equiv *swap_vr_value (tree, value_range_equiv *);
|
||||
bool range_of_expr (irange &r, tree expr, gimple *stmt = NULL);
|
||||
|
||||
void set_def_to_varying (const_tree);
|
||||
void set_defs_to_varying (gimple *);
|
||||
@@ -52,7 +122,6 @@ class vr_values
|
||||
tree op_with_constant_singleton_value_range (tree);
|
||||
void adjust_range_with_scev (value_range_equiv *, class loop *,
|
||||
gimple *, tree);
|
||||
tree vrp_evaluate_conditional (tree_code, tree, tree, gimple *);
|
||||
void dump_all_value_ranges (FILE *);
|
||||
|
||||
void extract_range_for_var_from_comparison_expr (tree, enum tree_code,
|
||||
@@ -62,11 +131,6 @@ class vr_values
|
||||
void extract_range_basic (value_range_equiv *, gimple *);
|
||||
void extract_range_from_stmt (gimple *, edge *, tree *, value_range_equiv *);
|
||||
|
||||
void vrp_visit_cond_stmt (gcond *, edge *);
|
||||
|
||||
void simplify_cond_using_ranges_2 (gcond *);
|
||||
bool simplify_stmt_using_ranges (gimple_stmt_iterator *);
|
||||
|
||||
/* Indicate that propagation through the lattice is complete. */
|
||||
void set_lattice_propagation_complete (void) { values_propagated = true; }
|
||||
|
||||
@@ -76,24 +140,9 @@ class vr_values
|
||||
void free_value_range (value_range_equiv *vr)
|
||||
{ vrp_value_range_pool.remove (vr); }
|
||||
|
||||
/* */
|
||||
void cleanup_edges_and_switches (void);
|
||||
|
||||
private:
|
||||
value_range_equiv *get_lattice_entry (const_tree);
|
||||
bool vrp_stmt_computes_nonzero (gimple *);
|
||||
bool op_with_boolean_value_range_p (tree);
|
||||
bool check_for_binary_op_overflow (enum tree_code, tree, tree, tree, bool *);
|
||||
const value_range_equiv *get_vr_for_comparison (int, value_range_equiv *);
|
||||
tree compare_name_with_value (enum tree_code, tree, tree, bool *, bool);
|
||||
tree compare_names (enum tree_code, tree, tree, bool *);
|
||||
bool two_valued_val_range_p (tree, tree *, tree *);
|
||||
tree vrp_evaluate_conditional_warnv_with_ops_using_ranges (enum tree_code,
|
||||
tree, tree,
|
||||
bool *);
|
||||
tree vrp_evaluate_conditional_warnv_with_ops (enum tree_code,
|
||||
tree, tree, bool,
|
||||
bool *, bool *);
|
||||
void extract_range_from_assignment (value_range_equiv *, gassign *);
|
||||
void extract_range_from_assert (value_range_equiv *, tree);
|
||||
void extract_range_from_ssa_name (value_range_equiv *, tree);
|
||||
@@ -106,17 +155,6 @@ class vr_values
|
||||
tree, tree, tree);
|
||||
void vrp_visit_assignment_or_call (gimple*, tree *, value_range_equiv *);
|
||||
void vrp_visit_switch_stmt (gswitch *, edge *);
|
||||
bool simplify_truth_ops_using_ranges (gimple_stmt_iterator *, gimple *);
|
||||
bool simplify_div_or_mod_using_ranges (gimple_stmt_iterator *, gimple *);
|
||||
bool simplify_abs_using_ranges (gimple_stmt_iterator *, gimple *);
|
||||
bool simplify_bit_ops_using_ranges (gimple_stmt_iterator *, gimple *);
|
||||
bool simplify_min_or_max_using_ranges (gimple_stmt_iterator *, gimple *);
|
||||
bool simplify_cond_using_ranges_1 (gcond *);
|
||||
bool fold_cond (gcond *);
|
||||
bool simplify_switch_using_ranges (gswitch *);
|
||||
bool simplify_float_conversion_using_ranges (gimple_stmt_iterator *,
|
||||
gimple *);
|
||||
bool simplify_internal_call_using_ranges (gimple_stmt_iterator *, gimple *);
|
||||
|
||||
/* Allocation pools for value_range objects. */
|
||||
object_allocator<value_range_equiv> vrp_value_range_pool;
|
||||
@@ -136,20 +174,12 @@ class vr_values
|
||||
number of executable edges we saw the last time we visited the
|
||||
node. */
|
||||
int *vr_phi_edge_counts;
|
||||
|
||||
/* Vectors of edges that need removing and switch statements that
|
||||
need updating. It is expected that a pass using the simplification
|
||||
routines will, at the end of the pass, clean up the edges and
|
||||
switch statements. The class dtor will try to detect cases
|
||||
that do not follow that expectation. */
|
||||
struct switch_update {
|
||||
gswitch *stmt;
|
||||
tree vec;
|
||||
};
|
||||
|
||||
vec<edge> to_remove_edges;
|
||||
vec<switch_update> to_update_switch_stmts;
|
||||
simplify_using_ranges simplifier;
|
||||
};
|
||||
|
||||
extern tree get_output_for_vrp (gimple *);
|
||||
|
||||
// FIXME: Move this to tree-vrp.c.
|
||||
void simplify_cond_using_ranges_2 (range_store *, gcond *);
|
||||
|
||||
#endif /* GCC_VR_VALUES_H */
|
||||
|
||||
Reference in New Issue
Block a user