This patch makes bswap[sd]i2 better register allocation, and reconstructs
bswapsi2 in order to take advantage of GIMPLE manual byte-swapping
recognition.
gcc/ChangeLog:
* gcc/config/xtensa/xtensa.md (bswapsi2): New expansion pattern.
(bswapsi2_internal): Revise the template and condition, and add
detection code for preceding the same insn in order to omit a
"SSAI 8" instruction of the latter.
(bswapdi2): Suppress built-in insn expansion with the corresponding
library call when optimizing for size.
gcc/testsuite/ChangeLog:
* gcc.target/xtensa/bswap-O1.c: New.
* gcc.target/xtensa/bswap-O2.c, gcc.target/xtensa/bswap-Os.c:
Ditto.
---
gcc/config/xtensa/xtensa.md | 77 +++++++++++++++++-----
gcc/testsuite/gcc.target/xtensa/bswap-O1.c | 37 +++++++++++
gcc/testsuite/gcc.target/xtensa/bswap-O2.c | 37 +++++++++++
gcc/testsuite/gcc.target/xtensa/bswap-Os.c | 37 +++++++++++
4 files changed, 172 insertions(+), 16 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/xtensa/bswap-O1.c
create mode 100644 gcc/testsuite/gcc.target/xtensa/bswap-O2.c
create mode 100644 gcc/testsuite/gcc.target/xtensa/bswap-Os.c
diff --git a/gcc/config/xtensa/xtensa.md b/gcc/config/xtensa/xtensa.md
index 2d146b7995c..6f5cbc541d8 100644
--- a/gcc/config/xtensa/xtensa.md
+++ b/gcc/config/xtensa/xtensa.md
@@ -471,23 +471,68 @@
;; Byte swap.
-(define_insn "bswapsi2"
- [(set (match_operand:SI 0 "register_operand" "=&a")
- (bswap:SI (match_operand:SI 1 "register_operand" "r")))]
- "!optimize_size"
- "ssai\t8\;srli\t%0, %1, 16\;src\t%0, %0, %1\;src\t%0, %0,
%0\;src\t%0, %1, %0"
- [(set_attr "type" "arith")
- (set_attr "mode" "SI")
- (set_attr "length" "15")])
+(define_expand "bswapsi2"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (bswap:SI (match_operand:SI 1 "register_operand" "")))]
+ "!optimize_debug && optimize > 1"
+{
+ /* GIMPLE manual byte-swapping recognition is now activated.
+ For both built-in and manual bswaps, emit corresponding library call
+ if optimizing for size, or a series of dedicated machine instructions
+ if otherwise. */
+ if (optimize_size)
+ emit_library_call_value (optab_libfunc (bswap_optab, SImode),
+ operands[0], LCT_NORMAL, SImode,
+ operands[1], SImode);
+ else
+ emit_insn (gen_bswapsi2_internal (operands[0], operands[1]));
+ DONE;
+})
-(define_insn "bswapdi2"
- [(set (match_operand:DI 0 "register_operand" "=&a")
- (bswap:DI (match_operand:DI 1 "register_operand" "r")))]
- "!optimize_size"
- "ssai\t8\;srli\t%0, %D1, 16\;src\t%0, %0, %D1\;src\t%0, %0,
%0\;src\t%0, %D1, %0\;srli\t%D0, %1, 16\;src\t%D0, %D0, %1\;src\t%D0,
%D0, %D0\;src\t%D0, %1, %D0"
- [(set_attr "type" "arith")
- (set_attr "mode" "DI")
- (set_attr "length" "27")])
+(define_insn "bswapsi2_internal"
+ [(set (match_operand:SI 0 "register_operand" "=a,&a")
+ (bswap:SI (match_operand:SI 1 "register_operand" "0,r")))
+ (clobber (match_scratch:SI 2 "=&a,X"))]
+ "!optimize_debug && optimize > 1 && !optimize_size"
+{
+ rtx_insn *prev_insn = prev_nonnote_nondebug_insn (insn);
+ const char *init = "ssai\t8\;";
+ static char result[64];
+ if (prev_insn && NONJUMP_INSN_P (prev_insn))
+ {
+ rtx x = PATTERN (prev_insn);
+ if (GET_CODE (x) == PARALLEL && XVECLEN (x, 0) == 2
+ && GET_CODE (XVECEXP (x, 0, 0)) == SET
+ && GET_CODE (XVECEXP (x, 0, 1)) == CLOBBER)
+ {
+ x = XEXP (XVECEXP (x, 0, 0), 1);
+ if (GET_CODE (x) == BSWAP && GET_MODE (x) == SImode)
+ init = "";
+ }
+ }
+ sprintf (result,
+ (which_alternative == 0)
+ ? "%s" "srli\t%%2, %%1, 16\;src\t%%2, %%2, %%1\;src\t%%2, %%2,
%%2\;src\t%%0, %%1, %%2"
+ : "%s" "srli\t%%0, %%1, 16\;src\t%%0, %%0, %%1\;src\t%%0, %%0,
%%0\;src\t%%0, %%1, %%0",
+ init);
+ return result;
+}
+ [(set_attr "type" "arith,arith")
+ (set_attr "mode" "SI")
+ (set_attr "length" "15,15")])
+
+(define_expand "bswapdi2"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (bswap:DI (match_operand:DI 1 "register_operand" "")))]
+ "!optimize_debug && optimize > 1 && optimize_size"
+{
+ /* Replace with a single DImode library call.
+ Without this, two SImode library calls are emitted. */
+ emit_library_call_value (optab_libfunc (bswap_optab, DImode),
+ operands[0], LCT_NORMAL, DImode,
+ operands[1], DImode);
+ DONE;
+})
;; Negation and one's complement.
diff --git a/gcc/testsuite/gcc.target/xtensa/bswap-O1.c
b/gcc/testsuite/gcc.target/xtensa/bswap-O1.c
new file mode 100644
index 00000000000..a0c885baaf1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/xtensa/bswap-O1.c
@@ -0,0 +1,37 @@
+/* { dg-do compile } */
+/* { dg-options "-O1" } */
+
+unsigned int test_0(unsigned int a)
+{
+ return (a & 0x000000FF) << 24 |
+ (a & 0x0000FF00) << 8 |
+ (a & 0x00FF0000) >> 8 |
+ (a & 0xFF000000) >> 24;
+}
+
+unsigned int test_1(unsigned int a)
+{
+ union
+ {
+ unsigned int i;
+ unsigned char a[4];
+ } u, v;
+ u.i = a;
+ v.a[0] = u.a[3];
+ v.a[1] = u.a[2];
+ v.a[2] = u.a[1];
+ v.a[3] = u.a[0];
+ return v.i;
+}
+
+unsigned int test_2(unsigned int a)
+{
+ return __builtin_bswap32(a);
+}
+
+unsigned long long test_3(unsigned long long a)
+{
+ return __builtin_bswap64(a);
+}
+
+/* { dg-final { scan-assembler-times "call" 2 } } */
diff --git a/gcc/testsuite/gcc.target/xtensa/bswap-O2.c
b/gcc/testsuite/gcc.target/xtensa/bswap-O2.c
new file mode 100644
index 00000000000..4cf95b9255c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/xtensa/bswap-O2.c
@@ -0,0 +1,37 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+unsigned int test_0(unsigned int a)
+{
+ return (a & 0x000000FF) << 24 |
+ (a & 0x0000FF00) << 8 |
+ (a & 0x00FF0000) >> 8 |
+ (a & 0xFF000000) >> 24;
+}
+
+unsigned int test_1(unsigned int a)
+{
+ union
+ {
+ unsigned int i;
+ unsigned char a[4];
+ } u, v;
+ u.i = a;
+ v.a[0] = u.a[3];
+ v.a[1] = u.a[2];
+ v.a[2] = u.a[1];
+ v.a[3] = u.a[0];
+ return v.i;
+}
+
+unsigned int test_2(unsigned int a)
+{
+ return __builtin_bswap32(a);
+}
+
+unsigned long long test_3(unsigned long long a)
+{
+ return __builtin_bswap64(a);
+}
+
+/* { dg-final { scan-assembler-times "ssai" 4 } } */
diff --git a/gcc/testsuite/gcc.target/xtensa/bswap-Os.c
b/gcc/testsuite/gcc.target/xtensa/bswap-Os.c
new file mode 100644
index 00000000000..1e010fd62ae
--- /dev/null
+++ b/gcc/testsuite/gcc.target/xtensa/bswap-Os.c
@@ -0,0 +1,37 @@
+/* { dg-do compile } */
+/* { dg-options "-Os" } */
+
+unsigned int test_0(unsigned int a)
+{
+ return (a & 0x000000FF) << 24 |
+ (a & 0x0000FF00) << 8 |
+ (a & 0x00FF0000) >> 8 |
+ (a & 0xFF000000) >> 24;
+}
+
+unsigned int test_1(unsigned int a)
+{
+ union
+ {
+ unsigned int i;
+ unsigned char a[4];
+ } u, v;
+ u.i = a;
+ v.a[0] = u.a[3];
+ v.a[1] = u.a[2];
+ v.a[2] = u.a[1];
+ v.a[3] = u.a[0];
+ return v.i;
+}
+
+unsigned int test_2(unsigned int a)
+{
+ return __builtin_bswap32(a);
+}
+
+unsigned long long test_3(unsigned long long a)
+{
+ return __builtin_bswap64(a);
+}
+
+/* { dg-final { scan-assembler-times "call" 4 } } */
--
2.20.1