Skip to content
Snippets Groups Projects
Commit 898f013e authored by Georg-Johann Lay's avatar Georg-Johann Lay
Browse files

AVR: Overhaul the avr-ifelse RTL optimization pass.

Mini-pass avr-ifelse realizes optimizations that replace two cbranch
insns with one comparison and two branches.  This patch adds the
following improvements:

- The right operand of the comparisons may also be REGs.
  Formerly only CONST_INT was handled.

- The RTX code of the first comparison in no more restricted
  to (effectively) EQ.

- When the second cbranch is located in the fallthrough path
  of the first cbranch, then difficult (expensive) comparisons
  can always be avoided.  This may require to swap the branch
  targets.  (When the second cbranch is located after the target
  label of the first one, then getting rid of difficult branches
  would require to reorder blocks.)

- The code has been cleaned up:  avr_rest_of_handle_ifelse() now
  just scans the insn stream for optimization candidates.  The code
  that actually performs the transformation has been outsourced to
  the new function avr_optimize_2ifelse().

- The code to find a better representation for reg-const_int comparisons
  has been split into two parts:  First try to find codes such that the
  right-hand sides of the comparisons are the same (avr_2comparisons_rhs).
  When this succeeds then one comparison can serve two branches, and
  that function tries to get rid of difficult branches.  This is always
  possible when the second cbranch is located in the fallthrough path
  of the first one.

Some final notes on why we don't use compare-elim:  1) The two cbranch
insns may come with different scratch operands depending on the chosen
constraint alternatives.  There are cases where the outgoing comparison
requires a scratch but only one incoming cbranch has one.  2) Avoiding
difficult branches can be achieved by rewiring basic blocks.
compare-elim doesn't do that; it doesn't even know the costs of the
branch codes.  3)  avr_2comparisons_rhs() may de-canonicalize a
comparison to achieve its goal.  compare-elim doesn't know how to do
that.  4) There are more reasons, see for example the commit message
and discussion for PR115830.

avr_2comparisons_rhs tries to decompose the interval as given by some
[u]intN_t into three intervals using the new Ranges struct that
implemens set operations on finite unions of intervals.
Sadly, value-range.h is not well suited for that, and writing a
wrapper around it that avoids all corner case ICEs would be more
laborious than struct Ranges.

gcc/
	* config/avr/avr.cc (INCLUDE_VECTOR): Define it.
	(cfganal.h): Include it.
	(Ranges): New struct.
	(avr_2comparisons_rhs, avr_redundant_compare_regs)
	(avr_strict_signed_p, avr_strict_unsigned_p): New static functions.
	(avr_redundant_compare): Overhaul: Allow more cases.
	(avr_optimize_2ifelse): New static function, outsourced from...
	(avr_rest_of_handle_ifelse): ...this method.
gcc/testsuite/
	* gcc.target/avr/torture/ifelse-c.h: New file.
	* gcc.target/avr/torture/ifelse-d.h: New file.
	* gcc.target/avr/torture/ifelse-q.h: New file.
	* gcc.target/avr/torture/ifelse-r.h: New file.
	* gcc.target/avr/torture/ifelse-c-i8.c: New test.
	* gcc.target/avr/torture/ifelse-d-i8.c: New test.
	* gcc.target/avr/torture/ifelse-q-i8.c: New test.
	* gcc.target/avr/torture/ifelse-r-i8.c: New test.
	* gcc.target/avr/torture/ifelse-c-i16.c: New test.
	* gcc.target/avr/torture/ifelse-d-i16.c: New test.
	* gcc.target/avr/torture/ifelse-q-i16.c: New test.
	* gcc.target/avr/torture/ifelse-r-i16.c: New test.
	* gcc.target/avr/torture/ifelse-c-u16.c: New test.
	* gcc.target/avr/torture/ifelse-d-u16.c: New test.
	* gcc.target/avr/torture/ifelse-q-u16.c: New test.
	* gcc.target/avr/torture/ifelse-r-u16.c: New test.
parent 6661944a
No related branches found
No related tags found
Loading
Showing
with 1275 additions and 229 deletions
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment