aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorHans-Peter Nilsson <hp@axis.com>2020-07-06 00:52:39 +0200
committerHans-Peter Nilsson <hp@axis.com>2020-07-06 01:17:25 +0200
commit65f8403f1a99f965ad3ed36adc4f889cf95ee1eb (patch)
tree21ff95af33cf2bc8ce70be715619cb5336bea220 /gcc
parentcc9a9229285a26ac12bc8de53237ce9c4d42f867 (diff)
downloadgcc-65f8403f1a99f965ad3ed36adc4f889cf95ee1eb.zip
gcc-65f8403f1a99f965ad3ed36adc4f889cf95ee1eb.tar.gz
gcc-65f8403f1a99f965ad3ed36adc4f889cf95ee1eb.tar.bz2
cris.md: Reinstate add/sub with extend
When cleaning out the multitude of patterns with unknown coverage, this one went the way of the bathwater. It's use is barely common enough to mark when diffing libgcc, and has a minimal impact on performance-testsuites. Anyway, reinstated with a couple of test-cases. It's suboptimal of gcc-core not to make use of the SImode pattern when performing HImode; see the FIXME (which is actually also reinstated). This version uses match_operator, for continuity but will be replaced with a version making use of iterators (like it does for the mode). gcc: * config/cris/cris.md ("*extopqihi", "*extop<mode>si<setnz>_swap") ("*extop<mode>si<setnz>", "*addxqihi_swap"): Reinstate. gcc/testsuite: * gcc.target/cris/pr93372-36.c, gcc.target/cris/pr93372-37.c, gcc.target/cris/pr93372-38.c: New tests.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/config/cris/cris.md83
-rw-r--r--gcc/testsuite/gcc.target/cris/pr93372-36.c37
-rw-r--r--gcc/testsuite/gcc.target/cris/pr93372-37.c26
-rw-r--r--gcc/testsuite/gcc.target/cris/pr93372-38.c30
4 files changed, 176 insertions, 0 deletions
diff --git a/gcc/config/cris/cris.md b/gcc/config/cris/cris.md
index 081041f..e700819 100644
--- a/gcc/config/cris/cris.md
+++ b/gcc/config/cris/cris.md
@@ -1108,6 +1108,89 @@
[(set_attr "slottable" "yes,yes,yes,yes,no,no")
(set_attr "cc<ccnz>" "normal,normal,clobber,clobber,normal,normal")])
+;; Extend versions (zero/sign) of normal add/sub (no side-effects).
+
+;; QImode to HImode
+;; FIXME: GCC should widen.
+
+(define_insn "*extopqihi"
+ [(set (match_operand:HI 0 "register_operand" "=r,r,r,r")
+ (match_operator:HI
+ 3 "cris_additive_operand_extend_operator"
+ [(match_operand:HI 1 "register_operand" "0,0,0,r")
+ (match_operator:HI
+ 4 "cris_extend_operator"
+ [(match_operand:QI 2 "nonimmediate_operand" "r,Q>,m,!To")])]))
+ (clobber (reg:CC CRIS_CC0_REGNUM))]
+ "GET_MODE_SIZE (GET_MODE (operands[0])) <= UNITS_PER_WORD
+ && (operands[1] != frame_pointer_rtx || GET_CODE (operands[3]) != PLUS)"
+ "@
+ %x3%E4.%m4 %2,%0
+ %x3%E4.%m4 %2,%0
+ %x3%E4.%m4 %2,%0
+ %x3%E4.%m4 %2,%1,%0"
+ [(set_attr "slottable" "yes,yes,no,no")
+ (set_attr "cc" "clobber")])
+
+(define_insn "*extop<mode>si<setnz>"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
+ (match_operator:SI
+ 3 "cris_operand_extend_operator"
+ [(match_operand:SI 1 "register_operand" "0,0,0,r")
+ (match_operator:SI
+ 4 "cris_extend_operator"
+ [(match_operand:BW 2 "nonimmediate_operand" "r,Q>,m,!To")])]))
+ (clobber (reg:CC CRIS_CC0_REGNUM))]
+ "(GET_CODE (operands[3]) != UMIN || GET_CODE (operands[4]) == ZERO_EXTEND)
+ && GET_MODE_SIZE (GET_MODE (operands[0])) <= UNITS_PER_WORD
+ && (operands[1] != frame_pointer_rtx || GET_CODE (operands[3]) != PLUS)"
+ "@
+ %x3%E4<m> %2,%0
+ %x3%E4<m> %2,%0
+ %x3%E4<m> %2,%0
+ %x3%E4<m> %2,%1,%0"
+ [(set_attr "slottable" "yes,yes,no,no")])
+
+;; We may have swapped operands for add or bound.
+;; For commutative operands, these are the canonical forms.
+
+;; QImode to HImode
+
+(define_insn "*addxqihi_swap"
+ [(set (match_operand:HI 0 "register_operand" "=r,r,r,r")
+ (plus:HI
+ (match_operator:HI
+ 3 "cris_extend_operator"
+ [(match_operand:QI 2 "nonimmediate_operand" "r,Q>,m,!To")])
+ (match_operand:HI 1 "register_operand" "0,0,0,r")))
+ (clobber (reg:CC CRIS_CC0_REGNUM))]
+ "operands[1] != frame_pointer_rtx"
+ "@
+ add%e3.b %2,%0
+ add%e3.b %2,%0
+ add%e3.b %2,%0
+ add%e3.b %2,%1,%0"
+ [(set_attr "slottable" "yes,yes,no,no")
+ (set_attr "cc" "clobber")])
+
+(define_insn "*extop<mode>si<setnz>_swap"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
+ (match_operator:SI
+ 4 "cris_plus_or_bound_operator"
+ [(match_operator:SI
+ 3 "cris_extend_operator"
+ [(match_operand:BW 2 "nonimmediate_operand" "r,Q>,m,!To")])
+ (match_operand:SI 1 "register_operand" "0,0,0,r")]))
+ (clobber (reg:CC CRIS_CC0_REGNUM))]
+ "(GET_CODE (operands[4]) != UMIN || GET_CODE (operands[3]) == ZERO_EXTEND)
+ && operands[1] != frame_pointer_rtx"
+ "@
+ %x4%E3<m> %2,%0
+ %x4%E3<m> %2,%0
+ %x4%E3<m> %2,%0
+ %x4%E3<m> %2,%1,%0"
+ [(set_attr "slottable" "yes,yes,no,no")])
+
;; This is the special case when we use what corresponds to the
;; instruction above in "casesi". Do *not* change it to use the generic
;; pattern and "REG 15" as pc; I did that and it led to madness and
diff --git a/gcc/testsuite/gcc.target/cris/pr93372-36.c b/gcc/testsuite/gcc.target/cris/pr93372-36.c
new file mode 100644
index 0000000..84fbdb7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/cris/pr93372-36.c
@@ -0,0 +1,37 @@
+/* Check that we produce sign- and zero-extended additions and
+ subtractions, and that no (eliminable) test- or compare-instructions
+ are used. */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { scan-assembler-not {\tcmp|\ttest|\tsub\.|\tadd\.|\tmovs} } } */
+/* { dg-final { scan-assembler "\tadds" } } */
+/* { dg-final { scan-assembler "\tsubs" } } */
+
+#ifndef t
+#define t signed char
+#define s _sc
+#endif
+
+#ifndef t2
+#define t2 int
+#endif
+
+#ifndef f
+#define f0(a, s) a ## s
+#define f(a, s) f0(a, s)
+#endif
+
+extern void g(int);
+
+t2 f(a, s) (t2 a, t *b, int *c)
+{
+ t2 d = a + *b;
+ *c = d == 0;
+ return d;
+}
+t2 f(b, s) (t2 a, t *b, int *c)
+{
+ t2 d = a - *b;
+ *c = d == 0;
+ return d;
+}
diff --git a/gcc/testsuite/gcc.target/cris/pr93372-37.c b/gcc/testsuite/gcc.target/cris/pr93372-37.c
new file mode 100644
index 0000000..0c43d77
--- /dev/null
+++ b/gcc/testsuite/gcc.target/cris/pr93372-37.c
@@ -0,0 +1,26 @@
+/* Check that we produce sign- and zero-extended additions and
+ subtractions, and that no (eliminable) test- or compare-instructions
+ are used. */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { scan-assembler-not {\tcmp|\ttest|\tsub\.|\tadd\.|\tmovu|\tmovs} } } */
+/* { dg-final { scan-assembler-times "\tadds" 1 } } */
+/* { dg-final { scan-assembler-times "\tsubs" 1 } } */
+/* { dg-final { scan-assembler-times "\taddu" 2 } } */
+/* { dg-final { scan-assembler-times "\tsubu" 2 } } */
+
+#define t unsigned char
+#define s _uc
+#include "pr93372-36.c"
+
+#undef t
+#undef s
+#define t signed short int
+#define s _ss
+#include "pr93372-36.c"
+
+#undef t
+#undef s
+#define t unsigned short int
+#define s _us
+#include "pr93372-36.c"
diff --git a/gcc/testsuite/gcc.target/cris/pr93372-38.c b/gcc/testsuite/gcc.target/cris/pr93372-38.c
new file mode 100644
index 0000000..c7cba3b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/cris/pr93372-38.c
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { scan-assembler-not {\tcmp|\tsub\.|\tadd\.|\tmovu|\tmovs} } } */
+/* { dg-final { scan-assembler-times "\ttest\.w" 4 } } */
+/* { dg-final { scan-assembler-times "\tadds" 1 } } */
+/* { dg-final { scan-assembler-times "\tsubs" 1 } } */
+/* { dg-final { scan-assembler-times "\taddu" 1 } } */
+/* { dg-final { scan-assembler-times "\tsubu" 1 } } */
+
+/* Check that we produce sign- and zero-extended additions and
+ subtractions, also for 8-bit to 16-bit results. Note that we can't
+ eliminate compare insns, as the condition codes reflect the 32-bit
+ result.
+ This test-case is brittle, as with the presence of compare
+ instructions, there are several optimal instruction sequence, some of
+ which match the non-matcher patterns and do not contain the matching
+ patterns. */
+
+#define t unsigned char
+#define t2 unsigned short
+#define s _us
+#include "pr93372-36.c"
+
+#undef t
+#undef s
+#undef t2
+#define t signed char
+#define t2 signed short
+#define s _ss
+#include "pr93372-36.c"