cris.md: Reinstate add/sub with extend
authorHans-Peter Nilsson <hp@axis.com>
Sun, 5 Jul 2020 22:52:39 +0000 (00:52 +0200)
committerHans-Peter Nilsson <hp@axis.com>
Sun, 5 Jul 2020 23:17:25 +0000 (01:17 +0200)
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.

gcc/config/cris/cris.md
gcc/testsuite/gcc.target/cris/pr93372-36.c [new file with mode: 0644]
gcc/testsuite/gcc.target/cris/pr93372-37.c [new file with mode: 0644]
gcc/testsuite/gcc.target/cris/pr93372-38.c [new file with mode: 0644]

index 081041fa24561af28077503746a53e9293912e5c..e700819d510f528a2b10f0190608af63b571bec5 100644 (file)
   [(set_attr "slottable" "yes,yes,yes,yes,no,no")
    (set_attr "cc<ccnz>" "normal,normal,clobber,clobber,normal,normal")])
 \f
+;; 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")])
+\f
+;; 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")])
+\f
 ;; 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 (file)
index 0000000..84fbdb7
--- /dev/null
@@ -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 (file)
index 0000000..0c43d77
--- /dev/null
@@ -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 (file)
index 0000000..c7cba3b
--- /dev/null
@@ -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"