Compare commits

...

203 Commits

Author SHA1 Message Date
Andrew MacLeod
f69ab586f6 ranger restructuring 2020-06-26 10:18:52 -04:00
Aldy Hernandez
f67c1bddaf Minor cleanups to range-op. 2020-06-19 15:26:01 +02:00
Aldy Hernandez
7cefb069fa Remove vrange as well as irange virtuals. 2020-06-19 15:14:08 +02:00
Aldy Hernandez
6472945db3 Minor cleanups to minimize differences with upstream. 2020-06-18 14:14:04 +02:00
Aldy Hernandez
397aece267 Remove unused gori_computable_p field in assert_info. 2020-06-17 20:17:09 +02:00
Aldy Hernandez
b9e67f2840 Merge from trunk at:
commit 56638b9b18
	Author: GCC Administrator <gccadmin@gcc.gnu.org>
	Date:   Wed Jun 17 00:16:36 2020 +0000

	    Daily bump.
2020-06-17 07:50:57 -04:00
Aldy Hernandez
1957047ed1 Fix bug where evrp was trapping on identical original and modified statements. 2020-06-11 08:43:02 +02:00
Aldy Hernandez
71920b87f7 Adjust evrp trapping code to display removal of PHIs. 2020-06-10 18:13:03 +02:00
Aldy Hernandez
e09c42b8a4 Revamp frvrp*changes flags.
Flags are now:

	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.

There is also another flag, but it is for testsuite use only, to turn
on/off the RVRP changes for all passes:

	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.
2020-06-10 14:44:48 +02:00
Aldy Hernandez
52e2fc662a Tidy up gimple_state class.
Previous method names were confusing.
2020-06-10 14:13:41 +02:00
Aldy Hernandez
9c7dce1bc5 Move evrp trapping conditional to its own function. 2020-06-10 13:18:11 +02:00
Aldy Hernandez
784003f0d5 Remove unused tmp_stats_pre_fold_bb_end. 2020-06-10 13:17:47 +02:00
Aldy Hernandez
708b56f90b Add more unimplemented operands in enhanced_operand_compare::operand_equal_p. 2020-06-10 10:59:46 +02:00
Aldy Hernandez
4efacd5dbb Fix off-by-one allocation bug in get_fresh_function_name. 2020-06-10 10:58:53 +02:00
Aldy Hernandez
49fac79438 Remove loop_ranger::range_of_phi as loop_ranger::range_of_stmt handles things. 2020-06-09 22:21:51 +02:00
Aldy Hernandez
2f28c16f0d Implement loop_ranger::range_of_stmt to use SCEV when evaluating PHI's. 2020-06-09 20:18:39 +02:00
Aldy Hernandez
df663310ee Fix operator_rshift::op1_range to work better with signed types.
We do this by discarding impossible ranges from the incoming LHS.
2020-06-09 07:49:32 +02:00
Aldy Hernandez
a5b9a237d6 Adjust range_of_range_op to handle non-trivial assignments involving an ADDR_EXPR. 2020-06-04 14:33:46 +02:00
Andrew MacLeod
c6e8b9bb06 use a bitmap obstack in the gori object instead of malloc 2020-06-03 10:56:13 -04:00
Aldy Hernandez
5a8c373b79 Do not call SCEV in loop_ranger::range_of_ssa_name.
This was huge hammer that was calling SCEV for every SSA, and it causes
Fortran timeouts because SCEV went into an infinite loop.
2020-06-03 13:29:35 +02:00
Aldy Hernandez
77f9508510 Rewrite operator_bitwise_and::remove_impossible_ranges using wide_ints.
This fixes subtle incompatibilities between int, HOST_WIDE_INT, trees,
and wide_ints that are causing endless grief.
2020-06-02 14:34:50 +02:00
Aldy Hernandez
d310e3372a Call range_of_stmt from rvrp to fold conditionals. 2020-06-02 14:02:35 +02:00
Aldy Hernandez
f5372d34d4 Fix operator_bitwise_and::remove_impossible_ranges so that masks wider than 32-bit work. 2020-06-02 14:02:35 +02:00
Aldy Hernandez
455c0b2c72 Test that [10,10][20,20] does NOT contain 15.
The problem was that value_inside_range was squishing a range into
a int_range<1>.  The inverse of this range no longer contained
what was conservatively needed.

The fix was to use widest_irange instead.
2020-06-02 14:02:29 +02:00
Aldy Hernandez
7b61d7a733 Fix undefined behavior in pr33922.c.
It was causing evrp to perform an undefined transformation
that rvrp was not doing and causing a trap.
2020-05-15 17:18:41 +02:00
Aldy Hernandez
e80f12ca10 Adjusts tests for rvrp execution.
The following are the known regressions:

> FAIL: gfortran.dg/integer_exponentiation_2.f90   -O2  (test for excess errors)
> FAIL: gfortran.dg/integer_exponentiation_2.f90   -O3 -fomit-frame-pointer -funroll-loops -fpeel
-loops -ftracer -finline-functions  (test for excess errors)
> FAIL: gfortran.dg/integer_exponentiation_2.f90   -O3 -g  (test for excess errors)
> FAIL: gfortran.dg/pr41043.f90   -O  (test for excess errors)

Fortran timeouts during compilation.  Will analyze next week.

> FAIL: gcc.dg/tree-ssa/pr88367.c scan-tree-dump-times optimized "bar \\(\\);" 2

-fno-delete-null-pointer-checks problem.  Discussing with Andrew.
2020-05-15 13:47:36 +02:00
Aldy Hernandez
478046cfa0 Remove gori_computable.
Now that ranger VRP is running, there is no need for this.
2020-05-15 11:46:45 +02:00
Aldy Hernandez
9e7dee0822 Enabled evrp trapping when IL changes but only iff -frvrp1-changes is set.
Also, implement global -frvrp-changes that overrides the individual pass settings.
2020-05-15 09:28:36 +02:00
Aldy Hernandez
ec5047297e Remove vr_values_tester.
It is no longer needed as we are running rvrp[12] and verifying usage
the trap code.
2020-05-15 08:50:18 +02:00
Aldy Hernandez
f12f352350 Add loop_ranger::range_of_ssa_name that calls SCEV. 2020-05-15 08:50:17 +02:00
Aldy Hernandez
8018a7eae5 Guard indent calculations in trace_ranger by dumping().
This keeps the indentation from going haywire when GORI dumping
is turned on and off during a compilation unit.
2020-05-15 08:50:17 +02:00
Aldy Hernandez
f21c760ce9 Move all branch local machinery into their own files (misc.*).
Move all the classes and support routines that are not meant to
be upstreamed, into their own files.

Also, add the initial cut of the classes needed to compare and
trap when IL changes are noticed in evrp.  This is disabled for now.
2020-05-15 08:50:17 +02:00
Aldy Hernandez
d1b1758148 Turn off simplify_conversion_using_ranges when rvrp1 IL changes are enabled.
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.
2020-05-15 08:50:17 +02:00
Aldy Hernandez
9fde43096e Turn off GORI/ranger dumps while dumping known ranges.
Since the ranger is on-demand, dumping the known range for each SSA use
causes us to calculate the ranges ahead of time, and confuse the listing.
For now, turn it off, so the range calculation isn't displayed.
2020-05-15 08:50:17 +02:00
Aldy Hernandez
0a16792f35 Add context stmt for simplify_using_ranges.
This gives better ranges for the simplifier class since it's using the
context in which the statement appears.
2020-05-15 08:50:17 +02:00
Aldy Hernandez
a80468e8ee Return a better range for lshift::op1_range if LHS does not contain a 0. 2020-05-15 08:50:16 +02:00
Aldy Hernandez
304543d8ff Run copy propagation before evrp. 2020-05-15 08:50:12 +02:00
Aldy Hernandez
af1295ebe1 Adjust gimple_range_adjustment so it works for imagpart and pointer_diff. 2020-05-14 19:37:12 +02:00
Aldy Hernandez
07a3e49243 Fix off-by-one error in popcount folding. 2020-05-14 19:37:12 +02:00
Aldy Hernandez
b454a26fc2 If argument of __builtin_constant_p resolves to a constant, return range of 1. 2020-05-14 19:09:26 +02:00
Aldy Hernandez
d7dc8055ac Handle -fstrict-enum casts.
This fixes:

< FAIL: g++.dg/pr84933.C  -std=gnu++14 (internal compiler error)
< FAIL: g++.dg/pr84933.C  -std=gnu++14 (test for excess errors)
< FAIL: g++.dg/pr84933.C  -std=gnu++17 (internal compiler error)
< FAIL: g++.dg/pr84933.C  -std=gnu++17 (test for excess errors)
< FAIL: g++.dg/pr84933.C  -std=gnu++2a (internal compiler error)
< FAIL: g++.dg/pr84933.C  -std=gnu++2a (test for excess errors)
< FAIL: g++.dg/pr84933.C  -std=gnu++98 (internal compiler error)
< FAIL: g++.dg/pr84933.C  -std=gnu++98 (test for excess errors)
2020-05-04 14:26:59 +02:00
Aldy Hernandez
eb227c9098 Clean up operator_cast. 2020-05-04 10:01:42 +02:00
Aldy Hernandez
671279d304 Disable -Wformat and -Wimplicit-fallthrough for stage1 builds. 2020-04-30 09:32:40 +02:00
Aldy Hernandez
638cee48e6 Query SSA names even for -fno-rvrp-changes.
This fixes the issue with RVRP1 running but not producing tracing dumps.
2020-04-30 09:32:24 +02:00
Aldy Hernandez
2453788a87 Rename substitute_and_fold_engine::post_fold_stmt to post_new_stmt. 2020-04-30 08:35:16 +02:00
Aldy Hernandez
edaa86722d Rip out all gori and ranger comparison code from EVPR.
Leave the vr_comparison class in for future comparison.
2020-04-29 18:57:17 +02:00
Aldy Hernandez
79b6818236 Return varying when unknown in rvrp_ranger.
All known regressions are because rvrp gets ahead of other passes, with the
exception of pr88217, which is the -fstrict-enum problem.

> FAIL: gcc.dg/ipa/pure-const-2.c scan-tree-dump local-pure-const1 "found to be pure: i_am_pure"
> FAIL: gcc.dg/tree-ssa/vrp35.c scan-tree-dump vrp1 "Removing dead stmt [^\r\n]* = j_.* == 10"
> FAIL: gcc.dg/tree-ssa/vrp36.c scan-tree-dump vrp1 "Removing dead stmt [^\r\n]* = i_.* == 1"
> FAIL: gcc.dg/vrp-min-max-1.c scan-tree-dump-times mergephi2 "MAX_EXPR" 1
> FAIL: gcc.dg/vrp-min-max-1.c scan-tree-dump-times mergephi2 "MIN_EXPR" 1
< XFAIL: gcc.dg/tree-ssa/vrp113.c scan-tree-dump vrp1 "return 3;"
< FAIL: g++.dg/pr88217.C  -std=gnu++14  8 blank line(s) in output
< FAIL: g++.dg/pr88217.C  -std=gnu++14 (internal compiler error)
< FAIL: g++.dg/pr88217.C  -std=gnu++14 (test for excess errors)
< FAIL: g++.dg/pr88217.C  -std=gnu++17  8 blank line(s) in output
< FAIL: g++.dg/pr88217.C  -std=gnu++17 (internal compiler error)
< FAIL: g++.dg/pr88217.C  -std=gnu++17 (test for excess errors)
< FAIL: g++.dg/pr88217.C  -std=gnu++2a  8 blank line(s) in output
< FAIL: g++.dg/pr88217.C  -std=gnu++2a (internal compiler error)
< FAIL: g++.dg/pr88217.C  -std=gnu++2a (test for excess errors)
> FAIL: g++.dg/tree-ssa/pr61034.C  -std=gnu++14  scan-tree-dump-times fre3 "free" 10
> FAIL: g++.dg/tree-ssa/pr61034.C  -std=gnu++14  scan-tree-dump-times fre3 "unreachable" 11
> FAIL: g++.dg/tree-ssa/pr61034.C  -std=gnu++17  scan-tree-dump-times fre3 "free" 10
> FAIL: g++.dg/tree-ssa/pr61034.C  -std=gnu++17  scan-tree-dump-times fre3 "unreachable" 11
> FAIL: g++.dg/tree-ssa/pr61034.C  -std=gnu++2a  scan-tree-dump-times fre3 "free" 10
> FAIL: g++.dg/tree-ssa/pr61034.C  -std=gnu++2a  scan-tree-dump-times fre3 "unreachable" 11
> FAIL: g++.dg/tree-ssa/pr61034.C  -std=gnu++98  scan-tree-dump-times fre3 "free" 10
> FAIL: g++.dg/tree-ssa/pr61034.C  -std=gnu++98  scan-tree-dump-times fre3 "unreachable" 11
2020-04-29 18:36:35 +02:00
Aldy Hernandez
4d54dcd0b2 Remove redundant code from operator_bitwise_and::op1_range. 2020-04-29 16:59:00 +02:00
Aldy Hernandez
423845c7db Add operator tests in range-op unit tests. 2020-04-29 16:59:00 +02:00
Aldy Hernandez
f4fdaf111d Only TDF_GORI turns on tracing, not TDF_DETAILS. 2020-04-29 16:59:00 +02:00
Aldy Hernandez
7f0cbb5e5c Run two RVRP passes before and after EVRP.
RVRP1 runs before EVRP.
RVRP2 runs after EVRP.
RVRP1 has IL changes OFF by default.
RVRP2 has IL changes ON by default.

IL changes are enabled/disabled with these flags:

	-frvrp1-changes vs -fno-rvrp1-changes
	-frvrp2-changes vs -fno-rvrp2-changes

GORI dumps are disabled by default and can be enabled with:

	-fdump-tree-all-details-gori
2020-04-29 16:56:33 +02:00
Aldy Hernandez
d01bb094e0 Use trace_ranger in evrp_range_analyzer. 2020-04-29 11:06:32 +02:00
Aldy Hernandez
d34a06eb10 Handle switches having a case pointing to the same destination as the default. 2020-04-29 11:06:32 +02:00
Aldy Hernandez
b1742cc9ca Use object_allocator to allocate new value_range_equiv entries. 2020-04-29 07:52:23 +02:00
Aldy Hernandez
57792146bf Disable IL changes in RVRP pass.
With IL changes enabled (-frvrp-changes), these are the known regressions:

> FAIL: gcc.dg/tree-ssa/evrp7.c scan-tree-dump evrp "Removing dead stmt [^\r\n]* = j_.* == 10"
> FAIL: gcc.dg/tree-ssa/evrp8.c scan-tree-dump evrp "Removing dead stmt [^\r\n]* = i_.* == 1"
> FAIL: gcc.dg/tree-ssa/pr21559.c scan-tree-dump-times evrp "Simplified relational" 1
> FAIL: gcc.dg/tree-ssa/pr61839_2.c scan-tree-dump-times evrp "972195717 / " 1
> FAIL: gcc.dg/tree-ssa/vrp17.c scan-tree-dump-times evrp "Simplified relational" 1
> FAIL: gcc.dg/tree-ssa/vrp18.c scan-tree-dump-times evrp "Simplified relational" 1
> FAIL: gcc.dg/tree-ssa/vrp23.c scan-tree-dump-times evrp "Simplified relational" 1
> FAIL: gcc.dg/tree-ssa/vrp24.c scan-tree-dump-times evrp "Simplified relational" 2
> FAIL: gcc.dg/tree-ssa/vrp35.c scan-tree-dump vrp1 "Removing dead stmt [^\r\n]* = j_.* == 10"
> FAIL: gcc.dg/tree-ssa/vrp36.c scan-tree-dump vrp1 "Removing dead stmt [^\r\n]* = i_.* == 1"
> FAIL: gcc.dg/vrp-min-max-1.c scan-tree-dump-times mergephi2 "MAX_EXPR" 1
> FAIL: gcc.dg/vrp-min-max-1.c scan-tree-dump-times mergephi2 "MIN_EXPR" 1
< XFAIL: gcc.dg/tree-ssa/vrp113.c scan-tree-dump vrp1 "return 3;"
< XFAIL: gcc.dg/vect/vect-mask-store-move-1.c -flto -ffat-lto-objects  scan-tree-dump-times vect "Move stmt to created bb" 4
> FAIL: g++.dg/pr84933.C  -std=gnu++14 (internal compiler error)
> FAIL: g++.dg/pr84933.C  -std=gnu++14 (test for excess errors)
> FAIL: g++.dg/pr84933.C  -std=gnu++17 (internal compiler error)
> FAIL: g++.dg/pr84933.C  -std=gnu++17 (test for excess errors)
> FAIL: g++.dg/pr84933.C  -std=gnu++2a (internal compiler error)
> FAIL: g++.dg/pr84933.C  -std=gnu++2a (test for excess errors)
> FAIL: g++.dg/pr84933.C  -std=gnu++98 (internal compiler error)
> FAIL: g++.dg/pr84933.C  -std=gnu++98 (test for excess errors)
> FAIL: g++.dg/tree-ssa/pr61034.C  -std=gnu++14  scan-tree-dump-times fre3 "free" 10
> FAIL: g++.dg/tree-ssa/pr61034.C  -std=gnu++14  scan-tree-dump-times fre3 "unreachable" 11
> FAIL: g++.dg/tree-ssa/pr61034.C  -std=gnu++17  scan-tree-dump-times fre3 "free" 10
> FAIL: g++.dg/tree-ssa/pr61034.C  -std=gnu++17  scan-tree-dump-times fre3 "unreachable" 11
> FAIL: g++.dg/tree-ssa/pr61034.C  -std=gnu++2a  scan-tree-dump-times fre3 "free" 10
> FAIL: g++.dg/tree-ssa/pr61034.C  -std=gnu++2a  scan-tree-dump-times fre3 "unreachable" 11
> FAIL: g++.dg/tree-ssa/pr61034.C  -std=gnu++98  scan-tree-dump-times fre3 "free" 10
> FAIL: g++.dg/tree-ssa/pr61034.C  -std=gnu++98  scan-tree-dump-times fre3 "unreachable" 11

The 84933 regression is the known -fstrict-enum failure.
2020-04-28 22:01:45 +02:00
Aldy Hernandez
596ec9a19b Set nonzero from mask if everything else fails. 2020-04-28 20:14:46 +02:00
Aldy Hernandez
ed94068fb3 Fix remove_impossible_ranges so it works with masks larger than 32-bits. 2020-04-28 18:26:31 +02:00
Aldy Hernandez
4e3a54f0ea Use varying if we can't determine anything on a bitwise AND op1_range. 2020-04-28 18:26:31 +02:00
Aldy Hernandez
6273e85ad8 Fix operator_mult::op1_range for when overflow wraps.
We can't solve 0 = OP1 * N by dividing by N with a wrapping type.
For example: For 0 = OP1 * 2, OP1 could be 0, or MAXINT.

So bail, when overflow wraps.
2020-04-28 18:26:31 +02:00
Aldy Hernandez
4a7bfd79b3 Fix union_ so it works with signed 1-bit numbers. 2020-04-28 18:26:31 +02:00
Aldy Hernandez
73d5e1ca79 Adjust bitwise and op1_range so it works with LHS of VARYING.
Nothing can be determined from:

VARYING = OP1 & MASK

In which case, return VARYING.
2020-04-28 18:26:26 +02:00
Aldy Hernandez
e8fd51064c Minor cleanups to propagate engine to make dumps more readable. 2020-04-28 10:08:18 +02:00
Aldy Hernandez
413b5adf6a Coding convention cleanups. 2020-04-28 10:07:31 +02:00
Aldy Hernandez
a55f167fde Andrew's fix to remove asserts in block cache. 2020-04-28 10:07:31 +02:00
Aldy Hernandez
77036c3309 Initial implementation of ranger VRP pass. 2020-04-28 10:07:28 +02:00
Aldy Hernandez
3fd307e754 Minor cleanups to gori. 2020-04-23 18:10:28 +02:00
Aldy Hernandez
25cfa84da6 Do not overflow when resizing large widest_irange's. 2020-04-22 15:17:50 +02:00
Aldy Hernandez
31445ce3c2 Add STMT argument to substitute_and_fold_engine::get_value(). 2020-04-22 14:17:52 +02:00
Aldy Hernandez
faf33902ff Cleanups to gori_compute_cache and logical_stmt_cache. 2020-04-22 10:28:54 +02:00
Aldy Hernandez
ab8cdab5e6 New tf_range class to pass around pairs of true/false ranges. 2020-04-22 01:39:44 +02:00
Aldy Hernandez
4a5c4619b4 Simlify arguments passed in logical_stmt_cache. 2020-04-22 01:38:50 +02:00
Aldy Hernandez
b9f248d8fa Refactor compute_logical_operands_in_chain. 2020-04-21 11:57:29 +02:00
Aldy Hernandez
f5267b3697 Cleanup compute_operand_range. 2020-04-21 11:49:40 +02:00
Aldy Hernandez
608481d7dc Refactor slot diagnostics from the set_range code. 2020-04-21 11:41:50 +02:00
Aldy Hernandez
c0f9a600cc Grow logical_stmt cache as needed. 2020-04-20 17:23:21 +02:00
Aldy Hernandez
6b179b967a Optimize logical operands whose operands may be known.
This optimizes:

	0 = x | y	Operands are known to be 0.

	1 = x & y	Operands are known to be 1.
2020-04-20 16:09:26 +02:00
Aldy Hernandez
717b963ed0 Remove recursion depth restrictions. 2020-04-20 16:09:26 +02:00
Aldy Hernandez
550186c047 Implement gori_compute_cache which caches boolean operations. 2020-04-20 16:09:23 +02:00
Aldy Hernandez
353e3a5465 Merge compute_operand_range_op and compute_operand_range into the latter. 2020-04-17 18:57:13 +02:00
Aldy Hernandez
302ef01db3 Take into account PHI args in the loop_ranger. 2020-04-08 13:31:21 -04:00
Aldy Hernandez
9eac184417 Implement global_ranger::range_on_edge to intersect with global ssa range. 2020-04-08 13:30:34 -04:00
Aldy Hernandez
277d95af38 Misc header cleanups. 2020-04-03 13:27:57 +02:00
Aldy Hernandez
e6db00c130 Convert range_of_builtin_call to irange API. 2020-04-03 13:27:55 +02:00
Aldy Hernandez
e6fd3f3cdf New gimple_ranger::range_of_builtin_call to house the builtins codes. 2020-04-03 10:17:53 +02:00
Aldy Hernandez
fa8f67d081 Shuffle all the ranger code around into various files:
gimple-range-cache.*
gimple-range-stmt.*
gimple-range-gori.*
gimple-range-cfg.*
gimple-ranger.*
2020-04-02 19:54:58 +02:00
Aldy Hernandez
d04d67fee0 More vr_comparison to vr-values.* 2020-04-02 11:06:23 +02:00
Aldy Hernandez
9e927c2144 Handle builtins in gimple_ranger::range_of_call. 2020-04-02 11:06:21 +02:00
Aldy Hernandez
762129fe36 Adjust value_inside_range() for irange.
Any uses of VR_ANTI_RANGE are problematic if the caller sent in an
irange that has more than <1> sub-range.  So all functions that
receive an irange should be adjusted to NEVER use VR_ANTI_RANGE.
2020-04-02 11:05:34 +02:00
Aldy Hernandez
c6b05b86ed Intersect known global ranges of LHS in gimple_ranger::range_of_call. 2020-03-31 16:19:37 +02:00
Aldy Hernandez
c8f4b642d2 Misc cleanups and cosmetic changes to ranger. 2020-03-31 16:17:39 +02:00
Aldy Hernandez
ff7ae60c27 Remove forward declaration of loop_ranger in ssa-range.h 2020-03-30 14:04:41 +02:00
Aldy Hernandez
5b6d81b17e New simplify_using_ranges and range_store classes.
simplify_using_ranges class contains the simplication with ranges code.

range_store is a class which provides a generic mechanism to get a stored
range for an SSA.  All goris and vr_values inherit from it.
2020-03-30 14:00:14 +02:00
Aldy Hernandez
fde9e8acfb Merge evrp dom walker with substitute_and_fold engine. 2020-03-25 17:27:44 +01:00
Aldy Hernandez
eaee77632d Rewrite simplify_min_or_max_using_ranges using range_ops. 2020-03-25 17:27:36 +01:00
Andrew MacLeod
ee70d79e66 add ranger code base 2020-03-23 13:10:34 -04:00
Aldy Hernandez
52f48b97c5 Enable gori tracing with a flag: -fdump-tree-all-gori. 2020-03-16 12:31:39 +01:00
Aldy Hernandez
c6a2bc2f87 Fix infinite loop on truncating widest_irange copies. 2020-03-13 13:28:07 -04:00
Aldy Hernandez
2b00c48907 Disable generic ignoring of narrowing casts in favor of finer grained. 2020-03-11 17:29:55 +01:00
Aldy Hernandez
4f40aee87d Document narrowing cast discrepancy. 2020-03-11 11:29:30 +01:00
Aldy Hernandez
f7626d1ebf Remove special checks for equivalences of the form: X .relop. Y.
It turns out these "equivalences" really only register overflow checks.  They notice:

unsigned_sum = unsigned_a + 1
if (unsigned_sum > unsigned_a)

and register that unsigned_a < MAXINT.

Instead of special checking this in the comparison and trap code, set gori_computable=false
in the overflow checking code.
2020-03-11 10:40:09 +01:00
Aldy Hernandez
1ece551411 Always trap on gori / evrp mismatches. 2020-03-11 10:40:07 +01:00
Aldy Hernandez
25acb18573 Move recursion limits to gori_compute::compute_operand_range_op.
Allow special cases of:

	1 = x & y
	0 = x | y

...to recurse infinitely, because we know they won't blow up compile time.
2020-03-10 17:42:12 +01:00
Aldy Hernandez
02807fb45d Early bail out of logical_combine if all operands are varying. 2020-03-10 17:41:45 +01:00
Aldy Hernandez
0e95df7c00 Adjust compute_logical_operands to use known range if we can't compute one. 2020-03-10 12:14:49 +01:00
Aldy Hernandez
7b0df61d25 Add code to trace compute_logical_operands. 2020-03-10 12:07:43 +01:00
Aldy Hernandez
5a9f103322 Do not refine some ranges in vr_gori_interface::outgoing_edge_range_p.
Do not refine ranges if result is already a singleton.
2020-03-10 12:05:49 +01:00
Aldy Hernandez
df81d24357 Avoid duplicate work in refine_range_with_equivalences. 2020-03-05 09:08:53 +01:00
Aldy Hernandez
c1729bcfb1 Implement new trace_gori_compute class to provide debugging facilities for GORI. 2020-03-05 09:08:53 +01:00
Aldy Hernandez
4fb96e0c6e Refactor the gori + evrp calculation code. 2020-03-05 09:08:04 +01:00
Aldy Hernandez
775488eb55 Remove use of assert_info in favor of using GORI's export list. 2020-03-04 13:43:00 +01:00
Aldy Hernandez
e0c9f49367 Remove vr_gori_interface::range_for_op2. 2020-03-04 13:43:00 +01:00
Aldy Hernandez
8096618793 New vr_gori_interface class. 2020-03-04 13:43:00 +01:00
Aldy Hernandez
8678b960e9 Do not give up in compute_logical_operands if one chain is incalculable. 2020-02-25 09:23:19 +01:00
Aldy Hernandez
1eb0287430 Rename S to STMT in gimple-range.cc. 2020-02-25 09:22:58 +01:00
Aldy Hernandez
f6873bb8ff Implement operator_bitwise_xor::op1_range for booleans. 2020-02-25 06:32:21 +01:00
Aldy Hernandez
a542cf738e Gori adjustments for Ada multi-bit booleans. 2020-02-25 06:32:21 +01:00
Aldy Hernandez
74cb4de899 Rename all variables S to STMT in GORI for consistency. 2020-02-25 06:32:21 +01:00
Aldy Hernandez
a3c7d42f45 Mark assert's that are not computable by GORI and ignore them.
Any time evrp is registering an assert from knowledge that is
unavailable in GORI (chasing IMM_USE chains, cheating casts, etc),
mark these asserts as uncomputable, so we can ignore them while
comparing against evrp.
2020-02-25 06:32:20 +01:00
Aldy Hernandez
ac18bfb92b Tweak dump_gori_differences. 2020-02-25 06:32:20 +01:00
Aldy Hernandez
bce6d53da6 GORIME environment variable can be used to run in dump only mode.
GORIME=dump will write differences to /tmp/gori-differences.

Otherwise, setting GORIME will trap.
2020-02-25 06:32:20 +01:00
Aldy Hernandez
3c027e0f14 Change debug_gori_ranges so it can dump to any file. 2020-02-25 06:32:20 +01:00
Aldy Hernandez
63657cd2eb Avoid dumping empty lines in gori::dump.
Also, shuffle equivalence + gori dumps from vr-values.
2020-02-25 06:32:20 +01:00
Aldy Hernandez
ec00a647c9 Do not calculate ranges for names that are not in the GORI exports. 2020-02-25 06:32:20 +01:00
Aldy Hernandez
483d62b0dc Ignore discrepancies between gori and evrp for equivalence looking things. 2020-02-25 06:32:20 +01:00
Aldy Hernandez
665956722d Comment the equivalence_iterator. 2020-02-25 06:32:20 +01:00
Aldy Hernandez
39ba0fabc0 Always use known range for operand2 in gori_compute::compute_operand2_range.
Adjust method so that even if it cannot compute the range for op2, it will use the known
range if available.
2020-02-25 06:31:06 +01:00
Aldy Hernandez
96e9021d1c Implement a special case of operator_mult::op1_range for singletons. 2020-02-24 21:03:27 +01:00
Aldy Hernandez
b6a6426a49 Use widest_irange temporaries in the GORI logical code.
This allows us to finely keep track of chains of logical expressions.
For example:

  bool _33, _34, _35;
  ...
  _33 = s_66 == 5;
  _34 = s_66 == 10;
  _35 = _33 | _34;
  if (_35 == 0)
    HERE;

While pawing back from HERE, we will be able to keep track that
s_66 is not 5 and not 10.
2020-02-24 21:03:27 +01:00
Aldy Hernandez
6b52a6baaa Implement strcmp variants for gimple and trees. 2020-02-24 21:03:27 +01:00
Aldy Hernandez
73a9a85d0d Add debug counter for when evrp ranges are calculated. 2020-02-24 21:03:26 +01:00
Aldy Hernandez
185146f0ac Rewrite vr_values::outgoing_edge_range_p to use all available ranges in equivalences. 2020-02-24 21:00:40 +01:00
Aldy Hernandez
6431c0c936 Rewrite bitwise_and::op1_range to use evrp's code.
Also, open code operator_bitwise_and::fold_range and make it remove
impossible ranges.
2020-01-29 16:38:57 +01:00
Aldy Hernandez
3a6a3700e1 Implement bitwise or for integers and pointers:
operator_bitwise_or::op1_range
pointer_or_operator::op1_range
pointer_or_operator::op2_range
2020-01-27 09:58:51 +01:00
Aldy Hernandez
5852617c99 Fix operator_rshift::op1_range so it doesn't overflow. 2020-01-27 09:58:51 +01:00
Aldy Hernandez
b93b79eceb Rewrite some comments in gori_compute::compute_operand_range*. 2020-01-27 09:58:51 +01:00
Aldy Hernandez
392dd3fbbb Allow ranges with overflowed components. 2020-01-27 09:58:51 +01:00
Aldy Hernandez
0437c263f0 Merge trunk@279995 into branch.
From-SVN: r280001
2020-01-08 13:36:28 +00:00
Aldy Hernandez
7b6889b84f Gather statistics on how many sub-ranges are used in widest_irange
throughout the compilation unit.

From-SVN: r278677
2019-11-25 10:55:26 +00:00
Aldy Hernandez
99403c03fd Use std::vector<value_range> isntead of auto_vec<value_range> in
ipa-fnsummary.c.

From-SVN: r278619
2019-11-22 15:11:23 +00:00
Aldy Hernandez
ff64c4fc2a Do not die on symbolics in gori_range_is_better.
From-SVN: r278569
2019-11-21 15:23:26 +00:00
Aldy Hernandez
f7716ecfbc Remove gori_range_is_unrepresentable since with widest_irange we can always
representing a range.

From-SVN: r278568
2019-11-21 15:23:18 +00:00
Aldy Hernandez
8d31cb98f6 Do not ICE when dumping gori improvements of symbolics.
From-SVN: r278567
2019-11-21 15:23:11 +00:00
Aldy Hernandez
20f438d4f0 Add test for truncating copy of an anti-range.
From-SVN: r278565
2019-11-21 15:23:04 +00:00
Aldy Hernandez
528ac0124c Fix infinite loop in vrange::operator=.
From-SVN: r278564
2019-11-21 15:22:56 +00:00
Aldy Hernandez
bfde05836d Convservatively convert multi-ranges that will be truncated to a value_range.
From-SVN: r278563
2019-11-21 15:22:48 +00:00
Aldy Hernandez
c1e7c67268 Have the union/intersect pointer versions call the reference.
From-SVN: r278562
2019-11-21 15:22:39 +00:00
Aldy Hernandez
1838cf93b0 Convert gori to irange.
From-SVN: r278561
2019-11-21 15:22:32 +00:00
Aldy Hernandez
7b785411e4 Remove value_range define in range-op.
From-SVN: r278560
2019-11-21 15:22:25 +00:00
Aldy Hernandez
862506fe27 Convert range-op to irange.
From-SVN: r278559
2019-11-21 15:22:17 +00:00
Aldy Hernandez
edfbdc27fa Swap int_range and irange names.
From-SVN: r278558
2019-11-21 15:22:09 +00:00
Aldy Hernandez
8f0abf2547 Implement abstract class vrange along with deriveded classes.
From-SVN: r278457
2019-11-19 17:45:40 +00:00
Aldy Hernandez
011496d96f Merge branch 'trunk-at-merge' into ranger
From-SVN: r278417
2019-11-18 16:42:49 +00:00
Aldy Hernandez
112a17036d Remove range_intersect, range_invert, and range_union.
From-SVN: r278261
2019-11-14 19:07:37 +00:00
Aldy Hernandez
53dc0d5f76 Merge branch 'trunk-at-merge' into ranger-merge
From-SVN: r278260
2019-11-14 19:07:24 +00:00
Aldy Hernandez
3cb7dcfdc6 Merge branch 'trunk-at-merge' into ranger
From-SVN: r278216
2019-11-14 10:31:36 +00:00
Aldy Hernandez
6dc1dafb21 Merge remote-tracking branch 'origin/trunk' into ranger-merge
From-SVN: r277770
2019-11-04 10:06:24 +00:00
Andrew Macleod
7366b4ed51 updated op1_range for operater_cast
From-SVN: r277713
2019-11-01 16:25:36 +00:00
Aldy Hernandez
a4e46044c3 Dump gori improvements to evrp in dump file.
Reshuffle order of methods.

From-SVN: r277673
2019-10-31 14:07:25 +00:00
Aldy Hernandez
1e4a1fcc4e Use operand_equal_p to implement value_range_base::operator== instead of wide-ints.
Use operand_equal_p to implement value_range_base::operator== instead of
wide-ints.  This allows us to compare ranges with symbolics.

Use value_range_base constructors in ::invert to force creation of
canonical ranges when flipping ranges.

From-SVN: r277671
2019-10-31 14:07:07 +00:00
Aldy Hernandez
4fdf8b66b7 Make range_has_numeric_bounds_p extern.
From-SVN: r277670
2019-10-31 14:06:54 +00:00
Aldy Hernandez
381cdee9cd Do not dump unprocessed BBs in gori_map::dump.
From-SVN: r277669
2019-10-31 14:06:38 +00:00
Aldy Hernandez
ab83346043 Normalize unsigned ~[0,0] into [1,MAX].
From-SVN: r277668
2019-10-31 14:06:26 +00:00
Aldy Hernandez
95c27443b4 Performance tweaks.
From-SVN: r277580
2019-10-29 17:46:22 +00:00
Aldy Hernandez
6b3e788d83 Rename unsigned_mask to unsigned_mask_p.
From-SVN: r277330
2019-10-23 13:11:31 +00:00
Aldy Hernandez
292d840c41 Merge gori and evrp results.
When GORIME environment variable set, assert that gori gets at least as good
results as evrp.

From-SVN: r277329
2019-10-23 13:11:22 +00:00
Aldy Hernandez
ffbed51445 Adjust vr_values::range_for_op2 to normalize addresses.
From-SVN: r277328
2019-10-23 13:11:14 +00:00
Aldy Hernandez
0467dd7cc5 Implement op1_range for bitmask << and >>.
From-SVN: r277327
2019-10-23 13:11:05 +00:00
Aldy Hernandez
5c27e40e54 Implement operator_bitwise_and::op1_range() for unsigned masks
known to be zero or non-zero.

From-SVN: r277326
2019-10-23 13:10:57 +00:00
Aldy Hernandez
af64c1bd95 Make vr_values inherit from gori_computes, and provide an
outgoing_edge_range_p that can handle equivalences.

From-SVN: r277325
2019-10-23 13:10:48 +00:00
Aldy Hernandez
7cee184441 Disable annoying warnings for some files.
From-SVN: r277324
2019-10-23 13:10:31 +00:00
Aldy Hernandez
6537c9b038 Dump GORI map when asserting value_ranges are equal.
Add dump functions for assert_info struct.

Add debug(gori_map&) dump routine.

From-SVN: r277066
2019-10-16 14:10:27 +00:00
Andrew Macleod
0c0d17e822 Fix evrp_range_analyzer::record_ranges_from_incoming_edge so we dont get a...
Fix evrp_range_analyzer::record_ranges_from_incoming_edge
so we dont get a "possibly uninitialized" warning by always generating a gori range

From-SVN: r277007
2019-10-15 18:47:00 +00:00
Aldy Hernandez
b80e6a443f Debug entire IL in assert_value_ranges_are_equal.
From-SVN: r276838
2019-10-10 15:48:59 +00:00
Aldy Hernandez
c8507441c7 Initial take at making evrp analyzer use GORI computes.
From-SVN: r276806
2019-10-10 13:24:53 +00:00
Aldy Hernandez
b540c32126 Fix typo in comment.
From-SVN: r276805
2019-10-10 13:11:05 +00:00
Aldy Hernandez
2bedc2b00c Make name_range argument in outgoing_edge_range_p a const.
From-SVN: r276803
2019-10-10 12:59:02 +00:00
Aldy Hernandez
ab1ce955e2 Add != operator for value_range_base.
From-SVN: r276802
2019-10-10 12:58:56 +00:00
Aldy Hernandez
43acb42282 Make gimple_range_ssa_p look at TREE_TYPE, instead of
incorrectly looking at the SSA name.

From-SVN: r276801
2019-10-10 12:58:50 +00:00
Aldy Hernandez
05d69a4066 Make gori_compute destructor virtual to silence warnings.
From-SVN: r276800
2019-10-10 12:58:44 +00:00
Aldy Hernandez
795a01b1b0 Handle undefined in normalize_address.
From-SVN: r276799
2019-10-10 12:58:38 +00:00
Aldy Hernandez
0651329d18 Fix typos in comments.
From-SVN: r276798
2019-10-10 12:58:32 +00:00
Aldy Hernandez
43e7f2b096 Adjust all comments and code for correct wrapping.
Remove all trailing spaces.

From-SVN: r276788
2019-10-10 06:33:57 +00:00
Andrew Macleod
82da0512f7 Add initial gimple-range and gori-computes components
From-SVN: r276772
2019-10-09 21:20:02 +00:00
Aldy Hernandez
85b722579d Merge branch 'trunk-at-merge' into merge
From-SVN: r276687
2019-10-08 07:16:20 +00:00
Aldy Hernandez
2a58ac1efd Inverting a range of VARYING or UNDEFINED traps.
From-SVN: r276486
2019-10-02 19:54:09 +00:00
Aldy Hernandez
fcdbbb3ebb Fix fallout from merge.
From-SVN: r276451
2019-10-02 11:16:30 +00:00
Aldy Hernandez
cd6639b86f Merge remote-tracking branch 'origin/trunk' into ranger
Merged at trunk commit 2ace3ebdd2
(trunk@276439).

From-SVN: r276450
2019-10-02 11:15:34 +00:00
Aldy Hernandez
9e6c41477c Add ChangeLog entries.
From-SVN: r276118
2019-09-25 07:44:25 +00:00
Aldy Hernandez
ec6fcd5a77 Performance shuffling for range-ops.
Performance shuffling for range-ops.  Mainly, avoid making unnecessary
copies of value_range's.

From-SVN: r276117
2019-09-25 07:21:49 +00:00
Aldy Hernandez
e5bda90a68 Remove inefficient dependencies on ranges_from_anti_range.
From-SVN: r276116
2019-09-25 07:21:43 +00:00
Aldy Hernandez
cd84b4aeba Add functions comments.
From-SVN: r276115
2019-09-25 07:21:37 +00:00
Aldy Hernandez
4372889799 Rename some range-ops gcc_asserts to gcc_checking_asserts.
From-SVN: r276114
2019-09-25 07:21:30 +00:00
Aldy Hernandez
41b0416dc2 Remove range-ops and VRP checking code.
Remove extract_range_from_binary_expr and dependencies.
Remove extract_range_from_unary_expr and dependencies.
Remove wide-int-range.* interface.

From-SVN: r276113
2019-09-25 07:21:23 +00:00
Aldy Hernandez
c08555a9bc RSHIFT by [SYM...
RSHIFT by [SYM, INT] is dropped to varying in VRP, but range-ops can normalize this to [0, INT]
which can sometimes give better results.  Adjust the checking code to ignore this
discrepancy.

From-SVN: r276029
2019-09-22 17:10:20 +00:00
Aldy Hernandez
20ecf0b30f Handle pointers in normalize_symbolics.
From-SVN: r276028
2019-09-22 15:52:05 +00:00
Aldy Hernandez
0a7de7f51a class cross_product_operator
From-SVN: r275595
2019-09-10 17:27:44 +00:00
Aldy Hernandez
7ff8d435e5 Minor comment fixes.
From-SVN: r275351
2019-09-03 19:40:53 +00:00
Aldy Hernandez
da26a4ac3b Remove wide_int_binop* switch in favor of implementing it with
virtual functions in the range operator class.

From-SVN: r275340
2019-09-03 13:07:47 +00:00
Aldy Hernandez
c98bbf5b9f Comment police work.
From-SVN: r274993
2019-08-28 15:05:02 +00:00
Aldy Hernandez
dbf325ba9a Rename accumulate_range and friends to create_range_with_overflow.
Change code so it returns a range instead of accumulating into a range.

From-SVN: r274974
2019-08-27 21:27:56 +00:00
Aldy Hernandez
f837b1ea59 Revert:
Move PLUS/MINUS_EXPR code into extract_range_from_plus_minus_expr.

From-SVN: r274973
2019-08-27 21:27:51 +00:00
Aldy Hernandez
228df8c40c Move PLUS/MINUS_EXPR code into extract_range_from_plus_minus_expr.
From-SVN: r274963
2019-08-27 17:29:17 +00:00
Aldy Hernandez
e005383e59 Initial trunk based range-ops port.
From-SVN: r274960
2019-08-27 15:24:26 +00:00
77 changed files with 7991 additions and 1086 deletions

View File

@@ -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 \

View File

@@ -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.

View File

@@ -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)

View File

@@ -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}

View File

@@ -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. */

View File

@@ -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}?")" {

View File

@@ -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
View 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
View 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

File diff suppressed because it is too large Load Diff

92
gcc/gimple-range-gori.h Normal file
View 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
View 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

File diff suppressed because it is too large Load Diff

160
gcc/gimple-range.h Normal file
View 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

View File

@@ -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.

View File

@@ -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

View File

@@ -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);

View File

@@ -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,

View File

@@ -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;

View File

@@ -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
View 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
View 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;
};

View File

@@ -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. */

View File

@@ -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);

File diff suppressed because it is too large Load Diff

View File

@@ -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,

View File

@@ -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); }

View File

@@ -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)
{

View File

@@ -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)
{

View File

@@ -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;

View File

@@ -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];

View File

@@ -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 ()

View File

@@ -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 ();

View File

@@ -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);

View File

@@ -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)

View File

@@ -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)

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);

View File

@@ -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)

View File

@@ -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);

View File

@@ -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)

View File

@@ -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];

View File

@@ -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);

View File

@@ -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));

View File

@@ -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))

View File

@@ -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))

View File

@@ -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

View 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;
}

View 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);
}

View File

@@ -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
{

View File

@@ -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
{

View File

@@ -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);

View File

@@ -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)

View File

@@ -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

View File

@@ -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)
{

View File

@@ -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) {

View File

@@ -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 ();

View File

@@ -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);

View File

@@ -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. */

View File

@@ -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)
{

View File

@@ -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)
{

View File

@@ -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);

View File

@@ -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. */

View File

@@ -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);

View File

@@ -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");
}

View File

@@ -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))

View File

@@ -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;

View File

@@ -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 */

View File

@@ -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 ();

View File

@@ -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 ());
}

View File

@@ -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);

File diff suppressed because it is too large Load Diff

View File

@@ -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

View File

@@ -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);

View File

@@ -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 */