Hi all,
This patch series is intended to improve use of widening multiply, and
widening multiply-and-accumulate instructions. This is primarily for the
benefit of ARM targets, but should give some improvements to other
targets also.
The patches provide a number of improvements:
* Support for instructions that widen by more than one mode
(e.g. from HImode to DImode).
* Use of widening multiplies even when the input mode is narrower than
the instruction uses. (e.g. Use HI->DI to do QI->DI).
* Use of signed widening multiplies (of a larger mode) where unsigned
multiplies are not available.
* Support for input operands with mis-matched signedness, with or
without usmul_widen_optab.
* Support for input operands with mis-matched mode [1].
* Improved pattern matching in the widening_mult pass.
* Recognition of true types, even if obscured by a cast.
* Insertion of extra gimple statements where the existing code was
incompatible with widening multiplies.
* Recognition of widening multiply-and-accumulate even where the
multiply expression was not widening.
The end result is that, on ARM, many many of the cases where the
compiler would fall back to regular multiplies, extensions, and add
instructions can now be handled with just one instruction.
For those interested in the before and after states, I have attached a
couple of shell scripts. These generate test cases with many
permutations of types and signedness.
[1] Operands of mis-matched mode are multiplied by extending the smaller
one to match the larger one. Although this does not support mis-matched
mode instructions directly, this ought to improve the chances of the
combine pass doing The Right Thing. (Although this does depend on there
being a suitable matched-mode instruction for widen_mult/expand to use.)
So, on to the patches ....
Andrew
#!/bin/bash
for op in madd mul; do
for i1 in char short int "long long"; do
for i2 in char short int "long long"; do
for o in char short int "long long"; do
for x in unsigned signed; do
for y in unsigned signed; do
for z in unsigned signed; do
for c in cast nocast; do
echo "$x $o"
echo "${op}_${x}_${o/ /}_${y}_${i1/ /}_${z}_${i2/ /}_$c ($x $o
a, $y $i1 *b, $z $i2 *c)"
echo "{"
case $op+$c in
madd+cast) echo " return a + ($x $o)*b * ($x $o)*c;" ;;
madd+nocast) echo " return a + *b * *c;" ;;
mul+cast) echo " return ($x $o)*b * ($x $o)*c;" ;;
mul+nocast) echo " return *b * *c;" ;;
esac
echo "}"
echo
done
done
done
done
done
done
done
done
#!/bin/bash
for op in madd mul; do
for i1 in char short int "long long"; do
for i2 in char short int "long long"; do
for o in char short int "long long"; do
for x in unsigned signed; do
for y in unsigned signed; do
for z in unsigned signed; do
for c in cast nocast; do
echo "$x $o"
echo "${op}_${x}_${o/ /}_${y}_${i1/ /}_${z}_${i2/ /}_$c ($x $o
a, $y $i1 b, $z $i2 c)"
echo "{"
case $op+$c in
madd+cast) echo " return a + ($x $o)b * ($x $o)c;" ;;
madd+nocast) echo " return a + b * c;" ;;
mul+cast) echo " return ($x $o)b * ($x $o)c;" ;;
mul+nocast) echo " return b * c;" ;;
esac
echo "}"
echo
done
done
done
done
done
done
done
done